<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://jin-castle.github.io/meep-examples/feed.xml" rel="self" type="application/atom+xml" /><link href="https://jin-castle.github.io/meep-examples/" rel="alternate" type="text/html" hreflang="ko" /><updated>2026-10-23T14:54:52+00:00</updated><id>https://jin-castle.github.io/meep-examples/feed.xml</id><title type="html">Meep Examples</title><subtitle>Meep(FDTD) 공식 예제와 공개 프로젝트를 직접 실행하며 배우는 시리즈. Korean body, English TL;DR, English code comments.</subtitle><author><name>jin-castle</name></author><entry xml:lang="ko"><title type="html">Meep Example 09 · Waveguide bend inverse design — 자유 설계 영역과 출력 포트 mode power</title><link href="https://jin-castle.github.io/meep-examples/bend-inverse/" rel="alternate" type="text/html" title="Meep Example 09 · Waveguide bend inverse design — 자유 설계 영역과 출력 포트 mode power" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/bend-inverse</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/bend-inverse/"><![CDATA[<h2 id="observe">1. 먼저 보기: 회색 블록에서 빛은 어디로 갈까?</h2>

<p>입력은 왼쪽, 원하는 출력은 위쪽입니다. 가운데 1 × 1 µm 정사각형의 재료만 바꿀 수 있다면, 빛이 90° 꺾이도록 어떤 구조를 만들면 될까요? 05편에서는 반지름 하나를 바꿨고, 이번에는 11 × 11 = <strong>121개 밀도</strong>를 바꿉니다.</p>

<div class="figure-pair">
<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/07_verify.png" data-lightbox="" aria-label="출발점의 전기장 원본 확대">
<svg viewBox="690 45 630 560" role="img" aria-labelledby="start-field-title"><title id="start-field-title">균일한 밀도 0.5에서 빛이 오른쪽으로 퍼지는 실제 전기장</title><image href="/meep-examples/assets/meep/09/07_verify.png" width="1950" height="630" /></svg>
</a>
<figcaption>출발점: 밀도가 모두 0.5입니다. 빛이 오른쪽으로 퍼지고, 위쪽 mode 1 투과율은 0.0154입니다.</figcaption>
</figure>
<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/07_verify.png" data-lightbox="" aria-label="갱신한 설계의 전기장 원본 확대">
<svg viewBox="1335 45 610 560" role="img" aria-labelledby="updated-field-title"><title id="updated-field-title">MMA 다섯 번째 평가 설계에서 빛이 위쪽 도파관으로 진행하는 실제 전기장</title><image href="/meep-examples/assets/meep/09/07_verify.png" width="1950" height="630" /></svg>
</a>
<figcaption>갱신 후: MMA 5회 평가 중 가장 높은 설계입니다. 새 시뮬레이션에서 잰 mode 1 투과율은 0.7801입니다.</figcaption>
</figure>
</div>

<p class="lesson-note"><strong>이 결과를 읽는 조건.</strong> 두 그림은 같은 해상도 10의 실제 Re(Ez) 결과입니다. 같은 설계를 해상도 20으로 다시 재면 투과율은 0.6391입니다. 121개 중 119개가 회색조이고 최적화는 5회 평가뿐이므로, 수렴한 설계나 제작 도면으로 볼 수 없습니다.</p>

<h3 id="어디에-쓰이는가">어디에 쓰이는가</h3>

<p>홈의 고해상도 DFT 예시는 <strong>빨강·파랑 파면 + 회색 구조</strong>로 표시합니다. 빨강은 음수, 파랑은 양수 Re(Ez)이며 약한 장은 투명하게 합성합니다. 회색은 고정 도파관과 연속 설계 밀도의 표시로, 저장된 실제 유전율 지도는 아닙니다. 원래의 복소장·위상·공통 색상 범위는 보존하고, gradient는 기존 RdBu로 구별합니다. 아래 저해상도 MMA 예제의 원본 그림과는 계산 이력이 다릅니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/iterations/005/updated-forward-scene.png" data-lightbox=""><img src="/meep-examples/assets/meep/09/iterations/005/updated-forward-scene.png" alt="여섯 번의 고해상도 밀도 갱신 후 회색 구조 위의 실제 DFT 파면" loading="lazy" /></a>
<figcaption>해상도 60, 61×61 연속 밀도, 6회 갱신 후의 저장된 정상상태 DFT입니다. 위상 재생은 시간에 따른 광원 켜짐이나 파면 도착을 뜻하지 않습니다.</figcaption>
</figure>

<p>역설계 bend는 PIC 부품의 면적을 수십 배 줄이는 방법의 첫 예다. 같은 틀이 splitter, crossing, mode converter에 그대로 쓰인다.</p>

<table>
  <thead>
    <tr>
      <th>응용</th>
      <th>이 글의 어떤 것을 쓰는가</th>
      <th>그 다음에 필요한 것</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>초소형 PIC 부품(bend, splitter, crossing, mode converter)</td>
      <td>자유 설계 영역 + 출력 모드 목적함수</td>
      <td>31·33·34편</td>
    </tr>
    <tr>
      <td>foundry 제약 반영(최소 선폭, 이진화)</td>
      <td>회색조·선폭 문제의 발견</td>
      <td>32편 filter·projection</td>
    </tr>
    <tr>
      <td>설계 변수 1개와 121개의 비교</td>
      <td>05편 반지름 sweep과 이 글</td>
      <td>—</td>
    </tr>
  </tbody>
</table>

<h2 id="predict">2. 먼저 예측하기: gradient는 완성된 길을 그릴까?</h2>

<p>지금 아는 것은 왼쪽에서 들어온 빛을 위로 보내고 싶다는 것뿐입니다. 균일한 출발점에서 계산한 첫 gradient가 무엇을 보여 줄지 골라 보세요.</p>

<fieldset class="prediction">
<legend>첫 gradient에서 가장 두드러지는 패턴은?</legend>
<label><input type="radio" name="gradient-prediction" value="diagonal" /> 입력과 출력을 잇는 대각선 전체가 양수다.</label>
<label><input type="radio" name="gradient-prediction" value="local" /> 중앙을 줄이고 일부 도파관 연결부를 늘리라는 국소적인 변화다.</label>
</fieldset>

<details>
  <summary>예측과 실제 결과 비교하기</summary>

  <p>이 출발점에서는 두 번째에 가깝습니다. 가장 큰 절댓값은 중앙의 <strong>음수 −13.4</strong>이고, 양수는 두 도파관을 설계 영역 안으로 연장하는 부근에 있습니다. 대각선 모양은 큰 step 뒤 일부 밀도가 0이나 1에 닿으면서 나타납니다. 첫 미분은 현재 설계를 조금 바꿀 방향을 알려 주며, 완성된 형상을 직접 그려 주지는 않습니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기: 두 계산에서 한 번의 갱신으로</h2>

<p>밀도 ρ는 설계 영역 안의 재료를 정하는 숫자입니다. <strong>0은 SiO₂, 1은 Si</strong>, 사이는 두 재료 사이의 보간 값입니다. 왼쪽과 위쪽의 폭 0.5 µm Si 도파관은 고정하고, 정사각형 안의 121개 값만 바꿉니다. 처음에는 모두 0.5이며, 바깥 배경은 공기입니다.</p>

<!-- concept-illustration:part-09:start -->

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/00_concept.png" data-lightbox="" aria-label="고정된 두 도파관과 중앙의 자유 설계 영역을 설명하는 개념도 원본 확대"><img src="/meep-examples/assets/meep/09/00_concept.png" alt="고정된 두 도파관과 중앙의 자유 설계 영역을 설명하는 개념도" loading="lazy" /></a>
<figcaption>왼쪽(+x) 입력과 위쪽(+y) 출력 도파관은 고정하고, 중앙 1 × 1 µm의 11 × 11개 밀도만 바꿉니다. 그림의 격자와 회색 농도는 설명용이며 실제 최적화 결과가 아닙니다.</figcaption>
</figure>

<!-- concept-illustration:part-09:end -->

<p>그림의 입력에서 빛을 보내는 계산이 forward, 출력의 목적함수에서 유도한 source로 설계 영역을 향해 응답을 구하는 별도 계산이 adjoint입니다. 저장한 두 field로 gradient를 구하고, 그 결과를 optimizer에 넘겨 밀도를 갱신합니다.</p>

<ol>
  <li><strong>Forward field:</strong> 왼쪽 입력 모드로 빛을 넣고, 위쪽 출력 포트의 mode 1 진폭을 구합니다.</li>
  <li><strong>Adjoint field:</strong> 목적함수에서 유도한 source로 별도 계산합니다. 이 예제에서는 출력 포트에서 설계 영역 쪽으로 향합니다.</li>
  <li><strong>Gradient:</strong> 저장한 두 field의 겹침과 재료의 밀도 의존성을 이용해 각 픽셀의 ∂J/∂ρ를 계산합니다.</li>
  <li><strong>Geometry update:</strong> gradient를 검증한 뒤, optimizer가 0 ≤ ρ ≤ 1 안에서 밀도를 갱신합니다.</li>
</ol>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/04_gradient.png" data-lightbox="" aria-label="실제 11×11 gradient와 색상 막대 원본 확대">
<svg viewBox="625 0 585 555" role="img" aria-labelledby="gradient-map-title"><title id="gradient-map-title">실제 초기 signed gradient: 중앙은 강한 음수, 일부 도파관 연결부는 양수</title><image href="/meep-examples/assets/meep/09/04_gradient.png" width="1800" height="570" /></svg>
</a>
<figcaption>실제로 계산한 초기 11 × 11 gradient입니다. 빨강(양수)은 밀도를 높이는 쪽, 파랑(음수)은 낮추는 쪽이 J를 증가시키는 국소 방향입니다. 양수 49개, 음수 72개입니다.</figcaption>
</figure>

<p class="lesson-note"><strong>색을 읽는 기준.</strong> 이 그림의 색은 재료 밀도가 아니라 J의 민감도입니다. 밀도를 낮추는 것은 설계 영역 안에서 SiO₂ 쪽으로 옮긴다는 뜻입니다. 검정·회색·흰색으로 그린 밀도 지도와 구별하세요.</p>

<table>
  <tbody>
    <tr>
      <td>목적함수는 출력 mode 1 진폭의 제곱 **J =</td>
      <td>a_out</td>
      <td>²<strong>입니다. 최적화 도중의 J는 optimizer의 정규화 관례를 따릅니다. 보고할 투과율은 최종 설계를 **새 시뮬레이션</strong>으로 측정하고, 직선 도파관 참조 run의 입력 mode 1 power로 나눈 값입니다.</td>
    </tr>
  </tbody>
</table>

\[T_{\mathrm{mode1}}=
\frac{P_{\mathrm{out,mode1}}\;\text{(fresh run)}}{P_{\mathrm{in,mode1}}\;\text{(reference run)}}\]

<p><strong>계산 범위:</strong> 2D Ez(TE), 파장 1.55 µm, Si 굴절률 3.4, SiO₂ 굴절률 1.44, 단일 주파수입니다. 설계 격자 11 × 11과 전자기장을 계산하는 Yee 격자는 서로 다릅니다. 최소 선폭과 이진화 제약은 없습니다.</p>

<details>
  <summary>수식·기호 자세히 보기</summary>

  <table>
    <tbody>
      <tr>
        <td>목적함수는 출력 포트 monitor에서 잰 mode 1 진폭의 제곱 J =</td>
        <td>a_out</td>
        <td>²이다. 08편과 수학은 같다. forward field E_f는 입력 도파관의 <code class="language-plaintext highlighter-rouge">EigenModeSource</code>가 만들고, adjoint field E_a는 출력 포트 monitor 자리에서 거꾸로 쏜 <code class="language-plaintext highlighter-rouge">EigenModeSource</code>가 만든다. gradient는 두 field의 겹침에 재료의 밀도 의존성과 정규화 계수를 반영해 구한다. 아래 비례식은 그 관계를 개념적으로 나타낸 것이다. 08편에서 adjoint가 위쪽 평면파 monitor에서 내려왔다면, 여기서는 출력 도파관을 타고 설계 영역으로 내려온다. 목적함수가 바뀌면 adjoint source의 위치와 모양이 바뀐다.</td>
      </tr>
    </tbody>
  </table>

\[J=\lvert a_{\mathrm{out}}\rvert^{2},\qquad
\frac{\partial J}{\partial \rho_i}\;\propto\;\mathrm{Re}\big(E_f\cdot E_a\big)\Big|_{\text{pixel } i},\qquad
T_{\mathrm{mode1}}=\frac{\lvert a_{\mathrm{out}}\rvert^{2}_{\text{fresh run}}}{P_{\mathrm{in}}}\]

  <p>보고하는 투과율 T_mode1의 분모 P_in은 직선 도파관만 있는 참조 run에서 입력면(x = −1 µm)의 mode 1 power다. 분자는 최종 설계를 새 <code class="language-plaintext highlighter-rouge">Simulation</code>에 넣고 <code class="language-plaintext highlighter-rouge">get_eigenmode_coefficients</code>로 다시 잰 값이다. optimizer가 돌려주는 J는 이 분모와 같은 잣대로 정규화되어 있지 않다. 실제로 J/P_in은 1.056이 나온다.</p>

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>ρ (121개)</td>
        <td>설계 밀도. 0 SiO2, 1 Si, 사이는 회색조</td>
        <td><code class="language-plaintext highlighter-rouge">x_start</code>, <code class="language-plaintext highlighter-rouge">x_optimized</code></td>
      </tr>
      <tr>
        <td>J</td>
        <td>출력 포트 mode 1 power |a_out|² (optimizer 단위)</td>
        <td><code class="language-plaintext highlighter-rouge">fom(x)</code></td>
      </tr>
      <tr>
        <td>g</td>
        <td>adjoint gradient ∂J/∂ρ</td>
        <td><code class="language-plaintext highlighter-rouge">g_start</code></td>
      </tr>
      <tr>
        <td>v, s</td>
        <td>gate 방향(g/|g|), FD step</td>
        <td><code class="language-plaintext highlighter-rouge">v</code>, <code class="language-plaintext highlighter-rouge">steps</code></td>
      </tr>
      <tr>
        <td>α</td>
        <td>손 step 크기</td>
        <td><code class="language-plaintext highlighter-rouge">one_step</code></td>
      </tr>
      <tr>
        <td>P_in</td>
        <td>입력면 mode 1 power (참조 run)</td>
        <td><code class="language-plaintext highlighter-rouge">input_power</code></td>
      </tr>
      <tr>
        <td>T_mode1, T_total</td>
        <td>새 run의 mode 1 power / P_in, 전체 flux / P_in</td>
        <td><code class="language-plaintext highlighter-rouge">report</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 2D Ez(TE), 굴절률 Si 3.4 / SiO2 1.44, 폭 0.5 µm, 해상도 10(픽셀 100 nm), 단일 주파수. 설계 격자 11 × 11은 Yee 격자와 별개다. 제작 제약(최소 선폭, 이진화)은 없다.</p>

</details>

<h2 id="run">4. 직접 실행하기: step 크기 하나만 비교하기</h2>

<p>먼저 <a href="https://github.com/jin-castle/meep-examples/blob/main/code">전체 스크립트와 공통 helper</a>를 같은 폴더에 두세요. <code class="language-plaintext highlighter-rouge">bend_inverse.py</code>와 <code class="language-plaintext highlighter-rouge">blogfig.py</code>가 필요합니다. Meep 1.33.0, NLopt, autograd가 준비된 환경에서 원본을 한 번 실행합니다. 기록된 실행 시간은 단일 코어 약 29초입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python bend_inverse.py
</code></pre></div></div>

<p>이번에 볼 출력은 <strong><code class="language-plaintext highlighter-rouge">one manual step:</code> 한 줄</strong>입니다. 원본은 같은 출발점과 같은 정규화 gradient 방향에서 α = 0.2, 1, 3, 8을 비교합니다. 각 설계는 앞선 결과에 이어서 움직인 것이 아니라, 모두 균일한 0.5에서 한 번씩 이동한 결과입니다.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 원본 전체 코드에서 발췌: 이 조각만 단독 실행하지 않습니다.
</span><span class="n">x_try</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x_start</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">v</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p><strong>한 가지 실험:</strong> 원본의 <code class="language-plaintext highlighter-rouge">for alpha in (0.2, 1.0, 3.0, 8.0):</code>에서 마지막 값만 <code class="language-plaintext highlighter-rouge">4.0</code>으로 바꿔 다시 실행하세요. α = 4와 8에서 J와 밀도 포화가 어떻게 달라질지 먼저 적고, 출력과 <code class="language-plaintext highlighter-rouge">06_step_mma.png</code>로 확인합니다. 다른 파라미터와 MMA 평가 횟수는 그대로 둡니다.</p>

<p><strong>실행 전 확인:</strong> gradient gate가 PASS인지 먼저 봅니다. 이 예제는 세 유한차분 step 모두 상대오차가 0.01% 이내였습니다. gate가 HOLD이면 optimizer 결과 해석을 멈추고 원인을 확인하세요. 입력 mode 1 비율이 0.95 아래라면 source부터 점검합니다.</p>

<details>
  <summary>시뮬레이션 설계도·파라미터·source 검증</summary>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/01_layout.png" data-lightbox="" aria-label="6×5 마이크로미터 계산 셀의 source와 입출력 monitor 배치 원본 확대"><img src="/meep-examples/assets/meep/09/01_layout.png" alt="6×5 마이크로미터 계산 셀의 source와 입출력 monitor 배치" loading="lazy" /></a>
<figcaption>6 × 5 µm 셀과 PML 1 µm입니다. Source는 x = −1.5 µm, 입력 monitor는 x = −1 µm, 출력 monitor는 y = 1 µm에 있습니다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>셀, 해상도</td>
        <td>6 × 5 µm, res 10</td>
        <td>강의 week 10과 같다. 한 run이 2~3 s</td>
        <td>res 20이면 결과 해석의 해상도 표처럼 값이 바뀐다</td>
      </tr>
      <tr>
        <td>설계 영역</td>
        <td>1 × 1 µm, 11 × 11</td>
        <td>도파관 폭의 2배. 변수 121개</td>
        <td>1.5 × 1.5면 변수 256개, 시간도 비례</td>
      </tr>
      <tr>
        <td>초기값</td>
        <td>균일 0.5</td>
        <td>내부점이라 gate를 바로 잴 수 있고 방향 편향이 없다</td>
        <td>0/1 초기값이면 08편처럼 clip 처리 필요</td>
      </tr>
      <tr>
        <td>source</td>
        <td>mode 1, fwidth 0.12 fcen</td>
        <td>좁은 대역. 단일 주파수 목적함수에 맞춘다</td>
        <td>넓히면 펄스가 짧아져 GIF에 좋지만 forward run은 그대로</td>
      </tr>
      <tr>
        <td>monitor</td>
        <td>출력 y = 1, 폭 2 µm</td>
        <td>설계 영역에서 0.5 µm 떨어진 곳</td>
        <td>설계 영역에 붙이면 근접장이 mode 분해에 섞인다</td>
      </tr>
      <tr>
        <td>gate steps</td>
        <td>2e-3, 5e-3, 1e-2</td>
        <td>08편과 같다</td>
        <td>—</td>
      </tr>
      <tr>
        <td>손 step α</td>
        <td>0.2, 1, 3, 8</td>
        <td>08편(0.05~2)보다 넓다. 포화를 보기 위해</td>
        <td>—</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">maxeval</code></td>
        <td>5</td>
        <td>수업용 smoke test</td>
        <td>수렴을 보려면 수십 회 + 이진화</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/00_source.png" data-lightbox="" aria-label="가우스 source의 시간 파형과 주파수 스펙트럼 원본 확대"><img src="/meep-examples/assets/meep/09/00_source.png" alt="가우스 source의 시간 파형과 주파수 스펙트럼" loading="lazy" /></a>
<figcaption>fwidth = 0.12 fcen인 source입니다. 펄스 폭은 12.9, 정점은 t0 = 64.6 µm/c이며, 1550 nm에서 ±50 nm 밖의 power는 1% 아래입니다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/02_source_check.png" data-lightbox="" aria-label="직선 도파관 참조 실행에서 측정한 입력 모드 원본 확대"><img src="/meep-examples/assets/meep/09/02_source_check.png" alt="직선 도파관 참조 실행에서 측정한 입력 모드" loading="lazy" /></a>
<figcaption>입력 mode 1 power / 전체 flux = 1.0043입니다. 분자는 전방 mode 1, 분모는 전방에서 후방을 뺀 순 flux여서 1을 조금 넘을 수 있습니다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 파라미터와 수치(mode 1 비율 1.0043, gate 0.0000/0.0000/0.0001, 손 step 16.7/118.9/176.2/235.5, MMA 4.31 → 222.4, 검증 0.0154 → 0.7801)는 강의 week 10과 같다. 강의는 Meep 1.34, 여기는 1.33인데 소수 넷째 자리까지 같다. 이 글이 더한 것은 해상도 20에서의 재측정(결과 해석 수렴성)과 GIF 두 개, 단계 번호가 붙은 설계도다.</p>

</details>

<details>
  <summary>코드 7단계 해설: 각 줄의 역할과 흔한 함정</summary>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
08편과 같은 구조이고, 달라지는 줄은 ⑤의 목적함수와 ⑦의 정규화뿐이다.</p>
  </blockquote>

  <h3 id="section">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">wl</span><span class="p">,</span> <span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span> <span class="o">=</span> <span class="mf">1.55</span><span class="p">,</span> <span class="mi">1</span> <span class="o">/</span> <span class="mf">1.55</span><span class="p">,</span> <span class="mf">0.12</span> <span class="o">/</span> <span class="mf">1.55</span>
<span class="n">Si</span><span class="p">,</span> <span class="n">SiO2</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">3.4</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">1.44</span><span class="p">)</span>
<span class="n">RES</span><span class="p">,</span> <span class="n">SX</span><span class="p">,</span> <span class="n">SY</span><span class="p">,</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">W</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.5</span>
<span class="n">SRC_X</span><span class="p">,</span> <span class="n">MON_IN_X</span><span class="p">,</span> <span class="n">MON_OUT_Y</span> <span class="o">=</span> <span class="o">-</span><span class="mf">1.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span>        <span class="c1"># source, input monitor, objective monitor
</span><span class="n">D</span><span class="p">,</span> <span class="n">NX</span><span class="p">,</span> <span class="n">NY</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">11</span>                                <span class="c1"># design square and its grid (121 densities)
</span><span class="n">x_start</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">ones</span><span class="p">(</span><span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="p">)</span>                        <span class="c1"># uniform grey: interior point, no bias
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 셀, 도파관, 설계 격자, 세 평면(source, 입력 monitor, 출력 monitor)의 위치.</li>
    <li><strong>왜</strong>: 입력 monitor는 source와 설계 영역 사이에 둔다. 참조 run에서 여기서 잰 mode 1 power가 모든 투과율의 분모다. 출력 monitor는 설계 영역에서 0.5 µm 띄운다.</li>
    <li><strong>틀리면</strong>: 설계 격자 11 × 11을 Yee 격자(res 10이면 1 µm에 10칸)와 혼동하면 “픽셀 하나 = 격자 하나”로 착각한다. <code class="language-plaintext highlighter-rouge">MaterialGrid</code>는 설계 격자를 Yee 격자에 보간한다.</li>
  </ul>

  <h3 id="section-1">② 재료와 구조 — 무엇이 어디에 있는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">waveguide_blocks</span><span class="p">():</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="n">SX</span> <span class="o">/</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SX</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">W</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">),</span>    <span class="c1"># input, from -x
</span>            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SY</span> <span class="o">/</span> <span class="mi">4</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">SY</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">)]</span>     <span class="c1"># output, to +y
</span>
<span class="n">design_variables</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">MaterialGrid</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">),</span> <span class="n">SiO2</span><span class="p">,</span> <span class="n">Si</span><span class="p">,</span> <span class="n">grid_type</span><span class="o">=</span><span class="s">"U_MEAN"</span><span class="p">,</span> <span class="n">do_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>   <span class="c1"># contract 1
</span><span class="n">design_region</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">DesignRegion</span><span class="p">(</span><span class="n">design_variables</span><span class="p">,</span> <span class="n">volume</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="n">D</span><span class="p">)))</span>
<span class="n">geometry</span> <span class="o">=</span> <span class="n">waveguide_blocks</span><span class="p">()</span> <span class="o">+</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">center</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">size</span><span class="p">,</span> <span class="n">material</span><span class="o">=</span><span class="n">design_variables</span><span class="p">)]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 고정된 Si 도파관 두 개와, 원점의 정사각형 <code class="language-plaintext highlighter-rouge">MaterialGrid</code>. 최적화는 정사각형 안만 바꾼다.</li>
    <li><strong>왜</strong>: 두 도파관이 설계 영역의 왼쪽 변과 위쪽 변에 닿는다. 설계 영역이 둘을 어떻게 이을지는 gradient가 정한다.</li>
    <li><strong>틀리면</strong>: 도파관 블록이 설계 영역과 겹치면 겹친 곳의 유전율은 나중 객체가 이긴다. 설계 영역을 마지막에 두어야 밀도가 반영된다.</li>
  </ul>

  <h3 id="source----">③ Source — 빛을 어떻게 넣는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">EigenModeSource</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">),</span> <span class="n">eig_band</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">NO_DIRECTION</span><span class="p">,</span>
                              <span class="n">eig_kpoint</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SRC_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>
<span class="n">adjoint_sources</span> <span class="o">=</span> <span class="n">opt</span><span class="p">.</span><span class="n">adjoint_sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>      <span class="c1"># one EigenModeSource at the OUTPUT monitor, made by opt
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 04편과 같은 <code class="language-plaintext highlighter-rouge">EigenModeSource</code>. adjoint source는 <code class="language-plaintext highlighter-rouge">OptimizationProblem</code>이 출력 monitor 자리에 만든다.</li>
    <li><strong>왜</strong>: 목적함수가 mode 1 진폭이므로 adjoint source도 mode 1 모양이다. 08편에서는 평면파였다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">direction=mp.NO_DIRECTION</code>에 <code class="language-plaintext highlighter-rouge">eig_kpoint</code>를 빼면 모드 방향이 정해지지 않는다. 참조 run의 mode 1 비율이 1에서 멀면 여기부터 의심한다.</li>
  </ul>

  <h3 id="simulation-----pml">④ Simulation과 경계 — 계산 상자와 PML</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">common</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SX</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)],</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
<span class="n">stop_cond</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="mf">1e-5</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 네 변 모두 PML 1 µm. 종료 감시점은 출력 monitor 중앙.</li>
    <li><strong>왜</strong>: forward, adjoint, FD, 검증, 해상도 확인이 모두 같은 <code class="language-plaintext highlighter-rouge">common</code>을 쓴다. 해상도만 바꿔 끼운다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">eps_averaging</code>을 기본값으로 두면 계약 1이 깨진다. 설계 영역 안에서는 <code class="language-plaintext highlighter-rouge">do_averaging=False</code>, 밖에서는 <code class="language-plaintext highlighter-rouge">eps_averaging=False</code>가 각각 담당한다.</li>
  </ul>

  <h3 id="monitor--">⑤ Monitor — 목적함수</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">out_mode</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">EigenmodeCoefficient</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span> <span class="n">mode</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">opt</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">OptimizationProblem</span><span class="p">(</span><span class="n">simulation</span><span class="o">=</span><span class="n">sim</span><span class="p">,</span> <span class="n">objective_functions</span><span class="o">=</span><span class="k">lambda</span> <span class="n">a</span><span class="p">:</span> <span class="n">npa</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">,</span>
                              <span class="n">objective_arguments</span><span class="o">=</span><span class="p">[</span><span class="n">out_mode</span><span class="p">],</span> <span class="n">design_regions</span><span class="o">=</span><span class="p">[</span><span class="n">design_region</span><span class="p">],</span> <span class="n">fcen</span><span class="o">=</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">nf</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li>
      <table>
        <tbody>
          <tr>
            <td><strong>무엇</strong>: 출력 monitor 선 위의 mode 1 진폭 a_out을 인자로,</td>
            <td>a_out</td>
            <td>²를 목적함수로.</td>
          </tr>
        </tbody>
      </table>
    </li>
    <li><strong>왜</strong>: 08편의 <code class="language-plaintext highlighter-rouge">kpoint_func</code>와 <code class="language-plaintext highlighter-rouge">eig_vol</code>이 없다. 도파관 모드는 monitor 폭 전체에서 풀면 되고 방향은 monitor의 법선이다. 바뀐 줄은 이 두 줄뿐이다.</li>
    <li><strong>틀리면</strong>: monitor 폭 2 µm가 도파관(0.5 µm)보다 충분히 넓어야 모드 꼬리를 담는다. 폭을 0.5로 줄이면 a_out이 작아지고 gradient도 그만큼 틀어진다.</li>
  </ul>

  <h3 id="forward-adjoint-gate---mma">⑥ 실행 — forward, adjoint, gate, 한 걸음, MMA</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">f</span><span class="p">,</span> <span class="n">dJ</span> <span class="o">=</span> <span class="n">opt</span><span class="p">([</span><span class="n">x</span><span class="p">],</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>                   <span class="c1"># forward + adjoint: J and dJ/drho for all 121 pixels
</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">g_start</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_start</span><span class="p">)</span>                   <span class="c1"># gate: gradient direction, x_start is already interior
</span><span class="n">fd</span> <span class="o">=</span> <span class="p">(</span><span class="n">fom</span><span class="p">(</span><span class="n">x_start</span> <span class="o">+</span> <span class="n">s</span> <span class="o">*</span> <span class="n">v</span><span class="p">)</span> <span class="o">-</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_start</span> <span class="o">-</span> <span class="n">s</span> <span class="o">*</span> <span class="n">v</span><span class="p">))</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">s</span><span class="p">)</span>
<span class="n">ok</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">g_start</span> <span class="o">@</span> <span class="n">v</span> <span class="o">-</span> <span class="n">fd</span><span class="p">)</span> <span class="o">/</span> <span class="nb">abs</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mf">0.20</span>

<span class="n">x_try</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x_start</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">v</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>              <span class="c1"># one step by hand, alpha in (0.2, 1, 3, 8)
</span>
<span class="n">solver</span> <span class="o">=</span> <span class="n">nlopt</span><span class="p">.</span><span class="n">opt</span><span class="p">(</span><span class="n">nlopt</span><span class="p">.</span><span class="n">LD_MMA</span><span class="p">,</span> <span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_lower_bounds</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_upper_bounds</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">solver</span><span class="p">.</span><span class="n">set_max_objective</span><span class="p">(</span><span class="n">nlopt_objective</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_maxeval</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">x_optimized</span> <span class="o">=</span> <span class="n">design_history</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">history</span><span class="p">))]</span>  <span class="c1"># keep the best evaluated design
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 08편과 같은 순서. gate, 손 step, MMA 5회, 최고 평가 보관.</li>
    <li><strong>왜</strong>: 초기값이 0.5 균일이라 clip 없이 바로 gate를 잰다. 08편에서 0/1 baseline을 0.02~0.98로 밀어 넣던 단계가 빠진다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">solver.optimize</code>가 돌려주는 x는 마지막 평가가 아니라 MMA 내부 상태다. 보고할 설계는 history에서 고른다.</li>
  </ul>

  <h3 id="section-2">⑦ 후처리 — 계약 4, 별도 검증과 정규화</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">modal_power</span><span class="p">(</span><span class="n">weights</span><span class="p">,</span> <span class="n">res</span><span class="o">=</span><span class="n">RES</span><span class="p">):</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_with</span><span class="p">(</span><span class="n">weights</span><span class="p">),</span> <span class="o">**</span><span class="nb">dict</span><span class="p">(</span><span class="n">common</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">))</span>      <span class="c1"># a NEW simulation
</span>    <span class="n">mon</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
    <span class="n">s</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_cond</span><span class="p">)</span>
    <span class="n">mode1</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mon</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span>
    <span class="k">return</span> <span class="n">mode1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">mon</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>

<span class="n">T_mode1</span> <span class="o">=</span> <span class="n">mode1</span> <span class="o">/</span> <span class="n">input_power</span>          <span class="c1"># input_power: mode-1 power at x = -1 um in the straight-waveguide run
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 최종 설계를 새 <code class="language-plaintext highlighter-rouge">Simulation</code>에 넣고 출력 포트의 mode 1 power와 전체 flux를 다시 잰 뒤 P_in으로 나눈다. 같은 함수에 res = 20을 넣어 한 번 더 잰다.</li>
    <li><strong>왜</strong>: optimizer 내부 J를 P_in으로 나누면 1.056이 나온다. 단위가 다른 숫자다. 투과율이라 부를 수 있는 값은 이 함수가 돌려주는 것뿐이다.</li>
    <li><strong>틀리면</strong>: res 20 검사에서 분모도 res 20의 참조 run으로 다시 재야 한다. 분자만 바꾸면 해상도 차이가 아니라 정규화 차이를 보게 된다.</li>
  </ul>

  <blockquote>
    <table>
      <tbody>
        <tr>
          <td><strong>함정</strong>: <code class="language-plaintext highlighter-rouge">mpa.EigenmodeCoefficient</code>의</td>
          <td>a</td>
          <td>²와 <code class="language-plaintext highlighter-rouge">get_eigenmode_coefficients</code>의</td>
          <td>α</td>
          <td>²는 같은 물리량이지만 정규화 관례가 다르다. 둘을 섞어 비율을 만들면 1이 넘는 투과율이 나온다. 분자와 분모를 같은 함수로 재는 것이 계약 4의 실질이다.</td>
        </tr>
      </tbody>
    </table>
  </blockquote>

</details>

<h2 id="interpret">5. 결과 해석하기: 좋아진 숫자가 무엇을 뜻할까?</h2>

<p>이 예제에서는 α가 8까지 커져도 J가 올랐습니다. 그렇다고 큰 step이 언제나 유리한 것은 아닙니다. 08편은 큰 step에서 값이 떨어졌고, 이 예제의 MMA도 <strong>4.31 → 180.7 → 4.5 → 106.2 → 222.4</strong>처럼 오르내렸습니다. 그래서 평가한 설계 중 가장 높은 J를 낸 5회차를 보관합니다.</p>

<table>
  <thead>
    <tr>
      <th>확인할 값</th>
      <th>출발점</th>
      <th>보관한 설계</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>새 run의 mode 1 투과율</td>
      <td>0.0154</td>
      <td>0.7801</td>
    </tr>
    <tr>
      <td>새 run의 전체 flux / 입력 mode 1 power</td>
      <td>0.1165</td>
      <td>0.8040</td>
    </tr>
  </tbody>
</table>

<p>두 열은 같은 참조 입력 power로 정규화했습니다. 최종 T_total과 T_mode1의 차이 약 0.024는 출력면을 지났지만 mode 1로 잡히지 않은 몫입니다.</p>

<p class="lesson-note"><strong>J = 222.4를 투과율로 읽지 않기.</strong> 이를 입력 power 210.6으로 나누면 1.056이 됩니다. 두 수의 정규화 관례가 다르기 때문입니다. 분자와 분모를 같은 함수로 다시 측정한 투과율이 0.7801입니다.</p>

<h3 id="이-설계를-얼마나-믿을-수-있을까">이 설계를 얼마나 믿을 수 있을까?</h3>

<p>gradient gate 통과는 <strong>현재 계산 설정에서 미분이 맞는지</strong> 확인합니다. 최적화 수렴, 해상도 수렴, 제작 가능성까지 보장하지는 않습니다.</p>

<table>
  <thead>
    <tr>
      <th>검사</th>
      <th>이번 결과</th>
      <th>의미</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Gradient gate</td>
      <td>세 step 모두 PASS, 오차 0.01% 이내</td>
      <td>유한차분과 adjoint가 일치</td>
    </tr>
    <tr>
      <td>같은 121개 밀도, 해상도 10 → 20</td>
      <td>T_mode1 0.7801 → 0.6391</td>
      <td>해상도 수렴이 확인되지 않음</td>
    </tr>
    <tr>
      <td>밀도와 평가 횟수</td>
      <td>회색조 119/121개, MMA 5회</td>
      <td>이진 재료 설계나 수렴한 최적해가 아님</td>
    </tr>
  </tbody>
</table>

<p>해상도 검사에서는 <strong>설계 밀도를 그대로 두고 Yee 격자를 세분화</strong>하며, 분모인 참조 입력 power도 새 해상도에서 다시 잽니다. 이번 결과는 adjoint 절차를 배우는 짧은 시연입니다. 다른 파장·편광·3D 성능이나 제조 성능은 이 수치에서 알 수 없습니다.</p>

<h3 id="시간에-따른-빛과-설계의-변화">시간에 따른 빛과 설계의 변화</h3>

<figure class="lesson-figure lesson-animation">
<a href="/meep-examples/assets/meep/09/08_anim_optimized.gif" data-lightbox="" aria-label="갱신한 설계에서 짧은 펄스가 출력 도파관으로 진행하는 애니메이션 원본 확대"><img src="/meep-examples/assets/meep/09/08_anim_optimized.gif" data-animation-src="/meep-examples/assets/meep/09/08_anim_optimized.gif" data-static-src="/meep-examples/assets/meep/09/07_verify.png" alt="갱신한 설계에서 짧은 펄스가 출력 도파관으로 진행하는 애니메이션" loading="lazy" /></a>
<button class="animation-toggle" type="button" hidden="">애니메이션 정지</button>
<figcaption>fwidth = 0.3 fcen의 짧은 펄스가 source에서 출력 monitor로 진행합니다. 정지하면 별도 검증의 실제 field 그림을 보여줍니다.</figcaption>
</figure>

<figure class="lesson-figure lesson-animation">
<a href="/meep-examples/assets/meep/09/09_anim_design.gif" data-lightbox="" aria-label="균일 출발점에서 MMA 평가 1~5와 최종 설계로 변하는 애니메이션 원본 확대"><img src="/meep-examples/assets/meep/09/09_anim_design.gif" data-animation-src="/meep-examples/assets/meep/09/09_anim_design.gif" data-static-src="/meep-examples/assets/meep/09/06_step_mma.png" alt="균일 출발점에서 MMA 평가 1~5와 최종 설계로 변하는 애니메이션" loading="lazy" /></a>
<button class="animation-toggle" type="button" hidden="">애니메이션 정지</button>
<figcaption>균일 출발점 → MMA 평가 1~5 → 보관한 5회차 순으로 바뀝니다. 정지하면 같은 실제 평가 이력의 전체 그림을 보여줍니다.</figcaption>
</figure>

<details>
  <summary>원본 결과 그림·수치표 자세히 보기</summary>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/03_fields.png" data-lightbox="" aria-label="균일 및 랜덤 출발점의 정방향 field와 균일 출발점의 수반 field 원본 확대"><img src="/meep-examples/assets/meep/09/03_fields.png" alt="균일 및 랜덤 출발점의 정방향 field와 균일 출발점의 수반 field" loading="lazy" /></a>
<figcaption>위는 균일 출발점(J = 4.31), 아래는 랜덤 출발점(J = 12.23)의 forward field입니다. 오른쪽 열은 출력에서 시작한 균일 출발점의 adjoint field입니다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/04_gradient.png" data-lightbox="" aria-label="균일한 밀도 0.5에서 계산한 signed gradient와 gradient 절댓값 원본 확대"><img src="/meep-examples/assets/meep/09/04_gradient.png" alt="균일한 밀도 0.5에서 계산한 signed gradient와 gradient 절댓값" loading="lazy" /></a>
<figcaption>초기 gradient의 가장 큰 절댓값은 중앙의 음수 −13.4입니다. 양수 49개, 음수 72개이며, 양수는 주로 두 도파관을 설계 영역 안으로 연장하는 부근에 있습니다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/05_gate.png" data-lightbox="" aria-label="세 step에서 유한차분과 수반 방향미분을 비교한 gradient gate 원본 확대"><img src="/meep-examples/assets/meep/09/05_gate.png" alt="세 step에서 유한차분과 수반 방향미분을 비교한 gradient gate" loading="lazy" /></a>
<figcaption>세 step의 유한차분은 38.240, 38.241, 38.244이고 adjoint는 38.240입니다. 세 번 모두 gate를 통과했습니다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>step</th>
        <th>FD</th>
        <th>adjoint g·v</th>
        <th>상대오차</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>2e-3</td>
        <td>38.2396</td>
        <td>38.2395</td>
        <td>0.0000</td>
      </tr>
      <tr>
        <td>5e-3</td>
        <td>38.2405</td>
        <td>38.2395</td>
        <td>0.0000</td>
      </tr>
      <tr>
        <td>1e-2</td>
        <td>38.2436</td>
        <td>38.2395</td>
        <td>0.0001</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/06_step_mma.png" data-lightbox="" aria-label="한 번의 gradient step 크기별 설계와 MMA 다섯 번의 평가 이력 원본 확대"><img src="/meep-examples/assets/meep/09/06_step_mma.png" alt="한 번의 gradient step 크기별 설계와 MMA 다섯 번의 평가 이력" loading="lazy" /></a>
<figcaption>위는 같은 출발점에서 α만 달리한 한 걸음, 아래는 MMA의 실제 평가 이력입니다. 5회차 J = 222.4를 보관했으며 119/121개 픽셀이 회색조입니다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>α</th>
        <th>J</th>
        <th>J / J_start</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0.2</td>
        <td>16.66</td>
        <td>3.9</td>
      </tr>
      <tr>
        <td>1.0</td>
        <td>118.92</td>
        <td>27.6</td>
      </tr>
      <tr>
        <td>3.0</td>
        <td>176.24</td>
        <td>40.9</td>
      </tr>
      <tr>
        <td>8.0</td>
        <td>235.54</td>
        <td>54.7</td>
      </tr>
    </tbody>
  </table>

  <p>08편에서는 α = 2에서 목적함수가 떨어졌다. 여기서는 α = 8까지 오른다. 출발점이 균일 0.5라 각 픽셀은 “올릴지 내릴지”만 정해지면 되고, 끝까지 밀어 clip되어도 방향이 맞으면 J는 오른다. 08편의 출발점은 이미 괜찮은 설계였고 거기서 멀리 가면 구조가 망가졌다. 좋은 step size는 문제마다 다르다. optimizer가 step을 스스로 조절해야 하는 이유다.</p>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/09/07_verify.png" data-lightbox="" aria-label="새 시뮬레이션에서 다시 측정한 투과율과 출발점 및 갱신 후 전기장 원본 확대"><img src="/meep-examples/assets/meep/09/07_verify.png" alt="새 시뮬레이션에서 다시 측정한 투과율과 출발점 및 갱신 후 전기장" loading="lazy" /></a>
<figcaption>새 시뮬레이션의 정규화 투과율과 Re(Ez)입니다. 갱신한 설계에서는 빛이 위로 꺾여 출력 도파관을 탑니다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>설계</th>
        <th>mode 1 power</th>
        <th>전체 flux</th>
        <th>T_mode1</th>
        <th>T_total</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>균일 0.5 출발점</td>
        <td>3.247</td>
        <td>24.546</td>
        <td>0.0154</td>
        <td>0.1165</td>
      </tr>
      <tr>
        <td>최적화 (MMA eval 5)</td>
        <td>164.29</td>
        <td>169.33</td>
        <td>0.7801</td>
        <td>0.8040</td>
      </tr>
    </tbody>
  </table>

  <p>T_total과 T_mode1의 차이(0.024)는 출력면을 지났지만 mode 1이 아닌 몫이다. 05편의 진단식과 같은 구분이다. optimizer 내부 J = 222.4를 P_in = 210.6으로 나누면 1.056이다. 그 숫자는 투과율이 아니다.</p>

  <h3 id="section-3">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (처음의 예측)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>입력면 mode 1 비율</td>
        <td>0.98~1.02</td>
        <td>1.0043</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>출발점 T_mode1</td>
        <td>몇 %</td>
        <td>0.0154</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>gradient 패턴</td>
        <td>대각선 띠가 양수</td>
        <td>중앙 음수, 두 도파관 연장선이 양수. 대각선은 큰 step 뒤에야 나타남</td>
        <td>❌</td>
      </tr>
      <tr>
        <td>gate 상대오차</td>
        <td>1% 안</td>
        <td>0.00%, 0.00%, 0.01%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>손 step α</td>
        <td>오르다 꺾임</td>
        <td>α = 8까지 계속 상승</td>
        <td>❌</td>
      </tr>
      <tr>
        <td>MMA 5회 뒤 T_mode1</td>
        <td>0.5~0.7</td>
        <td>0.780</td>
        <td>❌ (예측보다 높음)</td>
      </tr>
      <tr>
        <td>해상도 20에서 같은 설계</td>
        <td>몇 % 차이</td>
        <td>0.780 → 0.639</td>
        <td>❌</td>
      </tr>
      <tr>
        <td>회색조 픽셀</td>
        <td>절반 이상</td>
        <td>119 / 121</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>예측이 네 개 틀렸고, 틀린 것이 이 글의 내용이다. 첫째, 날것 gradient는 거울을 그리지 않는다. 첫 미분이 말하는 것은 “중앙의 밀도를 낮추고 두 도파관 연결부의 밀도를 높여라”이고, 대각선은 여러 픽셀이 포화한 뒤에 나타나는 구조다. 둘째, step size의 직관은 문제를 넘어 옮겨지지 않는다. 셋째, 다섯 번으로 0.78까지 간 것은 설계 자유도가 큰 덕이지 설계가 좋아서가 아니다. 넷째, 해상도 20에서 0.64로 떨어진 것은 이 설계가 res 10의 격자에 맞춰진 설계라는 뜻이다.</p>

  <h3 id="section-4">수렴성</h3>

  <table>
    <thead>
      <tr>
        <th>변수</th>
        <th>값</th>
        <th>T_mode1</th>
        <th>T_total</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>해상도</td>
        <td>10</td>
        <td>0.7801</td>
        <td>0.8040</td>
        <td>최적화에 쓴 해상도</td>
      </tr>
      <tr>
        <td>해상도</td>
        <td>20</td>
        <td>0.6391</td>
        <td>0.6870</td>
        <td>같은 11 × 11 밀도, 분모도 res 20 참조 run</td>
      </tr>
      <tr>
        <td>gate step</td>
        <td>2e-3 / 5e-3 / 1e-2</td>
        <td>FD 38.240 / 38.241 / 38.244</td>
        <td>—</td>
        <td>세 step 모두 adjoint 38.240과 0.01% 안</td>
      </tr>
    </tbody>
  </table>

  <p>해상도 10에서 Si 안의 파장은 456 nm이고 격자 간격은 100 nm다. 파장당 4.5칸은 Meep 문서의 권장(8칸 이상)에 못 미친다. 회색조 픽셀이 119개라 유전율이 매끄럽게 변하는 설계인데, 그 보간이 Yee 격자에 어떻게 얹히는지가 해상도에 따라 다르다. res 20에서 다시 최적화하면 다른 설계가 나온다. 별도로 표시한 해상도 검사 외의 최적화 결과는 res 10에서의 값이다.</p>

  <h3 id="section-5">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: 이 셀, 해상도 10, 단일 주파수에서 adjoint gradient는 유한차분과 0.01% 안에서 같다. 균일 0.5에서 다섯 번의 MMA 평가로 출력 mode 1 투과율이 0.015에서 0.780으로 올랐고, 그 값은 별도 run으로 재확인됐다. 08편의 절차는 목적함수를 바꿔도 그대로 쓰인다.</li>
    <li>할 수 없는 것: “0.78짜리 bend를 설계했다”. 121개 중 119개가 회색조라 물리적 재료가 아니다. 해상도 20에서 0.64다. maxeval 5는 수렴이 아니다. 최소 선폭 제약이 없어 이진화하면 값이 달라진다. 다른 파장, 다른 편광, 3D에서의 값.</li>
  </ul>

</details>

<details>
  <summary>문제가 생겼을 때: 증상과 점검 위치</summary>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>투과율이 1을 넘음</td>
        <td>optimizer 내부 J를 P_in으로 나눔</td>
        <td>분자와 분모를 같은 함수(<code class="language-plaintext highlighter-rouge">get_eigenmode_coefficients</code>)로</td>
      </tr>
      <tr>
        <td>mode 1 비율이 0.9 아래</td>
        <td>source 폭이 모드 꼬리를 못 담거나 <code class="language-plaintext highlighter-rouge">eig_kpoint</code> 누락</td>
        <td>참조 run의 field를 먼저 보고 source 폭 2 µm 확인</td>
      </tr>
      <tr>
        <td>gate HOLD</td>
        <td>초기값이 0/1 경계이거나 랜덤 방향</td>
        <td>내부점, gradient 방향(08편 §6)</td>
      </tr>
      <tr>
        <td>손 step에서 값이 떨어짐</td>
        <td>문제에 따라 정상</td>
        <td>꺾이는 α를 기록하고 optimizer에 맡김</td>
      </tr>
      <tr>
        <td>MMA가 중간에 추락</td>
        <td>신뢰영역 과대</td>
        <td>정상 동작. 최고 평가를 보관</td>
      </tr>
      <tr>
        <td>해상도를 올리니 값이 다름</td>
        <td>설계가 격자에 맞춰짐</td>
        <td>목표 해상도에서 최적화하거나 필터로 선폭 제한</td>
      </tr>
      <tr>
        <td>회색조 설계를 소자로 해석</td>
        <td>이진화·선폭 제약 없음</td>
        <td>필터·투영·β 스케줄(공식 adjoint 예제 02 이후)</td>
      </tr>
    </tbody>
  </table>

</details>

<h2 id="check">6. 확인하기: 두 가지를 설명할 수 있나요?</h2>

<details>
  <summary>1. Forward와 adjoint는 각각 어디에서 시작하며, gradient는 무엇을 바꾸라고 하나요?</summary>

  <p>Forward는 왼쪽 입력 도파관의 mode 1 source에서 시작합니다. Adjoint는 출력 mode 1 목적함수에서 유도되어 위쪽 출력 포트에 생긴 source로 별도 계산합니다. 두 계산으로 얻은 gradient는 설계 영역의 121개 밀도를 현재 상태에서 어느 방향으로 바꾸면 J가 늘어나는지 알려 줍니다. 첫 gradient 자체가 최종 도파관 모양은 아닙니다.</p>

</details>

<details>
  <summary>2. J = 222.4이고 투과율이 0.7801인데, 왜 완성된 소자라고 할 수 없나요?</summary>

  <p>J는 optimizer 내부 정규화 값이며 투과율은 새 run과 참조 run에서 다시 측정한 전력의 비입니다. 투과율도 해상도를 20으로 올리면 0.6391로 달라집니다. 설계는 119개 회색조 픽셀을 포함하고 평가도 5회뿐입니다. 해상도·최적화 수렴과 최소 선폭·이진화 검증이 더 필요합니다.</p>

</details>

<h2 id="reference">7. 참고 자료와 전체 코드</h2>

<details>
  <summary>English summary</summary>

  <ul>
    <li><strong>What</strong>: post 05 steered a 90° bend with one number, the radius. Here the corner is a 1 × 1 µm square opened as a free design region of 11 × 11 densities (SiO2 to Si), and the adjoint gradient fills it. The contract is the one from post 08; only the objective changes, from a diffraction order to the mode-1 power at the output port.</li>
    <li><strong>Result</strong>: the source puts 100.4 % of its flux into mode 1. The gradient passes the gate with 0.00 %, 0.00 %, 0.01 % error. Unlike post 08, one hand-made step keeps rising as α grows (3.9×, 28×, 41×, 55×) because pixels saturate at 0/1. Five MMA evaluations lift the internal objective 52×. Measured again in a fresh simulation and normalized to the input mode-1 power, the bend transmission goes from 0.015 to 0.780 (total flux through the port: 0.117 to 0.804). At twice the resolution the same design gives 0.639.</li>
    <li><strong>Takeaway</strong>: the four steps transfer unchanged when the objective changes. What does not transfer is intuition about step size: whether a gradient step overshoots depends on the problem. The optimizer’s internal number is not a transmission (it even exceeds the input power), 119 of 121 pixels are still grey, and the design is not converged in resolution. This is a smoke test, not a device.</li>
    <li><strong>Code</strong>: full script at the bottom, ~29 s on one core.</li>
  </ul>

</details>

<details>
  <summary>처음 세웠던 예측과 추가 실험 아이디어</summary>

  <h3 id="section-6">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>입력면 mode 1 비율</td>
        <td>0.98~1.02</td>
        <td>04편에서 <code class="language-plaintext highlighter-rouge">EigenModeSource</code>는 단일 모드를 넣었다</td>
      </tr>
      <tr>
        <td>균일 0.5 출발점의 T_mode1</td>
        <td>몇 %</td>
        <td>회색 블록은 도파관이 아니다. 빛은 직진해서 새어 나간다</td>
      </tr>
      <tr>
        <td>gradient 패턴</td>
        <td>입력과 출력을 잇는 대각선 띠가 양수</td>
        <td>45° 거울이 가장 단순한 bend다</td>
      </tr>
      <tr>
        <td>gate 상대오차</td>
        <td>1% 안</td>
        <td>08편 0.7%</td>
      </tr>
      <tr>
        <td>손 step α</td>
        <td>오르다 꺾임</td>
        <td>08편과 같은 선형 근사의 한계</td>
      </tr>
      <tr>
        <td>MMA 5회 뒤 T_mode1</td>
        <td>0.5~0.7</td>
        <td>자유도 121, 05편 sharp bend 0.20보다는 높을 것</td>
      </tr>
      <tr>
        <td>해상도 20에서 같은 설계</td>
        <td>몇 % 차이</td>
        <td>설계는 격자에 고정됐으니 유전율 분포는 같다</td>
      </tr>
      <tr>
        <td>회색조 픽셀</td>
        <td>절반 이상</td>
        <td>5회로는 포화하지 않는다</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: gate 상대오차 &gt; 20%면 HOLD. mode 1 비율이 0.95 아래면 source부터 다시. T_mode1 &gt; T_total이면 분해 오류.</p>

  <table>
    <thead>
      <tr>
        <th>바꿀 것</th>
        <th>예상 변화</th>
        <th>확인할 수치</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>설계 영역 1 × 1 → 1.5 × 1.5 µm</td>
        <td>변수 256개, 시간 2배</td>
        <td>T_mode1, 회색조 수</td>
      </tr>
      <tr>
        <td>초기값을 05편의 사분원 bend 모양으로</td>
        <td>출발점 T가 0.9 근처, gradient는 작음</td>
        <td>J_start, gate, 5회 뒤 변화</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">maxeval</code> 5 → 30</td>
        <td>투과율이 어디서 정체하는지</td>
        <td>history, 회색조 수</td>
      </tr>
      <tr>
        <td>res 20에서 처음부터 최적화</td>
        <td>다른 설계, res 10과 비교</td>
        <td>두 해상도의 T_mode1</td>
      </tr>
      <tr>
        <td>목적함수를 두 주파수 평균으로 (<code class="language-plaintext highlighter-rouge">nf=2</code>)</td>
        <td>대역폭 대 피크 trade-off</td>
        <td>각 주파수의 T_mode1</td>
      </tr>
    </tbody>
  </table>

</details>

<h3 id="전체-python-코드">전체 Python 코드</h3>

<details>
<summary>code/bend_inverse.py 전체 (클릭하여 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 09 - Waveguide bend inverse design (adjoint), with the same four-step contract as post 08.

Post 05 turned a 90-degree bend with ONE design variable (the radius). Here the corner is a 1 x 1 um square
opened as a free design region (11 x 11 densities, SiO2..Si) and the adjoint gradient fills it. Only the
objective changes: not a diffraction order but the guided mode-1 power at the output port.
  1. differentiability: eps_averaging=False, MaterialGrid do_averaging=False
  2. gradient gate: adjoint gradient vs centred finite differences along the gradient direction (interior point)
  3. a short MMA run (maxeval 5): a smoke test, not a converged design
  4. verification in a FRESH simulation with get_eigenmode_coefficients, normalized by the input mode-1 power
Plus: source check on a straight waveguide, forward field of uniform and random starts, adjoint field,
raw gradient, one manual step, a resolution check of the final design, two GIFs.

Run:  python bend_inverse.py      (~1 min on one core)
Out:  00_source.png, 01_layout.png, 02_source_check.png, 03_fields.png, 04_gradient.png, 05_gate.png,
      06_step_mma.png, 07_verify.png, 08_anim_optimized.gif, 09_anim_design.gif, result.json  (-&gt; ../assets/09/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">animation</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>
<span class="kn">import</span> <span class="nn">meep.adjoint</span> <span class="k">as</span> <span class="n">mpa</span>
<span class="kn">import</span> <span class="nn">nlopt</span>
<span class="kn">from</span> <span class="nn">autograd</span> <span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">npa</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">HERE</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"09"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">20260820</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- (1) units &amp; parameters (course week 10)
</span><span class="n">wl</span> <span class="o">=</span> <span class="mf">1.55</span>
<span class="n">fcen</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">wl</span>
<span class="n">fwidth</span> <span class="o">=</span> <span class="mf">0.12</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">Si</span><span class="p">,</span> <span class="n">SiO2</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">3.4</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">1.44</span><span class="p">)</span>
<span class="n">RES</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">SX</span><span class="p">,</span> <span class="n">SY</span> <span class="o">=</span> <span class="mf">6.0</span><span class="p">,</span> <span class="mf">5.0</span>
<span class="n">DPML</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">W</span> <span class="o">=</span> <span class="mf">0.5</span>                                   <span class="c1"># waveguide width
</span><span class="n">SRC_X</span><span class="p">,</span> <span class="n">SRC_SIZE</span> <span class="o">=</span> <span class="o">-</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">2.0</span>               <span class="c1"># EigenModeSource on the input waveguide
</span><span class="n">MON_IN_X</span> <span class="o">=</span> <span class="o">-</span><span class="mf">1.0</span>                           <span class="c1"># input-power monitor (between source and design region)
</span><span class="n">MON_OUT_Y</span> <span class="o">=</span> <span class="mf">1.0</span>                           <span class="c1"># objective monitor on the output waveguide
</span><span class="n">D</span> <span class="o">=</span> <span class="mf">1.0</span>                                   <span class="c1"># design region side
</span><span class="n">NX</span> <span class="o">=</span> <span class="n">NY</span> <span class="o">=</span> <span class="mi">11</span>                              <span class="c1"># design grid: 11 x 11 = 121 densities
</span><span class="n">EXTENT</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SX</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">SX</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SY</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">SY</span><span class="p">]</span>
<span class="n">DEXT</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">D</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">D</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">D</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">D</span><span class="p">]</span>

<span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">EigenModeSource</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">),</span> <span class="n">eig_band</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">NO_DIRECTION</span><span class="p">,</span>
                              <span class="n">eig_kpoint</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SRC_SIZE</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SRC_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>
<span class="n">common</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SX</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)],</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">stop_cond</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="mf">1e-5</span><span class="p">)</span>


<span class="c1"># ---------------------------------------------------------------- (2) geometry: input (-x) and output (+y) waveguides + design square
</span><span class="k">def</span> <span class="nf">waveguide_blocks</span><span class="p">():</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="n">SX</span> <span class="o">/</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SX</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">W</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SY</span> <span class="o">/</span> <span class="mi">4</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">SY</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">)]</span>


<span class="k">def</span> <span class="nf">geometry_with</span><span class="p">(</span><span class="n">weights</span><span class="p">):</span>
    <span class="n">grid</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">MaterialGrid</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">),</span> <span class="n">SiO2</span><span class="p">,</span> <span class="n">Si</span><span class="p">,</span> <span class="n">weights</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">weights</span><span class="p">).</span><span class="n">reshape</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">),</span> <span class="n">grid_type</span><span class="o">=</span><span class="s">"U_MEAN"</span><span class="p">,</span> <span class="n">do_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">waveguide_blocks</span><span class="p">()</span> <span class="o">+</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="n">D</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">grid</span><span class="p">)]</span>


<span class="n">design_variables</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">MaterialGrid</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">),</span> <span class="n">SiO2</span><span class="p">,</span> <span class="n">Si</span><span class="p">,</span> <span class="n">grid_type</span><span class="o">=</span><span class="s">"U_MEAN"</span><span class="p">,</span> <span class="n">do_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>     <span class="c1"># contract 1
</span><span class="n">design_region</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">DesignRegion</span><span class="p">(</span><span class="n">design_variables</span><span class="p">,</span> <span class="n">volume</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="n">D</span><span class="p">)))</span>
<span class="n">geometry</span> <span class="o">=</span> <span class="n">waveguide_blocks</span><span class="p">()</span> <span class="o">+</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">center</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">size</span><span class="p">,</span> <span class="n">material</span><span class="o">=</span><span class="n">design_variables</span><span class="p">)]</span>

<span class="c1"># ---------------------------------------------------------------- (4) simulation + (5) objective: output-port mode-1 power
</span><span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
<span class="n">out_mode</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">EigenmodeCoefficient</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span> <span class="n">mode</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">opt</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">OptimizationProblem</span><span class="p">(</span><span class="n">simulation</span><span class="o">=</span><span class="n">sim</span><span class="p">,</span> <span class="n">objective_functions</span><span class="o">=</span><span class="k">lambda</span> <span class="n">a</span><span class="p">:</span> <span class="n">npa</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">,</span> <span class="n">objective_arguments</span><span class="o">=</span><span class="p">[</span><span class="n">out_mode</span><span class="p">],</span>
                              <span class="n">design_regions</span><span class="o">=</span><span class="p">[</span><span class="n">design_region</span><span class="p">],</span> <span class="n">fcen</span><span class="o">=</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">nf</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">x_start</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">ones</span><span class="p">(</span><span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="p">)</span>          <span class="c1"># uniform grey: an interior point, differentiable, no bias
</span><span class="n">opt</span><span class="p">.</span><span class="n">update_design</span><span class="p">([</span><span class="n">x_start</span><span class="p">])</span>
<span class="c1"># a throw-away copy only for the layout figure: plot2D draws flux monitors, mpa objectives it does not
</span><span class="n">sim_plot</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_with</span><span class="p">(</span><span class="n">x_start</span><span class="p">),</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
<span class="n">sim_plot</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
<span class="n">sim_plot</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">MON_IN_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span>
<span class="n">annotated_layout</span><span class="p">(</span>
    <span class="n">sim_plot</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">7.4</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span>
    <span class="n">title</span><span class="o">=</span><span class="s">"bend as a free design region: input -x, output +y, 1 x 1 um square of 11 x 11 densities"</span><span class="p">,</span>
    <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">wl</span><span class="si">}</span><span class="s"> res=</span><span class="si">{</span><span class="n">RES</span><span class="si">}</span><span class="se">\n</span><span class="s">cell </span><span class="si">{</span><span class="n">SX</span><span class="si">}</span><span class="s">x</span><span class="si">{</span><span class="n">SY</span><span class="si">}</span><span class="s">, w=</span><span class="si">{</span><span class="n">W</span><span class="si">}</span><span class="se">\n</span><span class="s">Nx=Ny=</span><span class="si">{</span><span class="n">NX</span><span class="si">}</span><span class="s"> (121 vars)"</span><span class="p">,</span>
    <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">2.9</span><span class="p">,</span> <span class="mf">2.3</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">2.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SY</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="n">decay_text_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.9</span><span class="p">,</span> <span class="mf">1.75</span><span class="p">),</span>
    <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"design region: MaterialGrid, start = uniform 0.5"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">2.9</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.3</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"EigenModeSource, mode 1 -&gt; +x"</span><span class="p">,</span> <span class="p">(</span><span class="n">SRC_X</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">2.9</span><span class="p">,</span> <span class="mf">1.3</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"objective: |a_out|^2 on this line"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.8</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.9</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"input monitor (normalization)"</span><span class="p">,</span> <span class="p">(</span><span class="n">MON_IN_X</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.8</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.2</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
<span class="n">source_figure</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">run_dft_field</span><span class="p">(</span><span class="n">src_list</span><span class="p">,</span> <span class="n">geometry_list</span><span class="p">):</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_list</span><span class="p">,</span> <span class="o">**</span><span class="nb">dict</span><span class="p">(</span><span class="n">common</span><span class="p">,</span> <span class="n">sources</span><span class="o">=</span><span class="n">src_list</span><span class="p">))</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SX</span><span class="p">,</span> <span class="n">SY</span><span class="p">))</span>
    <span class="n">s</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_cond</span><span class="p">)</span>
    <span class="n">field</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">eps</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_epsilon</span><span class="p">();</span> <span class="n">s</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">field</span><span class="p">,</span> <span class="n">eps</span>


<span class="k">def</span> <span class="nf">contour</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">eps</span><span class="p">):</span>
    <span class="n">xs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXTENT</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">EXTENT</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">eps</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="n">ys</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXTENT</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">EXTENT</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">eps</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
    <span class="n">a</span><span class="p">.</span><span class="n">contour</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">,</span> <span class="n">eps</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="p">[</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="mf">1.44</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="mf">3.4</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)],</span> <span class="n">colors</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.6</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.9</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">show_design</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">weights</span><span class="p">,</span> <span class="n">title</span><span class="p">):</span>
    <span class="n">im</span> <span class="o">=</span> <span class="n">a</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">weights</span><span class="p">).</span><span class="n">reshape</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">DEXT</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"gray_r"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">im</span>


<span class="c1"># ---------------------------------------------------------------- source check: straight waveguide, mode-1 share at the input monitor
</span><span class="n">straight</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">W</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">)]</span>
<span class="n">field_src</span><span class="p">,</span> <span class="n">eps_src</span> <span class="o">=</span> <span class="n">run_dft_field</span><span class="p">(</span><span class="n">sources</span><span class="p">,</span> <span class="n">straight</span><span class="p">)</span>
<span class="n">s_in</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">straight</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
<span class="n">mon_in</span> <span class="o">=</span> <span class="n">s_in</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">MON_IN_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span>
<span class="n">s_in</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">MON_IN_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mf">1e-5</span><span class="p">))</span>
<span class="n">total_in</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">mon_in</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">input_power</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">s_in</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mon_in</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">s_in</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"source check: input flux </span><span class="si">{</span><span class="n">total_in</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">e</span><span class="si">}</span><span class="s">, mode-1 power </span><span class="si">{</span><span class="n">input_power</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">e</span><span class="si">}</span><span class="s">, mode-1 share </span><span class="si">{</span><span class="n">input_power</span> <span class="o">/</span> <span class="n">total_in</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">3.8</span><span class="p">))</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_src</span><span class="p">)))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">field_src</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"Re(Ez): wavefront"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_src</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"|Ez|: envelope"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">:</span>
    <span class="n">contour</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">eps_src</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">SRC_X</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">MON_IN_X</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="sa">f</span><span class="s">"source check on a straight waveguide: mode-1 share at x = </span><span class="si">{</span><span class="n">MON_IN_X</span><span class="si">}</span><span class="s"> um is </span><span class="si">{</span><span class="n">input_power</span> <span class="o">/</span> <span class="n">total_in</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_source_check.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">fom</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="s">"""Objective = output-port mode-1 power |a_out|^2 in optimizer units (NOT normalized; see contract 4)."""</span>
    <span class="n">f</span><span class="p">,</span> <span class="n">dJ</span> <span class="o">=</span> <span class="n">opt</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)],</span> <span class="n">need_gradient</span><span class="o">=</span><span class="n">need_gradient</span><span class="p">)</span>
    <span class="n">f</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">f</span><span class="p">).</span><span class="n">squeeze</span><span class="p">()))</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">need_gradient</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">f</span>
    <span class="k">return</span> <span class="n">f</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">squeeze</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">dJ</span><span class="p">))</span>


<span class="c1"># ---------------------------------------------------------------- forward fields: uniform vs random start; adjoint field
</span><span class="n">field_fwd</span><span class="p">,</span> <span class="n">eps_fwd</span> <span class="o">=</span> <span class="n">run_dft_field</span><span class="p">(</span><span class="n">sources</span><span class="p">,</span> <span class="n">geometry_with</span><span class="p">(</span><span class="n">x_start</span><span class="p">))</span>
<span class="n">f_start</span><span class="p">,</span> <span class="n">g_start</span> <span class="o">=</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_start</span><span class="p">,</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">x_random</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">rand</span><span class="p">(</span><span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="p">)</span>
<span class="n">field_rand</span><span class="p">,</span> <span class="n">eps_rand</span> <span class="o">=</span> <span class="n">run_dft_field</span><span class="p">(</span><span class="n">sources</span><span class="p">,</span> <span class="n">geometry_with</span><span class="p">(</span><span class="n">x_random</span><span class="p">))</span>
<span class="n">f_random</span> <span class="o">=</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_random</span><span class="p">)</span>
<span class="n">adjoint_sources</span> <span class="o">=</span> <span class="n">opt</span><span class="p">.</span><span class="n">adjoint_sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">field_adj</span><span class="p">,</span> <span class="n">eps_adj</span> <span class="o">=</span> <span class="n">run_dft_field</span><span class="p">(</span><span class="n">adjoint_sources</span><span class="p">,</span> <span class="n">geometry_with</span><span class="p">(</span><span class="n">x_start</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"forward: uniform-0.5 FOM = </span><span class="si">{</span><span class="n">f_start</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (|grad| = </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_start</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">e</span><span class="si">}</span><span class="s">); random start FOM = </span><span class="si">{</span><span class="n">f_random</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; "</span>
      <span class="sa">f</span><span class="s">"adjoint sources: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">adjoint_sources</span><span class="p">)</span><span class="si">}</span><span class="s"> x </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">adjoint_sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="n">__name__</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">6.4</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"width_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">0.55</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_fwd</span><span class="p">)),</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_rand</span><span class="p">)))</span>
<span class="k">for</span> <span class="n">r</span><span class="p">,</span> <span class="p">(</span><span class="n">weights</span><span class="p">,</span> <span class="n">fld</span><span class="p">,</span> <span class="n">eps</span><span class="p">,</span> <span class="n">tag</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(((</span><span class="n">x_start</span><span class="p">,</span> <span class="n">field_fwd</span><span class="p">,</span> <span class="n">eps_fwd</span><span class="p">,</span> <span class="s">"uniform 0.5"</span><span class="p">,</span> <span class="n">f_start</span><span class="p">),</span> <span class="p">(</span><span class="n">x_random</span><span class="p">,</span> <span class="n">field_rand</span><span class="p">,</span> <span class="n">eps_rand</span><span class="p">,</span> <span class="s">"random seed"</span><span class="p">,</span> <span class="n">f_random</span><span class="p">))):</span>
    <span class="n">show_design</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="n">r</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">weights</span><span class="p">,</span> <span class="sa">f</span><span class="s">"design: </span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="se">\n</span><span class="s">FOM = </span><span class="si">{</span><span class="n">val</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="n">r</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="n">r</span><span class="p">,</span> <span class="mi">1</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">fld</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="n">r</span><span class="p">,</span> <span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"forward Re(Ez)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="n">r</span><span class="p">,</span> <span class="mi">2</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fld</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="n">r</span><span class="p">,</span> <span class="mi">2</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"forward |Ez|"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">[</span><span class="n">r</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span><span class="mi">3</span><span class="p">]:</span>
        <span class="n">contour</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">eps</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">la</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_adj</span><span class="p">)))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">field_adj</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">la</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">la</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"adjoint Re(Ez) (source at the output port)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_adj</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"adjoint |Ez|"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">[:,</span> <span class="mi">3</span><span class="p">]:</span>
    <span class="n">contour</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">eps_adj</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"rows: uniform vs random start (forward); right column: the adjoint field of the uniform start"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_fields.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- raw gradient on the 11 x 11 grid
</span><span class="n">g2</span> <span class="o">=</span> <span class="n">g_start</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">)</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">g2</span><span class="p">)))</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mf">3.8</span><span class="p">))</span>
<span class="n">im0</span> <span class="o">=</span> <span class="n">show_design</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x_start</span><span class="p">,</span> <span class="s">"current design (uniform 0.5)"</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">colorbar</span><span class="p">(</span><span class="n">im0</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">fraction</span><span class="o">=</span><span class="mf">0.046</span><span class="p">)</span>
<span class="n">im1</span> <span class="o">=</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">g2</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">DEXT</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu_r"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"raw adjoint gradient dJ/d(density)</span><span class="se">\n</span><span class="s">red: more Si helps, blue: more SiO2 helps"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">colorbar</span><span class="p">(</span><span class="n">im1</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">fraction</span><span class="o">=</span><span class="mf">0.046</span><span class="p">)</span>
<span class="n">im2</span> <span class="o">=</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">g2</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">DEXT</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"viridis"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"|gradient|: where the design matters most"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">colorbar</span><span class="p">(</span><span class="n">im2</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">fraction</span><span class="o">=</span><span class="mf">0.046</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
    <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_gradient.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"gradient: max </span><span class="si">{</span><span class="n">g2</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s">, min </span><span class="si">{</span><span class="n">g2</span><span class="p">.</span><span class="nb">min</span><span class="p">()</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s">; positive pixels </span><span class="si">{</span><span class="nb">int</span><span class="p">((</span><span class="n">g2</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">).</span><span class="nb">sum</span><span class="p">())</span><span class="si">}</span><span class="s">, negative </span><span class="si">{</span><span class="nb">int</span><span class="p">((</span><span class="n">g2</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">).</span><span class="nb">sum</span><span class="p">())</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- contract 2: gradient gate (uniform 0.5 is already an interior point)
</span><span class="k">assert</span> <span class="n">np</span><span class="p">.</span><span class="nb">all</span><span class="p">((</span><span class="n">x_start</span> <span class="o">&gt;</span> <span class="mf">0.02</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">x_start</span> <span class="o">&lt;</span> <span class="mf">0.98</span><span class="p">))</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">g_start</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_start</span><span class="p">)</span>
<span class="n">adjoint_dd</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">g_start</span><span class="p">,</span> <span class="n">v</span><span class="p">))</span>
<span class="n">steps</span> <span class="o">=</span> <span class="p">[</span><span class="mf">2e-3</span><span class="p">,</span> <span class="mf">5e-3</span><span class="p">,</span> <span class="mf">1e-2</span><span class="p">]</span>
<span class="n">gate_rows</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">step</span> <span class="ow">in</span> <span class="n">steps</span><span class="p">:</span>
    <span class="n">fd</span> <span class="o">=</span> <span class="p">(</span><span class="n">fom</span><span class="p">(</span><span class="n">x_start</span> <span class="o">+</span> <span class="n">step</span> <span class="o">*</span> <span class="n">v</span><span class="p">)</span> <span class="o">-</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_start</span> <span class="o">-</span> <span class="n">step</span> <span class="o">*</span> <span class="n">v</span><span class="p">))</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">step</span><span class="p">)</span>
    <span class="n">rel</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">adjoint_dd</span> <span class="o">-</span> <span class="n">fd</span><span class="p">)</span> <span class="o">/</span> <span class="nb">max</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">fd</span><span class="p">),</span> <span class="mf">1e-30</span><span class="p">)</span>
    <span class="n">gate_rows</span><span class="p">.</span><span class="n">append</span><span class="p">({</span><span class="s">"step"</span><span class="p">:</span> <span class="n">step</span><span class="p">,</span> <span class="s">"fd"</span><span class="p">:</span> <span class="n">fd</span><span class="p">,</span> <span class="s">"adjoint"</span><span class="p">:</span> <span class="n">adjoint_dd</span><span class="p">,</span> <span class="s">"rel_err"</span><span class="p">:</span> <span class="n">rel</span><span class="p">,</span> <span class="s">"pass"</span><span class="p">:</span> <span class="nb">bool</span><span class="p">(</span><span class="n">rel</span> <span class="o">&lt;=</span> <span class="mf">0.20</span> <span class="ow">and</span> <span class="n">np</span><span class="p">.</span><span class="n">sign</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span> <span class="o">==</span> <span class="n">np</span><span class="p">.</span><span class="n">sign</span><span class="p">(</span><span class="n">adjoint_dd</span><span class="p">))})</span>
<span class="n">gradient_gate</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="s">"pass"</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"gate: "</span> <span class="o">+</span> <span class="s">"; "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"step </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'step'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">: FD </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'fd'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">e</span><span class="si">}</span><span class="s"> vs adjoint </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'adjoint'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">e</span><span class="si">}</span><span class="s">, rel </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'rel_err'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> </span><span class="si">{</span><span class="s">'PASS'</span> <span class="k">if</span> <span class="n">r</span><span class="p">[</span><span class="s">'pass'</span><span class="p">]</span> <span class="k">else</span> <span class="s">'HOLD'</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">)</span>
      <span class="o">+</span> <span class="sa">f</span><span class="s">" -&gt; gradient gate </span><span class="si">{</span><span class="s">'PASS'</span> <span class="k">if</span> <span class="n">gradient_gate</span> <span class="k">else</span> <span class="s">'HOLD'</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">3.4</span><span class="p">))</span>
<span class="n">idx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">steps</span><span class="p">))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">r</span><span class="p">[</span><span class="s">"fd"</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:orange"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"centred finite difference"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">adjoint_dd</span><span class="p">]</span> <span class="o">*</span> <span class="mi">3</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"adjoint  g . v"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticklabels</span><span class="p">([</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">s</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">steps</span><span class="p">]);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"finite-difference step"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"directional derivative"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"adjoint vs finite difference along the gradient direction"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">bars</span> <span class="o">=</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="p">[</span><span class="n">r</span><span class="p">[</span><span class="s">"rel_err"</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="p">[</span><span class="s">"tab:green"</span> <span class="k">if</span> <span class="n">r</span><span class="p">[</span><span class="s">"pass"</span><span class="p">]</span> <span class="k">else</span> <span class="s">"tab:red"</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">])</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mf">0.20</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"gate: 20 %"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">b</span><span class="p">,</span> <span class="n">r</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">bars</span><span class="p">,</span> <span class="n">gate_rows</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">get_x</span><span class="p">()</span> <span class="o">+</span> <span class="n">b</span><span class="p">.</span><span class="n">get_width</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">r</span><span class="p">[</span><span class="s">"rel_err"</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.004</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'rel_err'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xticklabels</span><span class="p">([</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">s</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">steps</span><span class="p">]);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.25</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"relative error"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"gradient gate: </span><span class="si">{</span><span class="s">'PASS'</span> <span class="k">if</span> <span class="n">gradient_gate</span> <span class="k">else</span> <span class="s">'HOLD'</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_gate.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">gradient_gate</span><span class="p">:</span>
    <span class="k">raise</span> <span class="nb">SystemExit</span><span class="p">(</span><span class="s">"gradient gate HOLD: do not interpret optimizer results"</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- one manual step, then MMA (contract 3)
</span><span class="n">one_step</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">alpha</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">0.2</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">8.0</span><span class="p">):</span>
    <span class="n">x_try</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x_start</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">v</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">one_step</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="n">alpha</span><span class="p">,</span> <span class="n">x_try</span><span class="p">,</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_try</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"one manual step: "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"alpha </span><span class="si">{</span><span class="n">a</span><span class="si">}</span><span class="s"> -&gt; </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="n">f</span> <span class="o">/</span> <span class="n">f_start</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">x)"</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">one_step</span><span class="p">))</span>

<span class="n">history</span><span class="p">,</span> <span class="n">design_history</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>


<span class="k">def</span> <span class="nf">nlopt_objective</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">grad</span><span class="p">):</span>
    <span class="n">f</span><span class="p">,</span> <span class="n">dJ</span> <span class="o">=</span> <span class="n">fom</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">grad</span><span class="p">.</span><span class="n">size</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">grad</span><span class="p">[:]</span> <span class="o">=</span> <span class="n">dJ</span>
    <span class="n">history</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">f</span><span class="p">);</span> <span class="n">design_history</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">copy</span><span class="o">=</span><span class="bp">True</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">f</span>


<span class="n">solver</span> <span class="o">=</span> <span class="n">nlopt</span><span class="p">.</span><span class="n">opt</span><span class="p">(</span><span class="n">nlopt</span><span class="p">.</span><span class="n">LD_MMA</span><span class="p">,</span> <span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="p">)</span>
<span class="n">solver</span><span class="p">.</span><span class="n">set_lower_bounds</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="p">));</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_upper_bounds</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">ones</span><span class="p">(</span><span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="p">))</span>
<span class="n">solver</span><span class="p">.</span><span class="n">set_max_objective</span><span class="p">(</span><span class="n">nlopt_objective</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_maxeval</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">solver</span><span class="p">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">x_start</span><span class="p">.</span><span class="n">copy</span><span class="p">())</span>
<span class="n">best_k</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">history</span><span class="p">))</span>
<span class="n">x_optimized</span> <span class="o">=</span> <span class="n">design_history</span><span class="p">[</span><span class="n">best_k</span><span class="p">]</span>                          <span class="c1"># keep the best evaluated design (MMA may overshoot)
</span><span class="n">gray</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">((</span><span class="n">x_optimized</span> <span class="o">&gt;</span> <span class="mf">0.02</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">x_optimized</span> <span class="o">&lt;</span> <span class="mf">0.98</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"MMA (maxeval 5): "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"eval </span><span class="si">{</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">f</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">history</span><span class="p">))</span> <span class="o">+</span> <span class="sa">f</span><span class="s">"; best eval </span><span class="si">{</span><span class="n">best_k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s"> = </span><span class="si">{</span><span class="nb">max</span><span class="p">(</span><span class="n">history</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="nb">max</span><span class="p">(</span><span class="n">history</span><span class="p">)</span> <span class="o">/</span> <span class="n">history</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">x); grayscale pixels </span><span class="si">{</span><span class="n">gray</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mf">5.6</span><span class="p">))</span>
<span class="n">show_design</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">x_start</span><span class="p">,</span> <span class="sa">f</span><span class="s">"start (uniform 0.5)</span><span class="se">\n</span><span class="s">FOM </span><span class="si">{</span><span class="n">f_start</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">x_try</span><span class="p">,</span> <span class="n">f_try</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span><span class="mi">5</span><span class="p">],</span> <span class="n">one_step</span><span class="p">):</span>
    <span class="n">show_design</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">x_try</span><span class="p">,</span> <span class="sa">f</span><span class="s">"one step, alpha = </span><span class="si">{</span><span class="n">alpha</span><span class="si">}</span><span class="se">\n</span><span class="s">FOM </span><span class="si">{</span><span class="n">f_try</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">history</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="n">history</span><span class="p">,</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="n">f_start</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"uniform start"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">set_xticks</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">history</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">));</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"MMA evaluation"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"|a_out|^2 (optimizer units)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"MMA history"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
    <span class="n">show_design</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">],</span> <span class="n">design_history</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="sa">f</span><span class="s">"MMA eval </span><span class="si">{</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">  FOM </span><span class="si">{</span><span class="n">history</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="o">+</span> <span class="p">(</span><span class="s">"  (kept)"</span> <span class="k">if</span> <span class="n">k</span> <span class="o">==</span> <span class="n">best_k</span> <span class="k">else</span> <span class="s">""</span><span class="p">))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">show_design</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span> <span class="n">x_optimized</span><span class="p">,</span> <span class="sa">f</span><span class="s">"optimized (eval </span><span class="si">{</span><span class="n">best_k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">)</span><span class="se">\n</span><span class="si">{</span><span class="n">gray</span><span class="si">}</span><span class="s"> grey px of </span><span class="si">{</span><span class="n">NX</span> <span class="o">*</span> <span class="n">NY</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"top: one manual gradient step (alpha sweep) and the MMA history; bottom: the design at every MMA evaluation"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"06_step_mma.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>


<span class="c1"># ---------------------------------------------------------------- contract 4: fresh simulation, modal power / input mode-1 power
</span><span class="k">def</span> <span class="nf">modal_power</span><span class="p">(</span><span class="n">weights</span><span class="p">,</span> <span class="n">res</span><span class="o">=</span><span class="n">RES</span><span class="p">):</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_with</span><span class="p">(</span><span class="n">weights</span><span class="p">),</span> <span class="o">**</span><span class="nb">dict</span><span class="p">(</span><span class="n">common</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">))</span>
    <span class="n">mon</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SX</span><span class="p">,</span> <span class="n">SY</span><span class="p">))</span>
    <span class="n">s</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_cond</span><span class="p">)</span>
    <span class="n">total</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">mon</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">mode1</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mon</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>
    <span class="n">field</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">eps</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_epsilon</span><span class="p">();</span> <span class="n">s</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">mode1</span><span class="p">,</span> <span class="n">total</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">eps</span>


<span class="n">report</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">tag</span><span class="p">,</span> <span class="n">weights</span> <span class="ow">in</span> <span class="p">((</span><span class="s">"start"</span><span class="p">,</span> <span class="n">x_start</span><span class="p">),</span> <span class="p">(</span><span class="s">"optimized"</span><span class="p">,</span> <span class="n">x_optimized</span><span class="p">)):</span>
    <span class="n">mode1</span><span class="p">,</span> <span class="n">total</span><span class="p">,</span> <span class="n">fld</span><span class="p">,</span> <span class="n">eps</span> <span class="o">=</span> <span class="n">modal_power</span><span class="p">(</span><span class="n">weights</span><span class="p">)</span>
    <span class="n">report</span><span class="p">[</span><span class="n">tag</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"mode1"</span><span class="p">:</span> <span class="n">mode1</span><span class="p">,</span> <span class="s">"total"</span><span class="p">:</span> <span class="n">total</span><span class="p">,</span> <span class="s">"T_mode1"</span><span class="p">:</span> <span class="n">mode1</span> <span class="o">/</span> <span class="n">input_power</span><span class="p">,</span> <span class="s">"T_total"</span><span class="p">:</span> <span class="n">total</span> <span class="o">/</span> <span class="n">input_power</span><span class="p">,</span> <span class="s">"field"</span><span class="p">:</span> <span class="n">fld</span><span class="p">,</span> <span class="s">"eps"</span><span class="p">:</span> <span class="n">eps</span><span class="p">}</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"verify [</span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="s">]: mode-1 power </span><span class="si">{</span><span class="n">mode1</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s">, total flux </span><span class="si">{</span><span class="n">total</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s"> -&gt; T_mode1 </span><span class="si">{</span><span class="n">mode1</span> <span class="o">/</span> <span class="n">input_power</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, T_total </span><span class="si">{</span><span class="n">total</span> <span class="o">/</span> <span class="n">input_power</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="c1"># resolution check of the final design (same 11 x 11 densities, finer Yee grid)
</span><span class="n">res_check</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">res</span> <span class="ow">in</span> <span class="p">(</span><span class="n">RES</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">RES</span><span class="p">):</span>
    <span class="n">m1</span><span class="p">,</span> <span class="n">tot</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">modal_power</span><span class="p">(</span><span class="n">x_optimized</span><span class="p">,</span> <span class="n">res</span><span class="o">=</span><span class="n">res</span><span class="p">)</span>
    <span class="n">s_in2</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">straight</span><span class="p">,</span> <span class="o">**</span><span class="nb">dict</span><span class="p">(</span><span class="n">common</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">))</span>
    <span class="n">mi</span> <span class="o">=</span> <span class="n">s_in2</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">MON_IN_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span>
    <span class="n">s_in2</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">MON_IN_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mf">1e-5</span><span class="p">))</span>
    <span class="n">pin</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">s_in2</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mi</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span><span class="p">);</span> <span class="n">s_in2</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">res_check</span><span class="p">[</span><span class="n">res</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"T_mode1"</span><span class="p">:</span> <span class="n">m1</span> <span class="o">/</span> <span class="n">pin</span><span class="p">,</span> <span class="s">"T_total"</span><span class="p">:</span> <span class="n">tot</span> <span class="o">/</span> <span class="n">pin</span><span class="p">}</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"resolution check [</span><span class="si">{</span><span class="n">res</span><span class="si">}</span><span class="s">]: T_mode1 </span><span class="si">{</span><span class="n">m1</span> <span class="o">/</span> <span class="n">pin</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, T_total </span><span class="si">{</span><span class="n">tot</span> <span class="o">/</span> <span class="n">pin</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">4.2</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"width_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">1.1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
<span class="n">idx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">tm</span> <span class="o">=</span> <span class="p">[</span><span class="n">report</span><span class="p">[</span><span class="s">"start"</span><span class="p">][</span><span class="s">"T_mode1"</span><span class="p">],</span> <span class="n">report</span><span class="p">[</span><span class="s">"optimized"</span><span class="p">][</span><span class="s">"T_mode1"</span><span class="p">]];</span> <span class="n">tt</span> <span class="o">=</span> <span class="p">[</span><span class="n">report</span><span class="p">[</span><span class="s">"start"</span><span class="p">][</span><span class="s">"T_total"</span><span class="p">],</span> <span class="n">report</span><span class="p">[</span><span class="s">"optimized"</span><span class="p">][</span><span class="s">"T_total"</span><span class="p">]]</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">tm</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"T_mode1 (output mode 1)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">tt</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"T_total (all flux)"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">k</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">tm</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.01</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">tm</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">tt</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.01</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">tt</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticklabels</span><span class="p">([</span><span class="s">"uniform start"</span><span class="p">,</span> <span class="sa">f</span><span class="s">"after MMA (eval </span><span class="si">{</span><span class="n">best_k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">)"</span><span class="p">]);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"normalized to input mode-1 power"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"contract 4: measured again in a new simulation"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">report</span><span class="p">[</span><span class="s">"start"</span><span class="p">][</span><span class="s">"field"</span><span class="p">])),</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">report</span><span class="p">[</span><span class="s">"optimized"</span><span class="p">][</span><span class="s">"field"</span><span class="p">])))</span>
<span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">tag</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">:],</span> <span class="p">(</span><span class="s">"start"</span><span class="p">,</span> <span class="s">"optimized"</span><span class="p">)):</span>
    <span class="n">a</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">report</span><span class="p">[</span><span class="n">tag</span><span class="p">][</span><span class="s">"field"</span><span class="p">]).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
    <span class="n">contour</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">report</span><span class="p">[</span><span class="n">tag</span><span class="p">][</span><span class="s">"eps"</span><span class="p">]);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"Re(Ez), </span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="s">  (T_mode1 = </span><span class="si">{</span><span class="n">report</span><span class="p">[</span><span class="n">tag</span><span class="p">][</span><span class="s">'T_mode1'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"07_verify.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- GIF 1: a short pulse through the optimized bend (source -&gt; output monitor)
</span><span class="n">fw_anim</span> <span class="o">=</span> <span class="mf">0.3</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">sim_a</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_with</span><span class="p">(</span><span class="n">x_optimized</span><span class="p">),</span> <span class="o">**</span><span class="nb">dict</span><span class="p">(</span><span class="n">common</span><span class="p">,</span> <span class="n">sources</span><span class="o">=</span><span class="p">[</span>
    <span class="n">mp</span><span class="p">.</span><span class="n">EigenModeSource</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw_anim</span><span class="p">),</span> <span class="n">eig_band</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">NO_DIRECTION</span><span class="p">,</span> <span class="n">eig_kpoint</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
                       <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SRC_SIZE</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SRC_X</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]))</span>
<span class="n">sim_a</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">vol_a</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SX</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">SY</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">))</span>
<span class="n">eps_a</span> <span class="o">=</span> <span class="n">sim_a</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">vol_a</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">ext_a</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="p">(</span><span class="n">SX</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">SX</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="n">SY</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">SY</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">]</span>
<span class="n">t0</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="n">fw_anim</span>
<span class="n">path</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">SRC_X</span><span class="p">)</span> <span class="o">+</span> <span class="n">SY</span> <span class="o">/</span> <span class="mi">2</span>                                    <span class="c1"># input straight + output straight, roughly
</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_a</span><span class="p">,</span> <span class="n">vol_a</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t0</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">fw_anim</span><span class="p">,</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t0</span> <span class="o">+</span> <span class="mf">1.2</span> <span class="o">*</span> <span class="n">path</span> <span class="o">*</span> <span class="mf">3.4</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="n">ext_a</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"08_anim_optimized.gif"</span><span class="p">),</span> <span class="n">eps</span><span class="o">=</span><span class="n">eps_a</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">6.2</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span>
               <span class="n">lines</span><span class="o">=</span><span class="p">[((</span><span class="n">SRC_X</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="n">SRC_X</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"source"</span><span class="p">),</span> <span class="p">((</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">MON_OUT_Y</span><span class="p">),</span> <span class="s">"blue"</span><span class="p">,</span> <span class="s">"output monitor"</span><span class="p">)],</span>
               <span class="n">title</span><span class="o">=</span><span class="s">"optimized bend"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- GIF 2: how the design changed, start -&gt; every MMA eval -&gt; final
</span><span class="n">evo</span> <span class="o">=</span> <span class="p">[</span><span class="n">x_start</span><span class="p">]</span> <span class="o">+</span> <span class="n">design_history</span> <span class="o">+</span> <span class="p">[</span><span class="n">x_optimized</span><span class="p">]</span>
<span class="n">evo_lab</span> <span class="o">=</span> <span class="p">[</span><span class="s">"start"</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="sa">f</span><span class="s">"eval </span><span class="si">{</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">design_history</span><span class="p">))]</span> <span class="o">+</span> <span class="p">[</span><span class="sa">f</span><span class="s">"final (eval </span><span class="si">{</span><span class="n">best_k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">)"</span><span class="p">]</span>
<span class="n">evo_fom</span> <span class="o">=</span> <span class="p">[</span><span class="n">f_start</span><span class="p">]</span> <span class="o">+</span> <span class="n">history</span> <span class="o">+</span> <span class="p">[</span><span class="nb">max</span><span class="p">(</span><span class="n">history</span><span class="p">)]</span>
<span class="n">fig_e</span><span class="p">,</span> <span class="n">ax_e</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">4.0</span><span class="p">,</span> <span class="mf">3.8</span><span class="p">))</span>
<span class="n">im_e</span> <span class="o">=</span> <span class="n">ax_e</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">evo</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">reshape</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">DEXT</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"gray_r"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
<span class="n">ax_e</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">ax_e</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">);</span> <span class="n">ttl_e</span> <span class="o">=</span> <span class="n">ax_e</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig_e</span><span class="p">.</span><span class="n">colorbar</span><span class="p">(</span><span class="n">im_e</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="n">ax_e</span><span class="p">,</span> <span class="n">fraction</span><span class="o">=</span><span class="mf">0.046</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"density (0 = SiO2, 1 = Si)"</span><span class="p">)</span>
<span class="n">fig_e</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">_evo</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
    <span class="n">im_e</span><span class="p">.</span><span class="n">set_data</span><span class="p">(</span><span class="n">evo</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">reshape</span><span class="p">(</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">).</span><span class="n">T</span><span class="p">);</span> <span class="n">ttl_e</span><span class="p">.</span><span class="n">set_text</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">evo_lab</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">}</span><span class="s">   FOM = </span><span class="si">{</span><span class="n">evo_fom</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">im_e</span><span class="p">,</span> <span class="n">ttl_e</span>


<span class="n">animation</span><span class="p">.</span><span class="n">FuncAnimation</span><span class="p">(</span><span class="n">fig_e</span><span class="p">,</span> <span class="n">_evo</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">evo</span><span class="p">),</span> <span class="n">blit</span><span class="o">=</span><span class="bp">False</span><span class="p">).</span><span class="n">save</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"09_anim_design.gif"</span><span class="p">),</span> <span class="n">writer</span><span class="o">=</span><span class="n">animation</span><span class="p">.</span><span class="n">PillowWriter</span><span class="p">(</span><span class="n">fps</span><span class="o">=</span><span class="mf">1.5</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">80</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig_e</span><span class="p">)</span>

<span class="k">if</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">():</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"params"</span><span class="p">:</span> <span class="p">{</span><span class="s">"wl"</span><span class="p">:</span> <span class="n">wl</span><span class="p">,</span> <span class="s">"res"</span><span class="p">:</span> <span class="n">RES</span><span class="p">,</span> <span class="s">"cell"</span><span class="p">:</span> <span class="p">[</span><span class="n">SX</span><span class="p">,</span> <span class="n">SY</span><span class="p">],</span> <span class="s">"w"</span><span class="p">:</span> <span class="n">W</span><span class="p">,</span> <span class="s">"design"</span><span class="p">:</span> <span class="p">[</span><span class="n">D</span><span class="p">,</span> <span class="n">D</span><span class="p">],</span> <span class="s">"N"</span><span class="p">:</span> <span class="p">[</span><span class="n">NX</span><span class="p">,</span> <span class="n">NY</span><span class="p">],</span> <span class="s">"fwidth_rel"</span><span class="p">:</span> <span class="mf">0.12</span><span class="p">},</span>
                   <span class="s">"source_check"</span><span class="p">:</span> <span class="p">{</span><span class="s">"total_in"</span><span class="p">:</span> <span class="n">total_in</span><span class="p">,</span> <span class="s">"input_power"</span><span class="p">:</span> <span class="n">input_power</span><span class="p">,</span> <span class="s">"mode1_share"</span><span class="p">:</span> <span class="n">input_power</span> <span class="o">/</span> <span class="n">total_in</span><span class="p">},</span>
                   <span class="s">"fom"</span><span class="p">:</span> <span class="p">{</span><span class="s">"start"</span><span class="p">:</span> <span class="n">f_start</span><span class="p">,</span> <span class="s">"random"</span><span class="p">:</span> <span class="n">f_random</span><span class="p">,</span> <span class="s">"grad_norm"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_start</span><span class="p">)),</span>
                           <span class="s">"grad_max"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">g2</span><span class="p">.</span><span class="nb">max</span><span class="p">()),</span> <span class="s">"grad_min"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">g2</span><span class="p">.</span><span class="nb">min</span><span class="p">()),</span> <span class="s">"grad_pos"</span><span class="p">:</span> <span class="nb">int</span><span class="p">((</span><span class="n">g2</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">).</span><span class="nb">sum</span><span class="p">()),</span> <span class="s">"grad_neg"</span><span class="p">:</span> <span class="nb">int</span><span class="p">((</span><span class="n">g2</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">).</span><span class="nb">sum</span><span class="p">())},</span>
                   <span class="s">"gate"</span><span class="p">:</span> <span class="n">gate_rows</span><span class="p">,</span> <span class="s">"gate_pass"</span><span class="p">:</span> <span class="n">gradient_gate</span><span class="p">,</span>
                   <span class="s">"one_step"</span><span class="p">:</span> <span class="p">[{</span><span class="s">"alpha"</span><span class="p">:</span> <span class="n">a</span><span class="p">,</span> <span class="s">"fom"</span><span class="p">:</span> <span class="n">f</span><span class="p">}</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">one_step</span><span class="p">],</span>
                   <span class="s">"mma"</span><span class="p">:</span> <span class="p">{</span><span class="s">"history"</span><span class="p">:</span> <span class="n">history</span><span class="p">,</span> <span class="s">"best_eval"</span><span class="p">:</span> <span class="n">best_k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"gray_pixels"</span><span class="p">:</span> <span class="n">gray</span><span class="p">},</span>
                   <span class="s">"verify"</span><span class="p">:</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">{</span><span class="n">kk</span><span class="p">:</span> <span class="n">vv</span> <span class="k">for</span> <span class="n">kk</span><span class="p">,</span> <span class="n">vv</span> <span class="ow">in</span> <span class="n">v</span><span class="p">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">kk</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s">"field"</span><span class="p">,</span> <span class="s">"eps"</span><span class="p">)}</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">report</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"resolution_check"</span><span class="p">:</span> <span class="n">res_check</span><span class="p">,</span>
                   <span class="s">"x_optimized"</span><span class="p">:</span> <span class="n">x_optimized</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">,</span> <span class="s">"nlopt"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">nlopt</span><span class="p">.</span><span class="n">version_major</span><span class="p">()</span><span class="si">}</span><span class="s">.</span><span class="si">{</span><span class="n">nlopt</span><span class="p">.</span><span class="n">version_minor</span><span class="p">()</span><span class="si">}</span><span class="s">"</span><span class="p">},</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span></code></pre></figure>

</details>

<p>§4의 발췌 코드와 달리 전체 코드에는 그림 저장·GIF 두 개·result.json 기록·해상도 20 재측정이 들어 있다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

<p><strong>실행 결과 (2026-10-23 실행)</strong>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>source check: input flux 2.09705e+02, mode-1 power 2.10614e+02, mode-1 share 1.0043
forward: uniform-0.5 FOM = 4.3095 (|grad| = 3.824e+01); random start FOM = 12.2263; adjoint sources: 1 x EigenModeSource
gradient: max +4.4568e+00, min -1.3404e+01; positive pixels 49, negative 72
gate: step 2e-03: FD 3.82396e+01 vs adjoint 3.82395e+01, rel 0.0000 PASS; step 5e-03: FD 3.82405e+01 vs adjoint 3.82395e+01, rel 0.0000 PASS; step 1e-02: FD 3.82436e+01 vs adjoint 3.82395e+01, rel 0.0001 PASS -&gt; gradient gate PASS
one manual step: alpha 0.2 -&gt; 16.657 (3.9x), alpha 1.0 -&gt; 118.917 (27.6x), alpha 3.0 -&gt; 176.244 (40.9x), alpha 8.0 -&gt; 235.537 (54.7x)
MMA (maxeval 5): eval 1: 4.310, eval 2: 180.684, eval 3: 4.533, eval 4: 106.244, eval 5: 222.402; best eval 5 = 222.402 (51.6x); grayscale pixels 119/121
verify [start]: mode-1 power 3.2469e+00, total flux 2.4546e+01 -&gt; T_mode1 0.0154, T_total 0.1165
verify [optimized]: mode-1 power 1.6429e+02, total flux 1.6933e+02 -&gt; T_mode1 0.7801, T_total 0.8040
resolution check [10]: T_mode1 0.7801, T_total 0.8040
resolution check [20]: T_mode1 0.6391, T_total 0.6870
</code></pre></div></div>

<p><strong>재현 환경</strong>: meep 1.33.0 · nlopt 2.x · autograd · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep nlopt autograd</code> · 실행 <code class="language-plaintext highlighter-rouge">python bend_inverse.py</code> (약 29 s, 단일 코어)</p>

<h3 id="공식-문서와-이어-읽기">공식 문서와 이어 읽기</h3>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Adjoint_Solver/">공식 Adjoint Solver 튜토리얼</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/adjoint_optimization/01-Introduction.ipynb">adjoint 예제 01 Introduction (waveguide bend)</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/adjoint_optimization/02-Filtered_Waveguide_Bend.ipynb">adjoint 예제 02 filtering and projection</a></li>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#materialgrid"><code class="language-plaintext highlighter-rouge">MaterialGrid</code> 레퍼런스</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#eigenmodesource"><code class="language-plaintext highlighter-rouge">EigenModeSource</code></a> · <a href="https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/#mma-method-of-moving-asymptotes-and-ccsa">NLopt MMA</a></li>
  <li>이전 글: <a href="/meep-examples/metagrating-inverse/">08 · Metagrating inverse design</a> · 설계 변수 하나였던 bend: <a href="/meep-examples/waveguide-bend-90/">05 · Bent waveguide와 radius trade-off</a> · 시리즈 처음: <a href="/meep-examples/point-line-source/">01 · Point source와 line source</a> · 다음 글(시즌 2): <a href="/meep-examples/dipole-pattern-3d/">10 · 점광원의 3D 방사 패턴</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="adjoint" /><category term="inverse-design" /><category term="waveguide-bend" /><category term="nlopt" /><category term="mma" /><summary type="html"><![CDATA[post 05 steered a 90° bend with one number, the radius. Here the corner is a 1 × 1 µm square opened as a free design region of 11 × 11 densities (SiO2 to Si), and the adjoint gradient fills it. The contract is the one from post 08; only the objective changes, from a diffraction order to the mode-1 power at the output port.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/09/07_verify.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/09/07_verify.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 06 · Binary grating과 diffraction order — grating equation, 차수별 효율, duty cycle이 만드는 위상</title><link href="https://jin-castle.github.io/meep-examples/binary-grating/" rel="alternate" type="text/html" title="Meep Example 06 · Binary grating과 diffraction order — grating equation, 차수별 효율, duty cycle이 만드는 위상" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/binary-grating</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/binary-grating/"><![CDATA[<details>
  <summary>English summary</summary>

  <ul>
    <li><strong>What</strong>: a glass binary grating under a normally incident plane wave. One period with Bloch-periodic boundaries gives the power in each diffraction order; a subwavelength period gives the amplitude and phase of the only surviving order as the duty cycle changes; a finite 8-ridge grating shows the beams.</li>
    <li><strong>Result</strong>: for a 2.6 µm period only m = 0, ±1 propagate (±36.6°). Power: m = 0 0.759, m = ±1 0.088 each; the orders add up to the transmitted flux and T + R = 0.999. The finite grating’s beams sit at 35.2° by spatial FFT. A duty-cycle sweep of a 1.2 µm period turns the phase by 0.09 × 2π (h = 0.35 µm) or 0.23 × 2π (h = 0.9 µm), close to Δn·h/λ.</li>
    <li><strong>Takeaway</strong>: the grating equation fixes where the light can go; only a simulation says how much goes where. A single period with <code class="language-plaintext highlighter-rouge">k_point</code> is enough for the numbers, and <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code> decomposes the transmitted field order by order.</li>
    <li><strong>Code</strong>: full script at the bottom, ~27 s on one core.</li>
  </ul>

</details>

<h2 id="observe">1. 관찰 · 빛의 경로를 먼저 보기</h2>

<p>유리 막대 8개에 왼쪽에서 평면파를 보냈습니다. 막대 뒤에서 빛이 <strong>곧장 가는 방향과 비스듬히 가는 방향</strong>으로 나뉩니다. 청록 점선은 방정식으로 예측한 방향이고, 오른쪽 곡선은 실제 필드의 공간 FFT입니다.</p>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/06/04_finite.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/06/04_finite.png" alt="유한한 8개 유리 격자 뒤의 세 회절 빔과 산란장 공간 FFT 피크." loading="lazy" />
  </a>
  <figcaption>유한 격자의 실제 필드입니다. 예측 각도는 0°, ±36.6°이고 FFT에서 읽은 양의 피크는 35.2°입니다. 두 값의 비교에는 유한한 cut 길이의 분해능을 함께 봐야 합니다.</figcaption>
</figure>

<figure class="lesson-figure lesson-animation">
  <a href="/meep-examples/assets/meep/06/05_anim_finite.gif" data-lightbox="">
    <img src="/meep-examples/assets/meep/06/05_anim_finite.gif" alt="8개 유리 막대 뒤에서 세 회절 빔이 형성되는 펄스의 시간 전개" loading="lazy" data-animation-src="/meep-examples/assets/meep/06/05_anim_finite.gif" data-static-src="/meep-examples/assets/meep/06/04_finite.png" />
  </a>
  <button class="animation-toggle" type="button" hidden="">애니메이션 정지</button>
  <figcaption>같은 유한 격자를 짧은 펄스로. 평면파가 막대를 지나는 순간 막대마다 산란파가 생기고, 그것들이 보강되는 세 방향으로만 빔이 자란다. 0차는 곧장, ±1차는 비스듬히.</figcaption>
</figure>

<h2 id="predict">2. 예측 · 결과를 읽기 전에</h2>

<p>파장 1.55 µm에서 주기를 2.6 µm에서 1.2 µm로 줄이면, 공기 쪽으로 전파하는 ±1차 빔은 어떻게 될까요?</p>

<fieldset class="prediction">
  <legend>먼저 하나를 골라보세요.</legend>
  <label><input type="radio" name="prediction-06" value="0" /> 주기가 작아져 더 큰 각도로 계속 전파한다</label>
  <label><input type="radio" name="prediction-06" value="1" /> 전파 조건을 벗어나 0차만 남는다</label>
</fieldset>

<details>
  <summary>예측의 근거 확인하기</summary>

  <p>두 번째입니다. ±1차는 sin θ = ±λ/Λ를 만족해야 합니다. 1.55/1.2가 1보다 커 실수 각도가 없으므로 공기 중으로 멀리 전파하지 않습니다. 구조 가까이의 소멸장까지 사라진다는 뜻은 아닙니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기 · 관찰을 설명하는 방법</h2>

<!-- concept-illustration:part-06:start -->

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/06/00_concept.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/06/00_concept.png" alt="왼쪽은 유리에서 공기로 돌출한 한 주기 격자와 y 주기 경계 및 x PML, 오른쪽은 +x 기준 0도와 ±36.6도의 공기 중 회절 방향을 보여준다." loading="lazy" />
  </a>
  <figcaption>A 실험의 유리(n = 1.5)는 왼쪽에 있고, 유리 돌출부가 오른쪽 공기로 이어집니다. 빛은 유리에서 +x 방향으로 입사합니다. y 방향 주기 2.6 µm, 돌출 높이 0.5 µm, 폭 1.3 µm이며 한 주기 셀은 y 주기 경계와 x PML을 사용합니다. 파장 1.55 µm에서 공기로 전파하는 차수는 0, ±1이며 각도 ±36.6°는 +x 법선 기준입니다. 오른쪽 반복 배열은 방향 설명용이며 별도 유한 8개 격자의 계산 배치와 구분합니다.</figcaption>
</figure>

<!-- concept-illustration:part-06:end -->

<h3 id="방향은-주기와-파장으로-정한다">방향은 주기와 파장으로 정한다</h3>

<p>수직 입사한 빛이 공기로 나갈 때, 주기 Λ는 가로 방향 파수를 차수 m마다 다르게 만듭니다.</p>

\[\sin\theta_m=m\lambda/\Lambda\]

<p>전파하려면 $\lvert m\rvert\lambda/\Lambda&lt;1$이어야 합니다. 주기 2.6 µm와 파장 1.55 µm에서는 m = 0, ±1만 전파하고, ±1차 각도는 법선에서 ±36.6°입니다. 이 식은 <strong>갈 수 있는 방향</strong>을 알려주며 각 방향의 power는 알려주지 않습니다.</p>

<h3 id="한-주기로-효율을-구하고-전체-합을-확인한다">한 주기로 효율을 구하고 전체 합을 확인한다</h3>

<p>무한히 반복되는 격자는 막대 하나와 y 방향 주기 경계로 계산합니다. PML은 빛이 진행하는 x 방향에만 둡니다. <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>로 각 차수의 복소 진폭을 분해한 뒤 입사 flux로 정규화합니다.</p>

\[T_m=\lvert a_m\rvert^2/P_{\mathrm{in}},\qquad \sum_mT_m=T_{\mathrm{total}},\qquad T_{\mathrm{total}}+R\approx1\]

<p>주기 1.2 µm에서는 0차만 전파합니다. 이때 duty cycle(막대 폭/주기)을 바꾸면 빔 개수보다 투과 진폭과 위상이 달라집니다. 유리의 낮은 굴절률 대비 때문에 높이 0.9 µm에서도 위상 변화는 한 바퀴에 못 미칩니다.</p>

<aside class="lesson-note">
  <p><strong>한 주기 실험과 유한 격자를 구분하세요.</strong> 수치는 2D Ez, 수직 입사, 손실 없는 유리 n = 1.5의 한 주파수 결과입니다. 한 주기 셀의 정확한 회절 각도와 유한 8개 격자의 넓은 빔 피크는 같은 종류의 관측값이 아닙니다.</p>
</aside>

<details>
  <summary>기호·설계 가정과 예측표 자세히 보기</summary>

  <p>주기 Λ의 구조는 평면파에 가로 방향 운동량 2πm/Λ를 더하거나 뺀다. 공기 중에서 전파하려면 가로 파수가 k₀ = 2π/λ보다 작아야 하므로 |m|λ/Λ &lt; 1인 차수만 살아남는다. Λ = 2.6 µm, λ = 1.55 µm면 λ/Λ = 0.60이라 m = 0, ±1까지이고 ±1차는 ±36.6°로 간다. Λ = 1.2 µm면 λ/Λ = 1.29 &gt; 1이라 0차만 남는다. 이때 격자는 “회절”하지 않고 하나의 유효 매질처럼 투과 진폭과 위상만 바꾼다.</p>

\[\sin\theta_m=\frac{m\lambda}{\Lambda},\qquad
T_m=\frac{\|a_m\|^2}{P_{\mathrm{in}}},\qquad \sum_m T_m = T_{\mathrm{total}},\qquad T_{\mathrm{total}}+R=1\]

\[\frac{\Delta\phi_{\max}}{2\pi}\;\lesssim\;\frac{(n-1)\,h}{\lambda}\]

  <p>두 번째 식은 duty cycle로 돌릴 수 있는 위상의 거친 상한이다. 높이 h의 막대를 지나며 쌓이는 위상차의 최대는 막대가 유리로 꽉 찼을 때와 비었을 때의 차, (n − 1)h/λ 바퀴다.</p>

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Λ, h, duty</td>
        <td>주기, 막대 높이, 막대 폭/주기</td>
        <td><code class="language-plaintext highlighter-rouge">gp</code>, <code class="language-plaintext highlighter-rouge">gh</code>, <code class="language-plaintext highlighter-rouge">gdc</code></td>
      </tr>
      <tr>
        <td>$a_m$</td>
        <td>m차 평면파의 복소 진폭 (<code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>)</td>
        <td><code class="language-plaintext highlighter-rouge">amp[m]</code></td>
      </tr>
      <tr>
        <td>$P_{\mathrm{in}}$</td>
        <td>reference run(유리로 꽉 찬 셀)의 투과 flux</td>
        <td><code class="language-plaintext highlighter-rouge">P_in</code></td>
      </tr>
      <tr>
        <td>$T_m$, R</td>
        <td>m차 효율, 반사율(입사장 뺀 flux)</td>
        <td><code class="language-plaintext highlighter-rouge">T_m[m]</code>, <code class="language-plaintext highlighter-rouge">R</code></td>
      </tr>
      <tr>
        <td>$k_y/2\pi$</td>
        <td>far cut 공간 FFT의 주파수 (cycles/µm)</td>
        <td><code class="language-plaintext highlighter-rouge">ky</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 2D, Ez 편광, 수직 입사, 손실 없는 유리(n 1.5). 격자는 유리 기판 위의 유리 막대. 유한 격자의 각도는 FFT 분해능 1/(cut 길이) ≈ 0.037 cycles/µm(±1.8°)로 제한된다.</p>

  <h3 id="section">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>2.6 µm 주기의 전파 차수</td>
        <td>m = 0, ±1 세 개</td>
        <td>λ/Λ = 0.60</td>
      </tr>
      <tr>
        <td>±1차 각도</td>
        <td>±36.6°</td>
        <td>asin(0.60)</td>
      </tr>
      <tr>
        <td>T₊₁ = T₋₁</td>
        <td>같음</td>
        <td>수직 입사 + 대칭 막대</td>
      </tr>
      <tr>
        <td>ΣT_m과 T_total, T + R</td>
        <td>같음, 1</td>
        <td>차수 분해 완비, 손실 없음</td>
      </tr>
      <tr>
        <td>1.2 µm 주기의 T_total − T₀</td>
        <td>0</td>
        <td>0차만 전파</td>
      </tr>
      <tr>
        <td>duty cycle 위상 span (h 0.35 / 0.9 µm)</td>
        <td>0.11 / 0.29 × 2π 이하</td>
        <td>(n − 1)h/λ</td>
      </tr>
      <tr>
        <td>유한 격자 FFT 피크</td>
        <td>0.385 cycles/µm (= 1/Λ)</td>
        <td>격자 방정식</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: ΣT_m이 T_total과 1%p 이상 다르면 차수 누락이나 DiffractedPlanewave 설정 오류. T + R이 1에서 1% 이상 벗어나면 reference run이 잘못됐다.</p>

</details>

<h2 id="run">4. 직접 실행 · 변수 하나만 바꾸기</h2>

<h3 id="한-번만-바꿔보기-회절-주기">한 번만 바꿔보기: 회절 주기</h3>

<ol>
  <li>전체 코드와 <code class="language-plaintext highlighter-rouge">blogfig.py</code>가 있는 <code class="language-plaintext highlighter-rouge">code/</code> 폴더에서 <code class="language-plaintext highlighter-rouge">python binary_grating.py</code>를 실행하고 기준 <code class="language-plaintext highlighter-rouge">result.json</code>을 보관합니다.</li>
  <li><code class="language-plaintext highlighter-rouge">GP_A, GH_A, GDC_A = 2.6, 0.5, 0.5</code>에서 <strong>첫 값만 3.5로</strong> 바꿉니다. 높이·duty cycle·파장은 그대로 둡니다.</li>
  <li>다시 실행해 <code class="language-plaintext highlighter-rouge">orders_propagating</code>의 차수 목록, 각 차수의 <code class="language-plaintext highlighter-rouge">T_m</code>, 그 합과 <code class="language-plaintext highlighter-rouge">T_total</code>을 비교합니다.</li>
</ol>

<p>방정식은 ±2차도 전파할 것으로 예측합니다. 새 차수에 얼마가 갈지는 계산으로 확인해야 합니다. 아래 측정 효율은 원래 2.6 µm 주기의 값이며, <strong>3.5 µm의 효율은 새 실험 결과로 채워야 합니다</strong>. B 실험의 <code class="language-plaintext highlighter-rouge">GP_B = 1.2</code>는 그대로 유지합니다.</p>

<details>
  <summary>계산 배치·광원·파라미터 보기</summary>

  <figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/06/01_layout.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/06/01_layout.png" alt="주기 2.6 µm 격자의 유리 기판, 막대, 광원, flux monitor와 x 방향 PML" loading="lazy" />
  </a>
  <figcaption>실험 A의 한 주기 셀(2.6 µm 높이). 왼쪽 검은 블록 = 유리 기판(PML 관통), 가운데 작은 블록 = 막대(높이 0.5, 폭 1.3 µm), 빨간 선 = 유리 안의 평면파 source, 파란 선 = 반사 monitor(유리)와 투과 monitor(공기), 녹색 빗금 = x 방향 PML. y 방향은 PML이 없고 `k_point`로 주기 경계다. 보라 × = 종료 감시점. 동그라미 숫자는 §4의 단계 번호다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>주기 Λ (A / B)</td>
        <td>2.6 / 1.2 µm</td>
        <td>A: m = 0, ±1만 전파하도록 공식 10 µm에서 축소. B: 0차만</td>
        <td>Λ ≥ 3.1 µm이면 ±2차도 생긴다</td>
      </tr>
      <tr>
        <td>막대 h, duty (A)</td>
        <td>0.5 µm, 0.5</td>
        <td>공식 예제 값</td>
        <td>효율 배분이 바뀐다 (§7)</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">fwidth</code></td>
        <td>0.1 fcen</td>
        <td>좁은 대역. 차수 분해는 한 주파수에서</td>
        <td>넓히면 차수별 스펙트럼을 얻을 수 있다</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">RESOLUTION</code></td>
        <td>25 (수렴성 50)</td>
        <td>유리 안 파장 1.03 µm → 26 px, 막대 12 px</td>
        <td>50에서 소수 셋째 자리가 움직인다</td>
      </tr>
      <tr>
        <td>source</td>
        <td>유리 안, 셀 전체 폭</td>
        <td>주기 셀에서는 폭 = 주기면 평면파</td>
        <td>—</td>
      </tr>
      <tr>
        <td>reference run</td>
        <td>셀 전체가 유리</td>
        <td>공식 예제 방식. P_in은 유리 안 입사 flux</td>
        <td>공기로 채우면 계면 반사가 분모에 들어간다</td>
      </tr>
      <tr>
        <td>유한 격자</td>
        <td>ridge 8개, 공기 10 µm, 전면 PML</td>
        <td>빔이 분리될 거리. FFT cut은 막대 뒤 8 µm</td>
        <td>ridge 수가 적으면 빔이 넓어진다</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/06/00_source.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/06/00_source.png" alt="격자 실험의 좁은 대역 가우시안 광원 시간 파형과 스펙트럼" loading="lazy" />
  </a>
  <figcaption>source 파형과 스펙트럼. width 15.5, t0 = 77.5. 대역이 좁아 flux·차수 분해는 fcen 한 점이다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 강의 week 7은 1.2 µm 주기 하나로 duty cycle sweep을 하고 band 1 mode coefficient를 0차의 대리로 쓴다. 이 글은 공식 예제의 회절 주기(2.6 µm)에서 <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>로 세 차수를 직접 분해하고, 수지 검산과 유한 격자 실험을 더했다. duty cycle sweep의 수치(위상 span 0.089 × 2π)는 강의와 같다.</p>

</details>

<details>
  <summary>코드 단계별 설명 보기</summary>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
실험 A·B는 같은 함수 <code class="language-plaintext highlighter-rouge">run_periodic</code>로, 실험 C는 별도의 유한 셀로 돈다.</p>
  </blockquote>

  <h3 id="section-1">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">wl</span> <span class="o">=</span> <span class="mf">1.55</span>
<span class="n">fcen</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">wl</span>
<span class="n">fwidth</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">fcen</span>           <span class="c1"># narrow band: single-frequency order decomposition
</span><span class="n">n_glass</span> <span class="o">=</span> <span class="mf">1.5</span>
<span class="n">glass</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">n_glass</span><span class="p">)</span>
<span class="n">DPML</span><span class="p">,</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">DPAD</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.0</span>

<span class="n">GP_A</span><span class="p">,</span> <span class="n">GH_A</span><span class="p">,</span> <span class="n">GDC_A</span> <span class="o">=</span> <span class="mf">2.6</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span>       <span class="c1"># A: diffracting period (lambda / GP = 0.60 -&gt; m = 0, +-1 only)
</span><span class="n">GP_B</span> <span class="o">=</span> <span class="mf">1.2</span>                               <span class="c1"># B: subwavelength period (lambda / GP = 1.29 -&gt; m = 0 only)
</span>
<span class="k">def</span> <span class="nf">orders_propagating</span><span class="p">(</span><span class="n">gp</span><span class="p">):</span>
    <span class="s">"""Grating equation at normal incidence: sin(theta_m) = m * wl / gp (into air)."""</span>
    <span class="n">m_max</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">floor</span><span class="p">(</span><span class="n">gp</span> <span class="o">/</span> <span class="n">wl</span><span class="p">))</span>
    <span class="k">return</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">m</span> <span class="o">*</span> <span class="n">wl</span> <span class="o">/</span> <span class="n">gp</span><span class="p">)))</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="n">m_max</span><span class="p">,</span> <span class="n">m_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 파장, 유리, 기판·공기 두께, 두 주기, 그리고 격자 방정식으로 전파 차수 목록을 미리 만든다.</li>
    <li><strong>왜</strong>: 어떤 차수를 분해할지는 시뮬레이션이 아니라 방정식이 정한다. 전파하지 않는 차수를 <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>에 넣으면 소멸파라 의미 없는 수가 나온다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">m_max</code>를 잘못 세어 ±2차를 넣으면 그 진폭은 소멸파 성분이라 T_m 합이 T_total을 넘거나 들쭉날쭉해진다.</li>
  </ul>

  <h3 id="section-2">② 재료와 구조 — 무엇이 어디에 있는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">grating_geometry</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">glass</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span>
                     <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="mi">0</span><span class="p">)),</span>          <span class="c1"># substrate through the PML
</span>            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">glass</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span> <span class="o">*</span> <span class="n">gp</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span>
                     <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">gh</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>      <span class="c1"># the ridge, width gdc * gp
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 왼쪽 PML을 관통하는 유리 기판과, 그 위의 막대 하나. 막대 폭이 duty × 주기다.</li>
    <li><strong>왜</strong>: 주기 셀에서는 막대 하나가 곧 무한 격자다. 기판은 PML을 관통해야 기판 뒷면 반사가 없다.</li>
    <li><strong>틀리면</strong>: 기판을 PML 앞에서 끊으면 유리·공기 계면이 하나 더 생겨 R에 4%가 추가된다.</li>
  </ul>

  <h3 id="source----">③ Source — 빛을 어떻게 넣는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">plane_wave</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">sy</span><span class="p">,</span> <span class="n">fw</span><span class="o">=</span><span class="n">fwidth</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                      <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DSUB</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sy</span><span class="p">))]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 유리 안에서 셀 전체 폭(= 한 주기)에 걸친 선원. +x로 가는 평면파다.</li>
    <li><strong>왜</strong>: 주기 경계 셀에서 셀 폭 전체의 선원은 그 자체로 무한 평면파다. 03편처럼 <code class="language-plaintext highlighter-rouge">is_integrated</code>가 필요 없다. y에는 PML이 없기 때문이다.</li>
    <li><strong>틀리면</strong>: source를 공기 쪽에 두면 “유리 안 입사 flux” 정규화가 맞지 않는다.</li>
  </ul>

  <h3 id="simulation-----pml">④ Simulation과 경계 — 계산 상자와 PML</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span>
                    <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">)],</span>   <span class="c1"># PML only along the propagation axis
</span>                    <span class="n">geometry</span><span class="o">=</span><span class="p">[]</span> <span class="k">if</span> <span class="n">empty</span> <span class="k">else</span> <span class="n">grating_geometry</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">),</span>
                    <span class="n">default_material</span><span class="o">=</span><span class="n">glass</span> <span class="k">if</span> <span class="n">empty</span> <span class="k">else</span> <span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">,</span>     <span class="c1"># reference: glass everywhere
</span>                    <span class="n">sources</span><span class="o">=</span><span class="n">plane_wave</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">),</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())</span>  <span class="c1"># Bloch-periodic in y with k = 0
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 높이가 한 주기뿐인 셀. PML은 x에만, y는 <code class="language-plaintext highlighter-rouge">k_point=(0,0,0)</code>의 Bloch 주기 경계.</li>
    <li><strong>왜</strong>: 수직 입사면 Bloch 위상이 0이라 <code class="language-plaintext highlighter-rouge">k_point</code>가 영벡터다. reference run은 셀 전체를 유리로 채워 계면 없는 입사 flux를 잰다(공식 예제 방식).</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">k_point</code>를 빼면 y 경계가 반사벽이 되어 격자가 아니라 도파로를 계산한다. PML을 y에도 두면 주기성이 깨진다.</li>
  </ul>

  <h3 id="monitor---">⑤ Monitor — 무엇을 재는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">refl</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.8</span> <span class="o">*</span> <span class="n">DSUB</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">gp</span><span class="p">)))</span>
<span class="n">tran</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPAD</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">gp</span><span class="p">)))</span>
<span class="p">...</span>
<span class="n">sim</span><span class="p">.</span><span class="n">load_minus_flux_data</span><span class="p">(</span><span class="n">refl</span><span class="p">,</span> <span class="n">refl_data</span><span class="p">)</span>     <span class="c1"># reflection only (03편)
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 유리 안의 반사 monitor(source 하류)와 공기 쪽의 투과 monitor. 둘 다 셀 폭 전체.</li>
    <li><strong>왜</strong>: 투과 monitor의 flux는 모든 차수의 합이고, 같은 monitor에서 <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>로 차수를 나눈다. 반사 monitor는 03편 방식으로 입사장을 뺀다.</li>
    <li><strong>틀리면</strong>: 투과 monitor를 막대에 너무 붙이면 소멸파 차수가 섞여 차수 합이 flux와 어긋난다. 막대에서 한 파장 이상 띄운다.</li>
  </ul>

  <h3 id="section-3">⑥ 실행과 종료 조건 — 언제 멈추는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPAD</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 투과 monitor 위치의 Ez가 10⁻⁶으로 감쇠할 때까지.</li>
    <li><strong>왜</strong>: 좁은 대역이라 펄스가 길다(width 15.5). 꼬리까지 monitor를 지나야 DFT가 정확하다.</li>
    <li><strong>틀리면</strong>: 공식 예제처럼 <code class="language-plaintext highlighter-rouge">until_after_sources=100</code> 고정 시간을 쓰면 다른 주기·높이에서 부족할 수 있다.</li>
  </ul>

  <h3 id="section-4">⑦ 후처리 — 숫자로 바꾸기</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">amp</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">tran</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">DiffractedPlanewave</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
       <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">orders</span><span class="p">}</span>                       <span class="c1"># one order per call: (0, m, 0) along the periodic axis y, s-pol (Ez)
</span><span class="n">T_m</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="nb">abs</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">P_in</span> <span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">amp</span><span class="p">.</span><span class="n">items</span><span class="p">()}</span>
<span class="n">phase_m</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">amp</span><span class="p">.</span><span class="n">items</span><span class="p">()}</span>
<span class="n">T_total</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">tran</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">P_in</span>
<span class="n">R</span> <span class="o">=</span> <span class="o">-</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">refl</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">P_in</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 차수 m의 평면파 진폭 a_m을 하나씩 구해 |a_m|²/P_in을 효율로, 위각을 위상으로 쓴다.</li>
    <li><strong>왜</strong>: <code class="language-plaintext highlighter-rouge">DiffractedPlanewave((0, m, 0), axis, s, p)</code>는 “주기 방향 y로 m번째 차수, s 편광(Ez)”이라는 하나의 평면파 모드다. <code class="language-plaintext highlighter-rouge">get_eigenmode_coefficients</code>는 이 객체를 한 번에 하나만 받는다. 04편의 band 번호 대신 차수를 직접 지정하는 셈이다.</li>
    <li><strong>틀리면</strong>: 리스트로 여러 <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>를 넘기면 <code class="language-plaintext highlighter-rouge">TypeError</code>가 난다(처음 실행에서 그랬다). <code class="language-plaintext highlighter-rouge">axis</code>를 x로 주면 평면 정의가 바뀌어 s·p가 뒤집힌다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: 위상 sweep은 <code class="language-plaintext highlighter-rouge">np.unwrap</code>으로 잇는다. 인접 표본의 위상차가 π보다 작을 때만 옳으므로 duty cycle을 촘촘히(9점) 잡는다. 이 글의 최대 인접 차는 0.33 rad이다.</p>
  </blockquote>

</details>

<h2 id="interpret">5. 해석 · 측정값과 한계를 함께 읽기</h2>

<h3 id="방향-예측과-power-측정을-따로-읽기">방향 예측과 power 측정을 따로 읽기</h3>

<table>
  <thead>
    <tr>
      <th>차수</th>
      <th>공기 중 각도</th>
      <th>입사 power 대비 효율</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>−1</td>
      <td>−36.6°</td>
      <td>0.0884</td>
    </tr>
    <tr>
      <td>0</td>
      <td>0°</td>
      <td>0.7591</td>
    </tr>
    <tr>
      <td>+1</td>
      <td>+36.6°</td>
      <td>0.0884</td>
    </tr>
  </tbody>
</table>

<p>차수 합은 0.9358로 전체 투과 flux 0.9358과 맞고, R = 0.0635를 더하면 0.9994입니다. 대칭 구조·수직 입사이므로 ±1차가 같습니다. 해상도 50에서는 T₀ = 0.7597, T±1 = 0.0881로 바뀝니다.</p>

<p>주기 1.2 µm의 duty sweep은 높이 0.35/0.9 µm에서 각각 <strong>0.089/0.229 × 2π</strong>의 위상 범위를 줍니다. 높이가 커져도 여기서는 2π 전체를 덮지 못해 다음 편의 phase library 설계에 한계가 있습니다.</p>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/06/02_orders.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/06/02_orders.png" alt="0차와 ±1차의 측정 효율 및 차수 합과 전체 flux 비교" loading="lazy" />
  </a>
  <figcaption>세 전파 차수의 효율과 검산. m = 0이 0.759, ±1차가 0.088씩. 세 차수의 합 0.936은 투과 monitor의 flux와 같고, 반사 0.064를 더하면 0.999다.</figcaption>
</figure>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/06/03_duty_sweep.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/06/03_duty_sweep.png" alt="두 막대 높이에서 duty cycle에 따른 0차 투과율과 위상 변화" loading="lazy" />
  </a>
  <figcaption>왼쪽: 0차 투과 T₀. 두 높이 모두 0.83~0.97 사이에서 비단조로 움직인다. 오른쪽: 0차의 위상(duty 0.1 기준, 2π 단위). h = 0.35 µm는 0.09 바퀴, 0.9 µm는 0.23 바퀴를 돈다. 빨간 선이 phase library가 필요로 하는 한 바퀴다.</figcaption>
</figure>

<aside class="lesson-note">
  <p><strong>유한 격자의 각도에는 분해능이 있습니다.</strong> FFT 피크 0.372 cycles/µm(35.2°)와 방정식의 0.385 cycles/µm(36.6°)는 cut 길이가 정하는 약 ±0.037 cycles/µm, ±1.8° 범위 안에서 비교합니다. 이 결과만으로 1° 이하의 각도 정확도, 비스듬한 입사·다른 편광·파장 스펙트럼까지 검증했다고 볼 수 없습니다.</p>
</aside>

<details>
  <summary>전체 측정표·예측 비교·수렴성 기록 보기</summary>

  <h3 id="a-26-m---">A. 2.6 µm 주기: 차수별 효율</h3>

  <table>
    <thead>
      <tr>
        <th>양</th>
        <th>값 (res 25)</th>
        <th>값 (res 50)</th>
        <th>10_sources 원본 (res 50)</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>T₀</td>
        <td>0.7591</td>
        <td>0.7597</td>
        <td>0.7597</td>
      </tr>
      <tr>
        <td>T₊₁ = T₋₁</td>
        <td>0.0884</td>
        <td>0.0881</td>
        <td>0.0881</td>
      </tr>
      <tr>
        <td>ΣT_m</td>
        <td>0.9358</td>
        <td>—</td>
        <td>0.9359</td>
      </tr>
      <tr>
        <td>T_total (flux)</td>
        <td>0.9358</td>
        <td>—</td>
        <td>0.9359</td>
      </tr>
      <tr>
        <td>R</td>
        <td>0.0635</td>
        <td>0.0639</td>
        <td>0.0639</td>
      </tr>
      <tr>
        <td>T + R</td>
        <td>0.9994</td>
        <td>0.9998</td>
        <td>0.9998</td>
      </tr>
    </tbody>
  </table>

  <h3 id="b-12-m--duty-cycle---">B. 1.2 µm 주기: duty cycle이 만드는 진폭과 위상</h3>

  <table>
    <thead>
      <tr>
        <th>높이 h</th>
        <th>위상 span / 2π</th>
        <th>어림 (n − 1)h/λ</th>
        <th>T₀ 범위</th>
        <th>max |T_total − T₀|</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0.35 µm</td>
        <td>0.089</td>
        <td>0.113</td>
        <td>0.83–0.97</td>
        <td>3 × 10⁻⁶</td>
      </tr>
      <tr>
        <td>0.90 µm</td>
        <td>0.229</td>
        <td>0.290</td>
        <td>0.85–0.95</td>
        <td>3 × 10⁻⁶</td>
      </tr>
    </tbody>
  </table>

  <h3 id="c----">C. 유한 격자: 빔과 각도</h3>

  <h3 id="section-5">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>전파 차수</td>
        <td>m = 0, ±1</td>
        <td>세 차수의 합 = flux</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>T₊₁ = T₋₁</td>
        <td>같음</td>
        <td>0.0884 = 0.0884</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>ΣT_m = T_total, T + R</td>
        <td>같음, 1</td>
        <td>0.9358 = 0.9358, 0.9994</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>1.2 µm의 T_total − T₀</td>
        <td>0</td>
        <td>3 × 10⁻⁶</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>위상 span (0.35 / 0.9 µm)</td>
        <td>≤ 0.11 / 0.29</td>
        <td>0.089 / 0.229</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>FFT 피크</td>
        <td>0.385 cycles/µm</td>
        <td>0.372 (±0.037 분해능)</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>모두 맞았다. 위상 span은 어림의 79%다. 막대가 주기를 다 채우지 못하므로 유효 굴절률 차가 (n − 1)보다 작기 때문이고, 어림이 상한이라는 뜻이다. 높이를 2.6배 키워도 0.23바퀴다. 07편의 phase library가 유리 대신 Si를 쓰는 이유가 여기 있다.</p>

  <h3 id="section-6">수렴성</h3>

  <table>
    <thead>
      <tr>
        <th>resolution</th>
        <th>T₀</th>
        <th>T₊₁</th>
        <th>R</th>
        <th>T + R</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>25</td>
        <td>0.7591</td>
        <td>0.0884</td>
        <td>0.0635</td>
        <td>0.9994</td>
      </tr>
      <tr>
        <td>50</td>
        <td>0.7597</td>
        <td>0.0881</td>
        <td>0.0639</td>
        <td>0.9998</td>
      </tr>
    </tbody>
  </table>

  <p>해상도를 2배 올려도 효율은 셋째 자리에서만 움직인다. 막대 높이 0.5 µm가 res 25에서 12 px라 충분하다.</p>

  <h3 id="section-7">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: 이 격자에서 수직 입사 Ez 편광의 세 차수 효율은 0.76 / 0.088 / 0.088이고 수지가 닫힌다. subwavelength 유리 격자는 duty cycle로 위상을 (n − 1)h/λ 바퀴 이하만 돌린다.</li>
    <li>할 수 없는 것: 유한 격자의 각도를 1° 안으로. FFT cut 길이가 ±1.8° 분해능을 정한다. 비스듬한 입사(Bloch 위상이 0이 아님)와 p 편광. 효율의 파장 의존성(한 주파수만 계산했다).</li>
  </ul>

</details>

<details>
  <summary>증상별 점검표 보기</summary>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">TypeError ... DiffractedPlanewave</code></td>
        <td>여러 차수를 리스트로 넘김</td>
        <td>차수마다 <code class="language-plaintext highlighter-rouge">get_eigenmode_coefficients</code>를 따로 호출</td>
      </tr>
      <tr>
        <td>차수 합이 flux보다 큼</td>
        <td>전파하지 않는 차수(소멸파)를 포함</td>
        <td>격자 방정식으로 |m|λ/Λ &lt; 1인 것만</td>
      </tr>
      <tr>
        <td>격자가 도파로처럼 동작</td>
        <td><code class="language-plaintext highlighter-rouge">k_point</code> 누락으로 y 경계가 반사벽</td>
        <td><code class="language-plaintext highlighter-rouge">k_point=mp.Vector3()</code></td>
      </tr>
      <tr>
        <td>R이 4%p 큼</td>
        <td>기판이 PML 전에 끊김</td>
        <td>기판 블록을 PML 관통</td>
      </tr>
      <tr>
        <td>위상 곡선이 톱니</td>
        <td>unwrap 실패(표본 간격이 넓음)</td>
        <td>duty cycle 점을 촘촘히</td>
      </tr>
      <tr>
        <td>유한 격자 FFT 피크가 넓음</td>
        <td>cut이 짧거나 ridge 수가 적음</td>
        <td>cut 길이·ridge 수 늘리기</td>
      </tr>
    </tbody>
  </table>

</details>

<h2 id="check">6. 확인 · 두 질문에 답해보기</h2>

<h3 id="1-0차만-전파하면-막대가-빛에-아무-영향도-주지-않는-것일까요">1. 0차만 전파하면 막대가 빛에 아무 영향도 주지 않는 것일까요?</h3>

<details>
  <summary>설명 확인하기</summary>

  <p>아닙니다. 멀리 전파하는 방향은 하나여도 0차의 진폭과 위상, 그리고 반사율이 바뀝니다. 이 복소 투과계수의 변화를 활용하는 것이 phase library의 출발점입니다.</p>

</details>

<h3 id="2-1차-각도는-맞는데-차수-합이-전체-투과-flux와-다르면-무엇을-확인할까요">2. ±1차 각도는 맞는데 차수 합이 전체 투과 flux와 다르면 무엇을 확인할까요?</h3>

<details>
  <summary>설명 확인하기</summary>

  <p>전파하는 차수를 빠뜨렸거나 소멸 차수를 넣지 않았는지, DiffractedPlanewave의 주기 방향·편광 설정과 monitor 위치가 맞는지 확인합니다. 각도 방정식이 맞아도 효율 분해의 검산은 별도로 필요합니다.</p>

</details>

<h2 id="reference">7. 참고 · 전체 코드와 원본 기록</h2>

<p>아래 전체 프로그램은 원본 그대로입니다. 실행 환경과 결과 기록을 함께 확인하세요.</p>

<details>
<summary>binary_grating.py (클릭해서 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 06 - Binary grating and diffraction orders.

  A. One period of a glass binary grating (period 2.6 um &gt; wavelength): the grating equation says only
     m = 0, +-1 propagate in air, at +-36.6 deg. DiffractedPlanewave gives the power in each order;
     checks: sum of orders = total transmitted flux, T + R = 1.  (official binary_grating.py, period reduced)
  B. A subwavelength period (1.2 um): only m = 0 propagates. Sweep the duty cycle and record the
     transmitted amplitude AND phase of the zeroth order, for two ridge heights. This curve is the
     prototype of the meta-atom phase library of post 07; the phase span scales like dn * h / lambda.
  C. A finite grating (8 ridges) with PML on all sides: the three beams become visible; the beam angle
     is read from the spatial FFT of the scattered field on a far cut and compared with the equation.
  D. GIF of C in time.

Run:  python binary_grating.py           (~5 min on one core)
Out:  00_source.png, 01_layout.png, 02_orders.png, 03_duty_sweep.png, 04_finite.png,
      05_anim_finite.gif, result.json   (-&gt; ../assets/06/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">bar_figure</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)),</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"06"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>

<span class="c1"># ---------------------------------------------------------------- (1) units &amp; parameters
</span><span class="n">wl</span> <span class="o">=</span> <span class="mf">1.55</span>
<span class="n">fcen</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">wl</span>
<span class="n">fwidth</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">fcen</span>           <span class="c1"># narrow band: single-frequency order decomposition
</span><span class="n">n_glass</span> <span class="o">=</span> <span class="mf">1.5</span>
<span class="n">glass</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">n_glass</span><span class="p">)</span>
<span class="n">DPML</span><span class="p">,</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">DPAD</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.0</span>

<span class="n">GP_A</span><span class="p">,</span> <span class="n">GH_A</span><span class="p">,</span> <span class="n">GDC_A</span> <span class="o">=</span> <span class="mf">2.6</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span>       <span class="c1"># A: diffracting period (lambda / GP = 0.60 -&gt; m = 0, +-1 only)
</span><span class="n">GP_B</span> <span class="o">=</span> <span class="mf">1.2</span>                               <span class="c1"># B: subwavelength period (lambda / GP = 1.29 -&gt; m = 0 only)
</span><span class="n">RESOLUTION</span> <span class="o">=</span> <span class="mi">25</span>


<span class="k">def</span> <span class="nf">orders_propagating</span><span class="p">(</span><span class="n">gp</span><span class="p">):</span>
    <span class="s">"""Grating equation at normal incidence: sin(theta_m) = m * wl / gp (into air)."""</span>
    <span class="n">m_max</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">floor</span><span class="p">(</span><span class="n">gp</span> <span class="o">/</span> <span class="n">wl</span><span class="p">))</span>
    <span class="k">return</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">m</span> <span class="o">*</span> <span class="n">wl</span> <span class="o">/</span> <span class="n">gp</span><span class="p">)))</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="n">m_max</span><span class="p">,</span> <span class="n">m_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span>


<span class="c1"># ---------------------------------------------------------------- (2) geometry: substrate + one ridge per period
</span><span class="k">def</span> <span class="nf">grating_geometry</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">glass</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span>
                     <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="mi">0</span><span class="p">)),</span>          <span class="c1"># substrate through the PML
</span>            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">glass</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span> <span class="o">*</span> <span class="n">gp</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span>
                     <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">gh</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>      <span class="c1"># the ridge, width gdc * gp
</span>

<span class="c1"># ---------------------------------------------------------------- (3) source: plane wave inside the glass, travelling +x
</span><span class="k">def</span> <span class="nf">plane_wave</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">sy</span><span class="p">,</span> <span class="n">fw</span><span class="o">=</span><span class="n">fwidth</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                      <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DSUB</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sy</span><span class="p">))]</span>


<span class="c1"># ---------------------------------------------------------------- (4) one periodic cell: PML in x only, Bloch-periodic in y (k = 0)
</span><span class="k">def</span> <span class="nf">periodic_cell</span><span class="p">(</span><span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RESOLUTION</span><span class="p">,</span> <span class="n">empty</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="n">sx</span> <span class="o">=</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="n">gh</span> <span class="o">+</span> <span class="n">DPAD</span> <span class="o">+</span> <span class="n">DPML</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span>
                        <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">)],</span>
                        <span class="n">geometry</span><span class="o">=</span><span class="p">[]</span> <span class="k">if</span> <span class="n">empty</span> <span class="k">else</span> <span class="n">grating_geometry</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">),</span>
                        <span class="n">default_material</span><span class="o">=</span><span class="n">glass</span> <span class="k">if</span> <span class="n">empty</span> <span class="k">else</span> <span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">,</span>     <span class="c1"># reference: glass everywhere
</span>                        <span class="n">sources</span><span class="o">=</span><span class="n">plane_wave</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">gp</span><span class="p">),</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())</span>
    <span class="c1"># ------------------------------------------------------------ (5) monitors: reflection (in glass), transmission (in air)
</span>    <span class="n">refl</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.8</span> <span class="o">*</span> <span class="n">DSUB</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">gp</span><span class="p">)))</span>
    <span class="n">tran</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPAD</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">gp</span><span class="p">)))</span>
    <span class="k">return</span> <span class="n">sim</span><span class="p">,</span> <span class="n">refl</span><span class="p">,</span> <span class="n">tran</span><span class="p">,</span> <span class="n">sx</span>


<span class="k">def</span> <span class="nf">run_periodic</span><span class="p">(</span><span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">,</span> <span class="n">orders</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RESOLUTION</span><span class="p">,</span> <span class="n">layout</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="s">"""Reference (all glass) then grating. Returns P_in-normalised T_m, T_total, R and the order amplitudes."""</span>
    <span class="n">sim</span><span class="p">,</span> <span class="n">refl</span><span class="p">,</span> <span class="n">tran</span><span class="p">,</span> <span class="n">sx</span> <span class="o">=</span> <span class="n">periodic_cell</span><span class="p">(</span><span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">,</span> <span class="n">resolution</span><span class="p">,</span> <span class="n">empty</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPAD</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>  <span class="c1"># (6)
</span>    <span class="n">P_in</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">tran</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>                      <span class="c1"># incident power per period (measured in glass)
</span>    <span class="n">refl_data</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_flux_data</span><span class="p">(</span><span class="n">refl</span><span class="p">)</span>

    <span class="n">sim</span><span class="p">,</span> <span class="n">refl</span><span class="p">,</span> <span class="n">tran</span><span class="p">,</span> <span class="n">sx</span> <span class="o">=</span> <span class="n">periodic_cell</span><span class="p">(</span><span class="n">gp</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="n">gdc</span><span class="p">,</span> <span class="n">resolution</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">load_minus_flux_data</span><span class="p">(</span><span class="n">refl</span><span class="p">,</span> <span class="n">refl_data</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">layout</span><span class="p">:</span>
        <span class="n">annotated_layout</span><span class="p">(</span>
            <span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">8.6</span><span class="p">,</span> <span class="mf">4.2</span><span class="p">),</span>
            <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s">"one period: glass substrate + ridge, PML in x only, Bloch-periodic in y (period </span><span class="si">{</span><span class="n">gp</span><span class="si">}</span><span class="s"> um)"</span><span class="p">,</span>
            <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">wl</span><span class="si">}</span><span class="s">  res=</span><span class="si">{</span><span class="n">resolution</span><span class="si">}</span><span class="se">\n</span><span class="s">L=</span><span class="si">{</span><span class="n">gp</span><span class="si">}</span><span class="s"> h=</span><span class="si">{</span><span class="n">gh</span><span class="si">}</span><span class="s"> dc=</span><span class="si">{</span><span class="n">gdc</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>
            <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">1.15</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">2.6</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPAD</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">decay_text_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">1.4</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">),</span>
            <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"glass substrate + ridge (geometry)"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">0.95</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                    <span class="n">Label</span><span class="p">(</span><span class="s">"plane-wave source in the glass"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DSUB</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.6</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">2.3</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.15</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                    <span class="n">Label</span><span class="p">(</span><span class="s">"flux: reflection (glass) / transmission (air)"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPAD</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.2</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.1</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.55</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)],</span>
            <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPAD</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="c1"># ------------------------------------------------------------ (7) orders by DiffractedPlanewave, totals by flux
</span>    <span class="c1"># one DiffractedPlanewave per call: order m along the periodic direction y, s-polarised (Ez)
</span>    <span class="n">amp</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">tran</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">DiffractedPlanewave</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
           <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">orders</span><span class="p">}</span>
    <span class="n">T_m</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">P_in</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">amp</span><span class="p">.</span><span class="n">items</span><span class="p">()}</span>
    <span class="n">phase_m</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">a</span><span class="p">))</span> <span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">amp</span><span class="p">.</span><span class="n">items</span><span class="p">()}</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"T_m"</span><span class="p">:</span> <span class="n">T_m</span><span class="p">,</span> <span class="s">"phase_m"</span><span class="p">:</span> <span class="n">phase_m</span><span class="p">,</span> <span class="s">"T_total"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">tran</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">P_in</span><span class="p">),</span>
            <span class="s">"R"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="o">-</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">refl</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">P_in</span><span class="p">),</span> <span class="s">"P_in"</span><span class="p">:</span> <span class="n">P_in</span><span class="p">}</span>


<span class="n">source_figure</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>

<span class="c1"># ================================================================ A. diffraction orders of the 2.6 um grating
</span><span class="n">angles</span> <span class="o">=</span> <span class="n">orders_propagating</span><span class="p">(</span><span class="n">GP_A</span><span class="p">)</span>
<span class="n">A</span> <span class="o">=</span> <span class="n">run_periodic</span><span class="p">(</span><span class="n">GP_A</span><span class="p">,</span> <span class="n">GH_A</span><span class="p">,</span> <span class="n">GDC_A</span><span class="p">,</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">),</span> <span class="n">layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">sum_orders</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="s">"T_m"</span><span class="p">].</span><span class="n">values</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"A. period </span><span class="si">{</span><span class="n">GP_A</span><span class="si">}</span><span class="s"> um: propagating orders </span><span class="si">{</span><span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">)</span><span class="si">}</span><span class="s"> at "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"m=</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">a</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span> <span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">.</span><span class="n">items</span><span class="p">())))</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"A. T_m = "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"m=</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">t</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">t</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="s">'T_m'</span><span class="p">].</span><span class="n">items</span><span class="p">()))</span> <span class="o">+</span>
      <span class="sa">f</span><span class="s">"; sum = </span><span class="si">{</span><span class="n">sum_orders</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, T_total (flux) = </span><span class="si">{</span><span class="n">A</span><span class="p">[</span><span class="s">'T_total'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, R = </span><span class="si">{</span><span class="n">A</span><span class="p">[</span><span class="s">'R'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, T+R = </span><span class="si">{</span><span class="n">A</span><span class="p">[</span><span class="s">'T_total'</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="s">'R'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">bar_figure</span><span class="p">([</span><span class="sa">f</span><span class="s">"m = </span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="se">\n</span><span class="s">(</span><span class="si">{</span><span class="n">angles</span><span class="p">[</span><span class="n">m</span><span class="p">]</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg)"</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">)]</span> <span class="o">+</span> <span class="p">[</span><span class="s">"sum of orders"</span><span class="p">,</span> <span class="s">"T (flux)"</span><span class="p">,</span> <span class="s">"R"</span><span class="p">,</span> <span class="s">"T + R"</span><span class="p">],</span>
           <span class="p">{</span><span class="s">"fraction of incident power"</span><span class="p">:</span> <span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="s">"T_m"</span><span class="p">][</span><span class="n">m</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">)]</span> <span class="o">+</span> <span class="p">[</span><span class="n">sum_orders</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="s">"T_total"</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="s">"R"</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="s">"T_total"</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="s">"R"</span><span class="p">]]},</span>
           <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_orders.png"</span><span class="p">),</span> <span class="n">ylabel</span><span class="o">=</span><span class="s">"fraction of incident power"</span><span class="p">,</span> <span class="n">reference</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">reference_label</span><span class="o">=</span><span class="s">"lossless: 1"</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span>
<span class="n">convergence</span> <span class="o">=</span> <span class="p">[{</span><span class="s">"resolution"</span><span class="p">:</span> <span class="n">RESOLUTION</span><span class="p">,</span> <span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s">"T_</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">"</span><span class="p">:</span> <span class="n">A</span><span class="p">[</span><span class="s">"T_m"</span><span class="p">][</span><span class="n">m</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">)},</span> <span class="s">"R"</span><span class="p">:</span> <span class="n">A</span><span class="p">[</span><span class="s">"R"</span><span class="p">],</span> <span class="s">"T_plus_R"</span><span class="p">:</span> <span class="n">A</span><span class="p">[</span><span class="s">"T_total"</span><span class="p">]</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="s">"R"</span><span class="p">]}]</span>
<span class="k">for</span> <span class="n">res</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">50</span><span class="p">,):</span>
    <span class="n">Ar</span> <span class="o">=</span> <span class="n">run_periodic</span><span class="p">(</span><span class="n">GP_A</span><span class="p">,</span> <span class="n">GH_A</span><span class="p">,</span> <span class="n">GDC_A</span><span class="p">,</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">)</span>
    <span class="n">convergence</span><span class="p">.</span><span class="n">append</span><span class="p">({</span><span class="s">"resolution"</span><span class="p">:</span> <span class="n">res</span><span class="p">,</span> <span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s">"T_</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">"</span><span class="p">:</span> <span class="n">Ar</span><span class="p">[</span><span class="s">"T_m"</span><span class="p">][</span><span class="n">m</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">)},</span> <span class="s">"R"</span><span class="p">:</span> <span class="n">Ar</span><span class="p">[</span><span class="s">"R"</span><span class="p">],</span> <span class="s">"T_plus_R"</span><span class="p">:</span> <span class="n">Ar</span><span class="p">[</span><span class="s">"T_total"</span><span class="p">]</span> <span class="o">+</span> <span class="n">Ar</span><span class="p">[</span><span class="s">"R"</span><span class="p">]})</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"convergence res=</span><span class="si">{</span><span class="n">res</span><span class="si">}</span><span class="s">: "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"T_</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">=</span><span class="si">{</span><span class="n">Ar</span><span class="p">[</span><span class="s">'T_m'</span><span class="p">][</span><span class="n">m</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">angles</span><span class="p">))</span> <span class="o">+</span> <span class="sa">f</span><span class="s">", R=</span><span class="si">{</span><span class="n">Ar</span><span class="p">[</span><span class="s">'R'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, T+R=</span><span class="si">{</span><span class="n">Ar</span><span class="p">[</span><span class="s">'T_total'</span><span class="p">]</span> <span class="o">+</span> <span class="n">Ar</span><span class="p">[</span><span class="s">'R'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># ================================================================ B. subwavelength period: duty-cycle sweep of the zeroth order
</span><span class="n">duty</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span>
<span class="n">sweep</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">gh</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">0.35</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">):</span>
    <span class="n">rows</span> <span class="o">=</span> <span class="p">[</span><span class="n">run_periodic</span><span class="p">(</span><span class="n">GP_B</span><span class="p">,</span> <span class="n">gh</span><span class="p">,</span> <span class="nb">float</span><span class="p">(</span><span class="n">d</span><span class="p">),</span> <span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">duty</span><span class="p">]</span>
    <span class="n">T0</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">r</span><span class="p">[</span><span class="s">"T_m"</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">])</span>
    <span class="n">ph</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">r</span><span class="p">[</span><span class="s">"phase_m"</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">]))</span>
    <span class="n">ph</span> <span class="o">-=</span> <span class="n">ph</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    <span class="n">step</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">ph</span><span class="p">))))</span>
    <span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"duty"</span><span class="p">:</span> <span class="n">duty</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"T0"</span><span class="p">:</span> <span class="n">T0</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"phase"</span><span class="p">:</span> <span class="n">ph</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"span_over_2pi"</span><span class="p">:</span> <span class="nb">float</span><span class="p">((</span><span class="n">ph</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span> <span class="o">-</span> <span class="n">ph</span><span class="p">.</span><span class="nb">min</span><span class="p">())</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)),</span>
                 <span class="s">"estimate_dn_h_over_wl"</span><span class="p">:</span> <span class="p">(</span><span class="n">n_glass</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">gh</span> <span class="o">/</span> <span class="n">wl</span><span class="p">,</span> <span class="s">"max_step_rad"</span><span class="p">:</span> <span class="n">step</span><span class="p">,</span>
                 <span class="s">"T_total_minus_T0_max"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="s">"T_total"</span><span class="p">]</span> <span class="o">-</span> <span class="n">r</span><span class="p">[</span><span class="s">"T_m"</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">))}</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"B. h=</span><span class="si">{</span><span class="n">gh</span><span class="si">}</span><span class="s">: T0 in [</span><span class="si">{</span><span class="n">T0</span><span class="p">.</span><span class="nb">min</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">, </span><span class="si">{</span><span class="n">T0</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">], phase span = </span><span class="si">{</span><span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">][</span><span class="s">'span_over_2pi'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> x 2pi "</span>
          <span class="sa">f</span><span class="s">"(estimate dn*h/wl = </span><span class="si">{</span><span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">][</span><span class="s">'estimate_dn_h_over_wl'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">), max step </span><span class="si">{</span><span class="n">step</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> rad, max|T_total - T0| = </span><span class="si">{</span><span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">][</span><span class="s">'T_total_minus_T0_max'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mf">3.9</span><span class="p">))</span>
<span class="k">for</span> <span class="n">gh</span><span class="p">,</span> <span class="n">st</span> <span class="ow">in</span> <span class="p">((</span><span class="mf">0.35</span><span class="p">,</span> <span class="s">"o-"</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.9</span><span class="p">,</span> <span class="s">"s--"</span><span class="p">)):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">duty</span><span class="p">,</span> <span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">][</span><span class="s">"T0"</span><span class="p">],</span> <span class="n">st</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"h = </span><span class="si">{</span><span class="n">gh</span><span class="si">}</span><span class="s"> um"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">duty</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">][</span><span class="s">"phase"</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="n">st</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"h = </span><span class="si">{</span><span class="n">gh</span><span class="si">}</span><span class="s"> um  (span </span><span class="si">{</span><span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">][</span><span class="s">'span_over_2pi'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">, estimate </span><span class="si">{</span><span class="n">sweep</span><span class="p">[</span><span class="n">gh</span><span class="p">][</span><span class="s">'estimate_dn_h_over_wl'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"duty cycle (ridge width / period)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"zeroth-order transmission T0"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.05</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"subwavelength period </span><span class="si">{</span><span class="n">GP_B</span><span class="si">}</span><span class="s"> um: amplitude side"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.0</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="mf">0.12</span><span class="p">,</span> <span class="mf">1.02</span><span class="p">,</span> <span class="s">"2 pi (what a phase library needs)"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"duty cycle"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"phase of T0 / 2 pi  (relative to duty 0.1)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.05</span><span class="p">,</span> <span class="mf">1.15</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"phase side: prototype of a phase library"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_duty_sweep.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ================================================================ C. finite grating: the beams, and the angle from a spatial FFT
</span><span class="n">N_RIDGE</span> <span class="o">=</span> <span class="mi">8</span>
<span class="n">RES_C</span> <span class="o">=</span> <span class="mi">15</span>
<span class="n">pad_y</span> <span class="o">=</span> <span class="mf">3.0</span>
<span class="n">sx_c</span> <span class="o">=</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="n">GH_A</span> <span class="o">+</span> <span class="mf">10.0</span> <span class="o">+</span> <span class="n">DPML</span>
<span class="n">sy_c</span> <span class="o">=</span> <span class="n">N_RIDGE</span> <span class="o">*</span> <span class="n">GP_A</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">pad_y</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span>
<span class="n">x_ridge</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx_c</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">GH_A</span>


<span class="k">def</span> <span class="nf">finite_geometry</span><span class="p">(</span><span class="n">with_ridges</span><span class="p">):</span>
    <span class="n">g</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">glass</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx_c</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="mi">0</span><span class="p">))]</span>
    <span class="k">if</span> <span class="n">with_ridges</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_RIDGE</span><span class="p">):</span>
            <span class="n">yc</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span> <span class="o">-</span> <span class="p">(</span><span class="n">N_RIDGE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">GP_A</span>
            <span class="n">g</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">glass</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">GH_A</span><span class="p">,</span> <span class="n">GDC_A</span> <span class="o">*</span> <span class="n">GP_A</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">x_ridge</span><span class="p">,</span> <span class="n">yc</span><span class="p">)))</span>
    <span class="k">return</span> <span class="n">g</span>


<span class="k">def</span> <span class="nf">finite_sim</span><span class="p">(</span><span class="n">with_ridges</span><span class="p">,</span> <span class="n">fw</span><span class="o">=</span><span class="n">fwidth</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES_C</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx_c</span><span class="p">,</span> <span class="n">sy_c</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)],</span>
                         <span class="n">geometry</span><span class="o">=</span><span class="n">finite_geometry</span><span class="p">(</span><span class="n">with_ridges</span><span class="p">),</span>
                         <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw</span><span class="p">,</span> <span class="n">is_integrated</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                                            <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx_c</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DSUB</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sy_c</span><span class="p">))])</span>


<span class="n">nonpml_c</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx_c</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">sy_c</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">))</span>
<span class="n">extent_c</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="p">(</span><span class="n">sx_c</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sx_c</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="n">sy_c</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sy_c</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">]</span>
<span class="n">fields</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">tag</span><span class="p">,</span> <span class="n">ridges</span> <span class="ow">in</span> <span class="p">((</span><span class="s">"flat"</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span> <span class="p">(</span><span class="s">"grating"</span><span class="p">,</span> <span class="bp">True</span><span class="p">)):</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">finite_sim</span><span class="p">(</span><span class="n">ridges</span><span class="p">)</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="n">nonpml_c</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sx_c</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mf">1e-5</span><span class="p">))</span>
    <span class="n">fields</span><span class="p">[</span><span class="n">tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">ridges</span><span class="p">:</span>
        <span class="n">eps_c</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">nonpml_c</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">ez_sc</span> <span class="o">=</span> <span class="n">fields</span><span class="p">[</span><span class="s">"grating"</span><span class="p">]</span> <span class="o">-</span> <span class="n">fields</span><span class="p">[</span><span class="s">"flat"</span><span class="p">]</span>                 <span class="c1"># scattered field: what the ridges added
</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">=</span> <span class="n">ez_sc</span><span class="p">.</span><span class="n">shape</span>
<span class="n">xs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">extent_c</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">extent_c</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">nx</span><span class="p">);</span> <span class="n">ys</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">extent_c</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">extent_c</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">ny</span><span class="p">)</span>
<span class="n">x_cut</span> <span class="o">=</span> <span class="n">x_ridge</span> <span class="o">+</span> <span class="mf">8.0</span>                                      <span class="c1"># far cut, 8 um past the ridges, in homogeneous air
</span><span class="n">line</span> <span class="o">=</span> <span class="n">ez_sc</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmin</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">xs</span> <span class="o">-</span> <span class="n">x_cut</span><span class="p">)),</span> <span class="p">:]</span>
<span class="n">ky</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">fftshift</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">fftfreq</span><span class="p">(</span><span class="n">ny</span><span class="p">,</span> <span class="n">d</span><span class="o">=</span><span class="n">ys</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">ys</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>  <span class="c1"># cycles per um
</span><span class="n">spec</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">fftshift</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">fft</span><span class="p">(</span><span class="n">line</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">hanning</span><span class="p">(</span><span class="n">ny</span><span class="p">))))</span> <span class="o">**</span> <span class="mi">2</span>
<span class="n">spec</span> <span class="o">/=</span> <span class="n">spec</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span>
<span class="n">pos</span> <span class="o">=</span> <span class="n">ky</span> <span class="o">&gt;</span> <span class="mf">0.15</span>
<span class="n">k_peak</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">ky</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">spec</span><span class="p">[</span><span class="n">pos</span><span class="p">])])</span>
<span class="n">theta_meas</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="n">k_peak</span> <span class="o">*</span> <span class="n">wl</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">))))</span>   <span class="c1"># sin(theta) = k_y / k0 = k_peak * wl
</span><span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"C. finite grating (</span><span class="si">{</span><span class="n">N_RIDGE</span><span class="si">}</span><span class="s"> ridges): spatial-FFT peak at </span><span class="si">{</span><span class="n">k_peak</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> cycles/um -&gt; theta = </span><span class="si">{</span><span class="n">theta_meas</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg "</span>
      <span class="sa">f</span><span class="s">"(grating equation: 1/period = </span><span class="si">{</span><span class="mi">1</span><span class="o">/</span><span class="n">GP_A</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> cycles/um -&gt; </span><span class="si">{</span><span class="n">angles</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg)"</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">5.2</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"width_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">1.5</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
<span class="n">im</span> <span class="o">=</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fields</span><span class="p">[</span><span class="s">"grating"</span><span class="p">]).</span><span class="n">T</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">extent_c</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">contour</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">,</span> <span class="n">eps_c</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="p">[</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">eps_c</span><span class="p">.</span><span class="nb">min</span><span class="p">()</span> <span class="o">+</span> <span class="n">eps_c</span><span class="p">.</span><span class="nb">max</span><span class="p">())],</span> <span class="n">colors</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
<span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">angles</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
    <span class="n">L</span> <span class="o">=</span> <span class="mf">9.0</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">([</span><span class="n">x_ridge</span><span class="p">,</span> <span class="n">x_ridge</span> <span class="o">+</span> <span class="n">L</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">))],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">L</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">))],</span> <span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"cyan"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">x_ridge</span> <span class="o">+</span> <span class="n">L</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">))</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">L</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">)),</span> <span class="sa">f</span><span class="s">"m=</span><span class="si">{</span><span class="n">m</span><span class="si">:</span><span class="o">+</span><span class="n">d</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"cyan"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">va</span><span class="o">=</span><span class="s">"center"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="n">x_cut</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.0</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">x_cut</span><span class="p">,</span> <span class="n">extent_c</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">-</span> <span class="mf">0.8</span><span class="p">,</span> <span class="s">"FFT cut"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"|Ez| at 1550 nm, </span><span class="si">{</span><span class="n">N_RIDGE</span><span class="si">}</span><span class="s"> ridges; dashed = grating-equation angles"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">colorbar</span><span class="p">(</span><span class="n">im</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">shrink</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">semilogy</span><span class="p">(</span><span class="n">ky</span><span class="p">,</span> <span class="n">spec</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="n">m</span> <span class="o">/</span> <span class="n">GP_A</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">GP_A</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">,</span> <span class="sa">f</span><span class="s">"+1/period = </span><span class="si">{</span><span class="mi">1</span><span class="o">/</span><span class="n">GP_A</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlim</span><span class="p">(</span><span class="o">-</span><span class="mf">1.2</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mf">1e-4</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"spatial frequency k_y / 2pi [cycles/um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"|FFT(E_scat on the cut)|^2 (norm.)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"peak </span><span class="si">{</span><span class="n">k_peak</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> -&gt; </span><span class="si">{</span><span class="n">theta_meas</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg (equation </span><span class="si">{</span><span class="n">angles</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">"both"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_finite.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ================================================================ D. GIF: the beams forming in time
</span><span class="n">fw_anim</span> <span class="o">=</span> <span class="mf">0.3</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">sim_anim</span> <span class="o">=</span> <span class="n">finite_sim</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span> <span class="n">fw</span><span class="o">=</span><span class="n">fw_anim</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="mi">12</span><span class="p">)</span>
<span class="n">sim_anim</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">eps_anim</span> <span class="o">=</span> <span class="n">sim_anim</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">nonpml_c</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_anim</span><span class="p">,</span> <span class="n">nonpml_c</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="mi">5</span> <span class="o">/</span> <span class="n">fw_anim</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">fw_anim</span><span class="p">,</span> <span class="n">t_end</span><span class="o">=</span><span class="mi">5</span> <span class="o">/</span> <span class="n">fw_anim</span> <span class="o">+</span> <span class="mf">1.5</span> <span class="o">*</span> <span class="n">sx_c</span> <span class="o">+</span> <span class="mi">10</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="n">extent_c</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_anim_finite.gif"</span><span class="p">),</span> <span class="n">eps</span><span class="o">=</span><span class="n">eps_anim</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.2</span><span class="p">,</span> <span class="mf">6.4</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span>
               <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">N_RIDGE</span><span class="si">}</span><span class="s">-ridge grating, plane wave from the left"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>

<span class="k">if</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">():</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"A"</span><span class="p">:</span> <span class="p">{</span><span class="s">"period"</span><span class="p">:</span> <span class="n">GP_A</span><span class="p">,</span> <span class="s">"angles_deg"</span><span class="p">:</span> <span class="n">angles</span><span class="p">,</span> <span class="o">**</span><span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">A</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="p">(</span><span class="s">"T_m"</span><span class="p">,</span> <span class="s">"phase_m"</span><span class="p">,</span> <span class="s">"T_total"</span><span class="p">,</span> <span class="s">"R"</span><span class="p">)},</span> <span class="s">"sum_orders"</span><span class="p">:</span> <span class="n">sum_orders</span><span class="p">},</span>
                   <span class="s">"convergence"</span><span class="p">:</span> <span class="n">convergence</span><span class="p">,</span> <span class="s">"B"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="n">k</span><span class="p">):</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">sweep</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"C"</span><span class="p">:</span> <span class="p">{</span><span class="s">"n_ridges"</span><span class="p">:</span> <span class="n">N_RIDGE</span><span class="p">,</span> <span class="s">"k_peak_cycles_per_um"</span><span class="p">:</span> <span class="n">k_peak</span><span class="p">,</span> <span class="s">"theta_meas_deg"</span><span class="p">:</span> <span class="n">theta_meas</span><span class="p">,</span> <span class="s">"theta_eq_deg"</span><span class="p">:</span> <span class="n">angles</span><span class="p">[</span><span class="mi">1</span><span class="p">]},</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">},</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span></code></pre></figure>

</details>

<details>
  <summary>원본 실행 로그·재현 환경 보기</summary>

  <p>§4의 발췌 코드와 달리 전체 코드에는 유한 격자 실험(C), 그림 저장·GIF 녹화·result.json 기록이 들어 있다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

  <p><strong>실행 결과 (2026-10-23 실행)</strong>:</p>
  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A. period 2.6 um: propagating orders [-1, 0, 1] at m=-1: -36.6 deg, m=0: +0.0 deg, m=1: +36.6 deg
A. T_m = m=-1: 0.0884, m=0: 0.7591, m=1: 0.0884; sum = 0.9358, T_total (flux) = 0.9358, R = 0.0635, T+R = 0.9994
convergence res=50: T_-1=0.0881, T_0=0.7597, T_1=0.0881, R=0.0639, T+R=0.9998
B. h=0.35: T0 in [0.829, 0.969], phase span = 0.089 x 2pi (estimate dn*h/wl = 0.113), max step 0.13 rad, max|T_total - T0| = 2.6e-06
B. h=0.9: T0 in [0.846, 0.950], phase span = 0.229 x 2pi (estimate dn*h/wl = 0.290), max step 0.33 rad, max|T_total - T0| = 2.6e-06
C. finite grating (8 ridges): spatial-FFT peak at 0.372 cycles/um -&gt; theta = 35.2 deg (grating equation: 1/period = 0.385 cycles/um -&gt; 36.6 deg)
</code></pre></div>  </div>

  <p><strong>재현 환경</strong>: meep 1.33.0 · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep</code> · 실행 <code class="language-plaintext highlighter-rouge">python binary_grating.py</code> (약 27 s, 단일 코어)</p>

</details>

<details>
  <summary>응용과 다음 학습 주제 보기</summary>

  <h3 id="section-8">어디에 쓰이는가</h3>

  <p>회절 격자는 분광기, 광섬유 결합기, AR 안경, 홀로그램의 공통 부품이다. 차수별 효율이 그 부품의 성능이다.</p>

  <table>
    <thead>
      <tr>
        <th>응용</th>
        <th>이 글의 어떤 것을 쓰는가</th>
        <th>그 다음에 필요한 것</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>분광기·모노크로미터</td>
        <td>차수별 효율, grating equation</td>
        <td>16편 far field</td>
      </tr>
      <tr>
        <td>grating coupler(광섬유 ↔ 칩)</td>
        <td>차수 하나로 몰기, 각도</td>
        <td>07편 meta-atom</td>
      </tr>
      <tr>
        <td>AR 안경의 도파로 격자, 홀로그램, 회절 광학소자(DOE)</td>
        <td>duty cycle이 만드는 위상</td>
        <td>07편 phase library</td>
      </tr>
      <tr>
        <td>유한한 격자의 빔 각도</td>
        <td>FFT로 잰 회절 각도</td>
        <td>16편</td>
      </tr>
    </tbody>
  </table>

</details>

<ul>
  <li><a href="https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating.py">공식 예제 binary_grating.py</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Mode_Decomposition/#diffraction-spectrum-of-a-binary-grating">튜토리얼: Diffraction Spectrum of a Binary Grating</a></li>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#diffractedplanewave"><code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code> 레퍼런스</a> · <a href="https://meep.readthedocs.io/en/latest/FAQ/#how-do-i-model-a-periodic-structure">Bloch 주기 경계와 <code class="language-plaintext highlighter-rouge">k_point</code></a></li>
  <li>이전 글: <a href="/meep-examples/waveguide-bend-90/">05 · Bent waveguide와 radius trade-off</a> · 다음 글: <a href="/meep-examples/meta-atom/">07 · Metalens의 meta-atom과 phase library</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="grating" /><category term="diffraction" /><category term="periodic" /><category term="phase-library" /><summary type="html"><![CDATA[a glass binary grating under a normally incident plane wave. One period with Bloch-periodic boundaries gives the power in each diffraction order; a subwavelength period gives the amplitude and phase of the only surviving order as the duty cycle changes; a finite 8-ridge grating shows the beams.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/06/04_finite.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/06/04_finite.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 11 · 두 거울 사이의 점광원 — LDOS와 Purcell 인자</title><link href="https://jin-castle.github.io/meep-examples/cavity-ldos/" rel="alternate" type="text/html" title="Meep Example 11 · 두 거울 사이의 점광원 — LDOS와 Purcell 인자" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/cavity-ldos</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/cavity-ldos/"><![CDATA[<h2 id="observe">1. 먼저 보기: 거울은 빛의 양도 바꿀까?</h2>

<p>10편에서는 거울 하나가 빛이 나가는 방향을 바꿨습니다. 이번에는 <strong>같은 쌍극자를 두 거울 사이에 놓았을 때 방출 power가 얼마나 달라지는지</strong> 봅니다. source 위치에서 잰 LDOS를 거울 없는 bulk의 LDOS로 나눈 값이 Purcell 인자입니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/03_purcell.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/03_purcell.png" alt="두 거울 간격에 따른 실제 Purcell 인자와 해석식 및 cylindrical와 3D 결과 비교" /></a>
<figcaption>파트 A의 실제 결과입니다. 가로축은 정규화 두께 t = nL/λ입니다. cutoff 세 점을 제외한 18점의 해석식 대비 오차는 중앙값 0.94%, 최대 3.6%입니다.</figcaption>
</figure>

<p class="lesson-note"><strong>두 실험의 물리량을 구별하세요.</strong> 파트 A는 손실 없는 평면 거울 사이에서 bulk로 정규화한 Purcell 인자를 계산합니다. 파트 B는 구멍이 있는 2D PEC 상자의 raw LDOS와 Q/V 근사를 비교합니다. 파트 B의 숫자를 검증된 3D Purcell 인자로 해석할 수 없습니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/06_anim_planar.gif" data-lightbox=""><img src="/meep-examples/assets/meep/11/06_anim_planar.gif" data-animation-src="/meep-examples/assets/meep/11/06_anim_planar.gif" data-static-src="/meep-examples/assets/meep/11/04_cavity_field.png" alt="두 평면 거울 사이에서 r 방향으로 퍼지는 실제 cylindrical Er 펄스" /></a>
<button type="button" class="animation-toggle" hidden="">애니메이션 정지</button>
<figcaption>파트 A, t = 1.0의 펄스입니다. 두 검은 선이 거울이고 가로는 r, 세로는 z입니다. 읽기 위해 z축을 늘려 그렸으며 실제 비율의 3D 장면은 아닙니다.</figcaption>
</figure>

<h2 id="predict">2. 먼저 예측하기: 거울을 두면 항상 더 밝아질까?</h2>

<fieldset class="prediction">
<legend>같은 source를 두 거울 사이에 넣으면 Purcell 인자는 항상 1보다 클까요?</legend>
<label><input type="radio" name="cavity-prediction" value="always" /> 빛을 가두므로 항상 1보다 크다.</label>
<label><input type="radio" name="cavity-prediction" value="modes" /> 간격과 허용되는 모드에 따라 1보다 작아질 수도 있다.</label>
</fieldset>

<details>
  <summary>예측과 실제 결과 비교하기</summary>

  <p>두 번째입니다. t = 1.0에서 cylindrical 계산은 <strong>0.912</strong>, 3D는 <strong>0.933</strong>, 해석식은 <strong>0.9375</strong>입니다. 모두 1보다 작습니다. 거울은 source가 결합할 수 있는 모드를 바꾸므로 방출을 강화할 수도, 억제할 수도 있습니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기: 같은 source로 두 번 재는 이유</h2>

<p>쌍극자는 자신이 만든 field와 상호작용합니다. 거울에서 돌아온 field가 source 자리의 응답을 바꾸면, 같은 진폭의 전류가 내는 power도 달라집니다. <code>dft_ldos</code>는 source 자리의 field와 전류의 주파수 성분으로 이 응답을 구합니다.</p>

<figure class="lesson-figure">
<svg viewBox="0 0 320 210" role="img" aria-labelledby="cavity-concept-title" xmlns="http://www.w3.org/2000/svg">
<title id="cavity-concept-title">설명용 도식: 같은 source를 거울 없는 bulk와 두 거울 사이에서 계산해 LDOS 비율을 구한다</title>
<rect width="320" height="210" fill="#f5f8fa" />
<g font-family="sans-serif" font-size="16" fill="#0d1b2a">
<text x="26" y="29">① bulk</text><text x="176" y="29">② cavity</text>
<text x="27" y="155">같은 source</text><text x="183" y="155">거울 간격 L</text>
<text x="25" y="193">Purcell 인자 = LDOS② / LDOS①</text>
</g>
<rect x="21" y="42" width="117" height="90" fill="#e7f7fb" stroke="#dce5eb" />
<rect x="176" y="42" width="119" height="90" fill="#e7f7fb" />
<path d="M176 43H295M176 131H295" stroke="#0d1b2a" stroke-width="6" />
<circle cx="79" cy="87" r="7" fill="#0087ad" /><circle cx="235" cy="87" r="7" fill="#0087ad" />
<path d="M56 87H102M212 87H258M56 87l8-5M56 87l8 5M102 87l-8-5M102 87l-8 5M212 87l8-5M212 87l8 5M258 87l-8-5M258 87l-8 5" fill="none" stroke="#0087ad" stroke-width="2" />
</svg>
<figcaption>설명용 도식입니다. 검은 선은 손실 없는 PEC 거울, 청록 점과 가로 화살표는 거울에 평행한 쌍극자입니다. 두 run은 같은 매질과 source 표현을 사용하며, 그림은 실제 field 값이 아닙니다.</figcaption>
</figure>

<p><strong>F_P = LDOS(cavity) / LDOS(bulk)</strong>로 나누면 같은 source·좌표계·격자 정규화의 영향을 비교에서 상쇄할 수 있습니다. cylindrical과 3D는 각각 자신의 bulk run으로 나눠야 합니다.</p>

<p>거울 간격은 매질 안 파장으로 환산한 <strong>t = nL/λ</strong>로 읽습니다. 이 평면 cavity와 in-plane 쌍극자에서는 t가 0.5, 1.5, 2.5를 지날 때 모드가 새로 열리며 해석식이 불연속으로 뜁니다. 이 지점이 cutoff입니다. 유한 격자와 유한 시간으로 계산한 cutoff 값을 매끈한 구간과 같은 오차 통계에 섞지 않습니다.</p>

<p class="lesson-note"><strong>평면 cavity의 조건.</strong> 파장 1 µm, 굴절률 2.4, 손실 없는 매질·PEC 거울입니다. cylindrical은 Er와 m = −1, 3D는 Ex로 in-plane 쌍극자를 표현합니다. 거울 방향 z에는 PML을 두지 않고 옆으로 나가는 파만 흡수합니다. 손실 매질의 점광원 LDOS에 이 절차를 그대로 적용할 수는 없습니다.</p>

<p>다음으로 파트 B에서는 1 × 1 µm의 2D PEC 상자에 폭 w의 구멍을 냅니다. 구멍이 좁을수록 누설이 줄어 Q가 커지고, 공진 근처 LDOS를 재는 데 필요한 시간도 길어집니다. 이 예제는 <strong>2Q/f</strong>를 실행 시간의 기준으로 쓰며, 최대 6000에서 자릅니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/07_anim_metal.gif" data-lightbox=""><img src="/meep-examples/assets/meep/11/07_anim_metal.gif" data-animation-src="/meep-examples/assets/meep/11/07_anim_metal.gif" data-static-src="/meep-examples/assets/meep/11/05_metal_ldos.png" alt="2D PEC 상자 안의 Ez 펄스가 공진하며 폭 0.4 마이크로미터 구멍으로 누설되는 모습" /></a>
<button type="button" class="animation-toggle" hidden="">애니메이션 정지</button>
<figcaption>파트 B, w = 0.4 µm의 실제 펄스입니다. 상자 안에서 field가 진동하며 오른쪽 구멍으로 나갑니다. 이 그림은 평면 cavity의 Purcell sweep과 별도인 2D 실험입니다.</figcaption>
</figure>

<h2 id="run">4. 직접 실행하기: 높은 Q를 더 오래 관찰하기</h2>

<p>Meep 1.33.0 환경에서 저장소의 <code>code/</code> 폴더에 있는 원본과 공통 helper를 사용합니다. 먼저 원본 결과를 보관하세요. 기존 단일 코어 실행은 약 6.6분입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">OMP_NUM_THREADS</span><span class="o">=</span>1 python cavity_ldos.py
</code></pre></div></div>

<p><strong>T_MAX만 6000.0에서 12000.0으로 바꿔</strong> 같은 명령으로 실행합니다. 이것은 파트 B의 실행 시간 상한 한 가지만 바꾸는 실험입니다. 다른 파라미터와 source는 그대로 둡니다.</p>

<p>w = 0.2의 로그에서 <code>T_run</code>, <code>dft_ldos</code>, 스펙트럼 폭으로 구한 Q를 원본과 비교하세요. 더 긴 계산에서 공진 스펙트럼이 어떻게 변하는지 확인합니다. 원본이 요구한 시간은 23915이므로 <strong>12000 역시 그 기준보다 짧습니다.</strong> 새 수치를 수렴한 값으로 단정하지 말고, 원본의 3499.1119와 구별해 기록하세요.</p>

<h2 id="interpret">5. 결과 해석하기: 큰 Q와 믿을 수 있는 LDOS는 다르다</h2>

<table>
  <thead>
    <tr>
      <th>평면 cavity의 비교</th>
      <th>실제 기록</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>cutoff를 제외한 해석식 대비 오차</td>
      <td>중앙값 0.94%, 최대 3.6%</td>
    </tr>
    <tr>
      <td>t = 1.0: CYL / 3D / 해석식</td>
      <td>0.912 / 0.933 / 0.9375</td>
    </tr>
    <tr>
      <td>t = 2.0: CYL / 3D / 해석식</td>
      <td>0.988 / 0.979 / 0.9844</td>
    </tr>
    <tr>
      <td>t = 1.5 cutoff의 CYL 값</td>
      <td>0.507, 아래쪽 해석식 극한 약 0.519에 가까움</td>
    </tr>
  </tbody>
</table>

<p>3D 확인은 t = 1, 2 <strong>두 점뿐</strong>입니다. 이 일치가 cutoff 근처를 포함한 모든 두께와 해상도의 검증은 아닙니다. t = 2.5의 CYL 값 1.172는 아래쪽 0.728과 위쪽 1.320 사이에 있어, 한쪽 계단에 정확히 일치한다고 말할 수 없습니다.</p>

<table>
  <thead>
    <tr>
      <th>2D 상자의 구멍 w</th>
      <th style="text-align: right">Harminv Q</th>
      <th style="text-align: right">시간 기준 2Q/f</th>
      <th style="text-align: right">실행 시간</th>
      <th style="text-align: right">LDOS / (Q/V 기반 추정)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0.2 µm</td>
      <td style="text-align: right">8060</td>
      <td style="text-align: right">23915</td>
      <td style="text-align: right">6000, 상한 도달</td>
      <td style="text-align: right">0.72</td>
    </tr>
    <tr>
      <td>0.3 µm</td>
      <td style="text-align: right">1271</td>
      <td style="text-align: right">3802</td>
      <td style="text-align: right">3802</td>
      <td style="text-align: right">0.89</td>
    </tr>
    <tr>
      <td>0.4 µm</td>
      <td style="text-align: right">189</td>
      <td style="text-align: right">574</td>
      <td style="text-align: right">574</td>
      <td style="text-align: right">0.85</td>
    </tr>
    <tr>
      <td>0.5 µm</td>
      <td style="text-align: right">74</td>
      <td style="text-align: right">230</td>
      <td style="text-align: right">230</td>
      <td style="text-align: right">0.81</td>
    </tr>
  </tbody>
</table>

<p>표의 근사값은 2Q/(πωV)이며, V = a²/4는 <strong>닫힌 상자</strong>의 해석값입니다. 구멍이 있는 상자에는 근사이므로 충분히 실행해도 비가 정확히 1일 필요는 없습니다. w = 0.2에서는 시간까지 부족해 스펙트럼 Q가 5597로 Harminv의 8060보다 작았습니다. 따라서 raw LDOS 3499를 수렴한 값으로 보고하지 않습니다.</p>

<h2 id="check">6. 이해 확인하기</h2>

<ol>
  <li>cavity의 LDOS 하나만 알고 있을 때 “방출이 몇 배 변했다”고 말할 수 없는 이유는 무엇인가요?</li>
  <li>w = 0.2에서 Q가 8060으로 측정되었는데도 LDOS를 수렴한 값으로 보고할 수 없는 이유는 무엇인가요?</li>
</ol>

<details>
  <summary>두 질문의 답 확인하기</summary>

  <ol>
    <li>같은 매질·source·좌표계의 bulk 기준값이 필요합니다. 두 LDOS의 비율이 Purcell 인자이고, raw LDOS 하나에는 정규화 조건이 섞여 있습니다.</li>
    <li>LDOS 실행은 6000에서 잘렸고 시간 기준 2Q/f는 23915입니다. 공진의 긴 시간 응답을 충분히 포함하지 못했으며 스펙트럼 Q도 다릅니다. 큰 Q 자체가 LDOS 수렴을 보증하지 않습니다.</li>
  </ol>

</details>

<h2 id="reference">7. 참고 자료와 전체 코드</h2>

<p>원본의 해석식, 좌표계별 설정, 자세한 측정 표와 실행 기록은 아래에서 확인할 수 있습니다.</p>

<details>
  <summary>English summary</summary>

  <h3 id="tldr-english">TL;DR (English)</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/03_purcell.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/03_purcell.png" alt="두 거울 사이에서 빛의 양은 어떻게 달라질까? — hero 원본 그림" loading="lazy" /></a>
</figure>

  <ul>
    <li><strong>What</strong>: post 10 put one mirror next to a dipole and the pattern changed. Here the dipole sits between two mirrors and the question is the emitted power itself. Meep measures it as the local density of states (LDOS) at the source point with <code class="language-plaintext highlighter-rouge">dft_ldos</code>. Part A: an in-plane dipole in a dielectric slab (n = 2.4) between two lossless metallic mirrors, the Purcell factor F = LDOS(cavity)/LDOS(bulk) versus the normalized thickness t = nL/λ, swept in cylindrical coordinates and checked in 3D. Part B: a dipole in a 2D metal box with one aperture, where the LDOS at resonance is compared with the single-mode estimate 2Q/(πωV).</li>
    <li><strong>Result</strong>: away from the three modal cutoffs the cylindrical sweep matches the analytic curve of Abram et al. with a median error of 0.94% (max 3.6%); at the cutoffs t = 0.5, 1.5, 2.5 the LDOS is discontinuous and FDTD lands on one side of the step. Two full-3D points agree with the cylindrical run to 2.3% / 0.9% (t = 1.0 / 2.0). In the metal box the Harminv Q rises from 74 (w = 0.5) to 8060 (w = 0.2); the directly measured LDOS is 0.81–0.89 of 2Q/(πωV) where the run was long enough, and only 0.72 of it for w = 0.2, whose required run time 2Q/f = 23915 was capped at 6000.</li>
    <li><strong>Takeaway</strong>: a mirror changes not only where light goes but how much is emitted. The Purcell factor is always a ratio of two LDOS runs with the same source. A new cavity mode opens at every half wavelength and the LDOS jumps there. A high-Q LDOS costs a run time of order 2Q/f, and an under-converged LDOS is not a small error but a different number.</li>
    <li><strong>Code</strong>: full script at the bottom, ~6.6 min on one core.</li>
  </ul>

</details>

<details>
  <summary>배경·물리식·파라미터 자세히 보기</summary>

  <h3 id="section">원본 §0 · 이 글에서 배우는 것</h3>

  <ul>
    <li>LDOS가 무엇인가: 단위 쌍극자가 그 자리에서 내는 power. <code class="language-plaintext highlighter-rouge">dft_ldos</code>는 공간 monitor 없이 source 점에서 이것을 잰다</li>
    <li>Purcell 인자는 LDOS 하나가 아니라 같은 source로 돌린 두 run(cavity, bulk)의 비율이라는 것</li>
    <li>두 거울 사이에서 반파장마다 모드가 하나씩 열리고 LDOS가 계단처럼 뛰는 이유. cutoff에서는 비교 자체가 성립하지 않는다</li>
    <li>in-plane 쌍극자를 cylindrical 좌표의 <code class="language-plaintext highlighter-rouge">Er</code>, <code class="language-plaintext highlighter-rouge">m = -1</code>로 표현하는 법(13편의 예고)과 3D와의 교차검증</li>
    <li>z 방향에 PML을 두지 않는 것이 실수가 아니라 거울이라는 물리 조건이라는 것</li>
    <li>공진 LDOS ≈ 2Q/(πωV). Harminv의 Q로 필요한 run 시간 2Q/f를 정하고, 짧게 돌리면 어떻게 틀리는지</li>
  </ul>

  <p><strong>전제 지식</strong>: 10편의 image dipole과 PEC, 01편의 점원. <strong>공식 예제</strong>: <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Local_Density_of_States/">Local density of states 튜토리얼</a>의 <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Local_Density_of_States/#planar-cavity-with-lossless-metallic-walls">planar cavity with lossless metallic walls</a>와 <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Local_Density_of_States/#square-box-with-a-small-opening">metal cavity with an aperture</a>, 스크립트 <a href="https://github.com/NanoComp/meep/blob/master/python/examples/planar_cavity_ldos.py">planar_cavity_ldos.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/metal-cavity-ldos.py">metal-cavity-ldos.py</a>. <strong>이전 글</strong>: <a href="/meep-examples/dipole-pattern-3d/">10 · 점광원의 3D 방사 패턴</a> · <strong>다음 글</strong>: <a href="/meep-examples/ring-resonator/">12 · 빛을 가두는 고리</a></p>

  <h3 id="section-1">원본 §1 · 무엇을 알고 싶은가</h3>

  <p>10편의 끝 질문이었다. 거울 하나는 방사 패턴을 다섯 lobe로 바꿨다. 거울 둘 사이에 점광원을 두면 패턴만이 아니라 내는 빛의 양 자체가 바뀌는가. 같은 쌍극자, 같은 진폭인데 주변 구조에 따라 power가 달라진다는 것은 고전 전자기학 안에서 설명된다. 쌍극자가 내는 power는 자기 자신이 만든 field가 자기 전류에 하는 일이고, 거울이 그 field를 되돌려 보내면 일의 양이 바뀐다. 이 양을 재는 물리량이 LDOS이고, bulk 대비 비율이 Purcell 인자다. 두 번째 질문은 가둬 둔 빛에 관한 것이다. 금속 상자에 작은 구멍 하나를 내면 빛이 오래 머물고(Q), 그만큼 LDOS가 커진다는 Q/V 관계가 실제 측정과 맞는가.</p>

  <h3 id="section-2">어디에 쓰이는가</h3>

  <p>빛을 가두는 이유는 세 가지다. 첫째, 방출 속도가 바뀐다. 발광 분자가 비발광 경로보다 빨리 빛을 내면 효율이 오른다(Purcell). 둘째, 상호작용 시간이 늘어난다. 같은 재료라도 빛이 Q번 왕복하면 센서·변조기·비선형 효과가 Q배 커진다. 셋째, 주파수를 고른다. 공진 주파수의 빛만 통과시키는 것이 필터와 레이저의 원리다. 이 글의 LDOS와 Q는 세 가지 모두의 기초 수치다.</p>

  <table>
    <thead>
      <tr>
        <th>응용</th>
        <th>이 글의 어떤 것을 쓰는가</th>
        <th>그 다음에 필요한 것</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>OLED·LED 내부 효율</td>
        <td>Purcell 인자. 전극(거울)과 발광층 두께가 방출 속도를 정한다</td>
        <td>14편 광추출 효율</td>
      </tr>
      <tr>
        <td>단일광자원(양자점–cavity), 레이저 threshold</td>
        <td>LDOS, Q/V, 공진 모드의 β 인자</td>
        <td>12편 고리, 13편 cylindrical</td>
      </tr>
      <tr>
        <td>센서·변조기·비선형 소자</td>
        <td>Q로 상호작용 시간을 늘린다</td>
        <td>12편 ring, 22편 비선형</td>
      </tr>
      <tr>
        <td>필터·파장 분할 다중화(WDM)</td>
        <td>공진 주파수 선택, 선폭 f/Q</td>
        <td>12편 ring resonator</td>
      </tr>
      <tr>
        <td>열방사·복사 냉각</td>
        <td>LDOS 그 자체(열 LDOS)</td>
        <td>—</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-3">원본 §2 · 물리 한 페이지</h3>

  <p>주파수 ω에서 위치 $\mathbf x_0$의 쌍극자 $\hat p$가 내는 power는 그 자리의 전기장이 전류에 하는 일 $-\tfrac12\mathrm{Re}[\hat E\cdot\hat J^*]$에 비례한다. Meep의 <code class="language-plaintext highlighter-rouge">dft_ldos</code>는 이것을 단위 쌍극자로 정규화해 돌려준다.</p>

\[\mathrm{LDOS}(\mathbf x_0,\omega)=-\frac{2}{\pi}\,\varepsilon(\mathbf x_0)\,
\frac{\mathrm{Re}\big[\hat E_\ell(\mathbf x_0,\omega)\,\hat p(\omega)^*\big]}{\lvert \hat p(\omega)\lvert ^2},\qquad
F_P=\frac{\mathrm{LDOS}_{\mathrm{cavity}}}{\mathrm{LDOS}_{\mathrm{bulk}}}\]

  <p>분모가 필요한 이유는 분자에 source 진폭, 좌표계, 격자의 정규화가 모두 들어 있기 때문이다. 같은 source 표현으로 bulk를 한 번 더 돌려 나누면 그것들이 상쇄된다. 두 거울 사이의 in-plane 쌍극자에 대해 Abram 등(1998)은 두께 $t=nL/\lambda$의 함수로 닫힌 식을 줬다.</p>

\[F_P(t)=\frac{3N}{4t}+\frac{4N^3-N}{16t^3},\qquad N=\mathrm{fix}\!\left(t+\tfrac12\right)\]

  <p>$N$은 거울 사이에 들어가는 모드의 수다. $t$가 반정수를 지날 때마다 모드가 하나 열리고 $F_P$가 뛴다. $t=0.5$에서 3, $t=1.0$에서 0.94, $t=2.0$에서 0.98이다. 뛰는 지점(cutoff)에서는 LDOS가 연속 함수가 아니므로 유한 시간·유한 격자의 FDTD 값은 계단의 어느 쪽에 걸리느냐로 정해진다.</p>

  <p>금속 상자의 공진 모드 하나가 LDOS를 지배하면 single-mode 근사가 성립한다.</p>

\[\mathrm{LDOS}(\omega_n)\approx\frac{2}{\pi\,\omega_n}\,\frac{Q_n}{V_n},\qquad
V^{(1)}=\frac{a^2}{4},\quad \omega^{(1)}=\frac{\sqrt2\,\pi c}{a}\]

  <p>빛이 오래 머물수록($Q$), 좁은 곳에 몰릴수록($V$) 쌍극자가 더 많이 낸다. <code class="language-plaintext highlighter-rouge">dft_ldos</code>로 이것을 직접 재려면 DFT가 수렴할 만큼, 즉 field가 다 빠져나갈 만큼 돌려야 하고 그 시간은 $2Q/f$ 정도다.</p>

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$t=nL/\lambda$</td>
        <td>매질 안 파장 단위의 거울 간격</td>
        <td><code class="language-plaintext highlighter-rouge">T_NORM</code></td>
      </tr>
      <tr>
        <td>$L$</td>
        <td>실제 거울 간격 $t\lambda/n$</td>
        <td><code class="language-plaintext highlighter-rouge">cavity_um</code></td>
      </tr>
      <tr>
        <td>$N$</td>
        <td>열린 모드 수 $\mathrm{fix}(t+\tfrac12)$</td>
        <td><code class="language-plaintext highlighter-rouge">np.fix(t + 0.5)</code></td>
      </tr>
      <tr>
        <td>$F_P$</td>
        <td>Purcell 인자</td>
        <td><code class="language-plaintext highlighter-rouge">purcell_cyl</code>, <code class="language-plaintext highlighter-rouge">purcell_3d</code></td>
      </tr>
      <tr>
        <td>$Q$, $f$</td>
        <td>공진의 Q와 주파수 (Harminv)</td>
        <td><code class="language-plaintext highlighter-rouge">Q</code>, <code class="language-plaintext highlighter-rouge">f</code></td>
      </tr>
      <tr>
        <td>$V$</td>
        <td>모드 부피 $a^2/4$ (해석값)</td>
        <td><code class="language-plaintext highlighter-rouge">V_MODE</code></td>
      </tr>
      <tr>
        <td>$2Q/f$</td>
        <td><code class="language-plaintext highlighter-rouge">dft_ldos</code>에 필요한 run 시간</td>
        <td><code class="language-plaintext highlighter-rouge">T_req</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 파트 A는 손실 없는 유전체(n = 2.4)와 완전도체 거울, 단일 주파수, 수평 편광 쌍극자. 파트 B는 2D Ez, 완전도체 상자. 모드 부피 $a^2/4$는 닫힌 상자의 해석값이라 구멍이 있는 상자에는 근사다. 손실 매질의 점광원 LDOS는 해상도에 따라 발산하므로 이 글의 방법을 그대로 옮기면 안 된다.</p>

  <h3 id="section-4">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$F_P(t=1.0)$</td>
        <td>0.94</td>
        <td>Eq. 7, $N=1$</td>
      </tr>
      <tr>
        <td>cutoff 제외 median 오차 (CYL)</td>
        <td>2% 안</td>
        <td>노트 0.95%</td>
      </tr>
      <tr>
        <td>cutoff 세 점</td>
        <td>Eq. 7과 다르다, 어느 쪽 계단인지는 모른다</td>
        <td>불연속점</td>
      </tr>
      <tr>
        <td>3D(res 48) vs CYL, $t=1,2$</td>
        <td>3% 안</td>
        <td>노트의 CYL–3D median 1.3%</td>
      </tr>
      <tr>
        <td>$Q$의 w 의존</td>
        <td>w 0.5 → 0.2에서 수십 배</td>
        <td>구멍이 좁을수록 누설이 준다</td>
      </tr>
      <tr>
        <td>$Q$(w = 0.2)</td>
        <td>8000 근처</td>
        <td>노트 8060</td>
      </tr>
      <tr>
        <td>converged run의 LDOS vs $2Q/(\pi\omega V)$</td>
        <td>20% 안</td>
        <td>노트 median 15%. $V$가 근사값</td>
      </tr>
      <tr>
        <td>w = 0.2 (cap 6000 &lt; 2Q/f)</td>
        <td>$2Q/(\pi\omega V)$의 절반 아래</td>
        <td>노트: 2000 run에서 62%</td>
      </tr>
      <tr>
        <td>스펙트럼 FWHM의 $Q$ vs Harminv $Q$</td>
        <td>10% 안</td>
        <td>같은 공진</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: cutoff 밖 median &gt; 5%면 bulk 정규화나 경계(z PML 유무)를 의심한다. converged run에서 LDOS/(Q/V 추정)이 2배 넘게 다르면 Harminv가 다른 모드를 잡은 것이다.</p>

  <h3 id="section-5">원본 §3 · 시뮬레이션 설계도</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/02_layout_cyl.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/02_layout_cyl.png" alt="파트 A의 cylindrical r–z 셀(t=1.0, L = 0.417 µm). 가로가 반지름 r, 세로가 거울 법선 z. 위아래 셀 벽에 PML이 없다. 그 벽이 완전도체 거울이다. PML은 r 바깥쪽(녹색 빗금)에만 있다. 빨간" loading="lazy" /></a>
<figcaption>파트 A의 cylindrical r–z 셀($t=1.0$, L = 0.417 µm). 가로가 반지름 r, 세로가 거울 법선 z. 위아래 셀 벽에 PML이 없다. 그 벽이 완전도체 거울이다. PML은 r 바깥쪽(녹색 빗금)에만 있다. 빨간 점이 축에서 1.5 픽셀 떨어진 Er 쌍극자.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/01_layout.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/01_layout.png" alt="파트 B의 2D 셀. 완전도체 상자(1 × 1 µm, 벽 0.1 µm)의 오른쪽 벽에 폭 w의 구멍. 가운데 Ez 쌍극자가 Harminv의 probe이자 `dft_ldos`의 점이다. 사방 PML 1 µm. `plot2D`는 `mp." loading="lazy" /></a>
<figcaption>파트 B의 2D 셀. 완전도체 상자(1 × 1 µm, 벽 0.1 µm)의 오른쪽 벽에 폭 w의 구멍. 가운데 Ez 쌍극자가 Harminv의 probe이자 <code class="language-plaintext highlighter-rouge">dft_ldos</code>의 점이다. 사방 PML 1 µm. <code class="language-plaintext highlighter-rouge">plot2D</code>는 <code class="language-plaintext highlighter-rouge">mp.metal</code>(ε = −∞)을 흰색으로, 공기를 검게 그리므로 흰 테두리가 금속이다. 파란 사각형은 대표 Ez DFT 영역.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>A 파장, n, 해상도</td>
        <td>1 µm, 2.4, res 71</td>
        <td>공식 값. 매질 안 파장 0.417 µm에 30칸</td>
        <td>res가 낮으면 셀 두께가 격자에 반올림되어 계단이 생긴다</td>
      </tr>
      <tr>
        <td>A 두께 sweep</td>
        <td>$t$ = 0.5~2.5, 0.1 간격 21점</td>
        <td>공식 41점의 절반. cutoff 세 점 포함</td>
        <td>간격을 줄이면 cutoff 근처 계단이 더 보인다</td>
      </tr>
      <tr>
        <td>A 3D 확인</td>
        <td>$t$ = 1.0, 2.0, res 48</td>
        <td>전체 sweep을 3D로 하면 수십 분</td>
        <td>두 점만으로 좌표계 교차검증</td>
      </tr>
      <tr>
        <td>A bulk 셀</td>
        <td>CYL 6 µm, 3D 3 µm (+PML 0.5)</td>
        <td>균일 매질이라 크기에 둔감</td>
        <td>너무 작으면 PML 반사가 LDOS에 섞인다</td>
      </tr>
      <tr>
        <td>A 종료</td>
        <td>source 점의 field 감쇠 1e-6</td>
        <td>공식 값</td>
        <td>cavity run은 z 손실이 없어 bulk보다 오래 걸린다</td>
      </tr>
      <tr>
        <td>B 상자, 구멍</td>
        <td>a = 1, 벽 0.1, w = 0.2/0.3/0.4/0.5</td>
        <td>공식 0.2~0.4에 0.5 추가</td>
        <td>w가 작을수록 Q와 필요한 시간이 커진다</td>
      </tr>
      <tr>
        <td>B Harminv</td>
        <td>fcen = √0.5/a = 0.707, df 0.2, 500 time unit</td>
        <td>닫힌 상자의 기본 모드 주파수</td>
        <td>대역을 넓히면 고차 모드가 섞인다</td>
      </tr>
      <tr>
        <td>B <code class="language-plaintext highlighter-rouge">dft_ldos</code> 시간</td>
        <td>min(2Q/f, 6000)</td>
        <td>공식은 cap 없음. w = 0.2는 일부러 미수렴</td>
        <td>cap을 없애면 w = 0.2가 수십 분</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/00_source.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/00_source.png" alt="파트 A의 source 파형과 스펙트럼(1000 nm, fwidth 0.2 fcen). LDOS는 이 대역의 중심 주파수 하나에서 잰다." loading="lazy" /></a>
<figcaption>파트 A의 source 파형과 스펙트럼(1000 nm, fwidth 0.2 fcen). LDOS는 이 대역의 중심 주파수 하나에서 잰다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 강의 범위 밖이다. 10_sources의 두 노트는 각각 41점 sweep(CYL + 3D 전체, res 71)과 구멍 세 개(2000 cap)를 돌렸다. 이 글은 sweep을 21점으로 줄이고 3D를 두 점으로 제한한 대신, 구멍에 w = 0.5를 더하고 <code class="language-plaintext highlighter-rouge">dft_ldos</code> 스펙트럼의 폭으로 Q를 한 번 더 재서 Harminv와 맞춘다.</p>

</details>

<details>
  <summary>원본 코드 단계별 설명</summary>

  <h3 id="section-6">원본 §4 · 코드 따라가기</h3>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
이번 글의 ⑤는 공간 monitor가 아니라 source 점의 <code class="language-plaintext highlighter-rouge">dft_ldos</code>와 <code class="language-plaintext highlighter-rouge">Harminv</code>다.</p>
  </blockquote>

  <h3 id="section-7">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WL</span><span class="p">,</span> <span class="n">N_CAV</span><span class="p">,</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="n">RES_3D</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.4</span><span class="p">,</span> <span class="mi">71</span><span class="p">,</span> <span class="mi">48</span>
<span class="n">T_NORM</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">2.51</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">),</span> <span class="mi">2</span><span class="p">)</span>       <span class="c1"># t = n L / wl; cutoffs at 0.5, 1.5, 2.5
</span><span class="n">L</span> <span class="o">=</span> <span class="n">t</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_CAV</span>                                     <span class="c1"># the physical mirror spacing that goes into the cell
</span>
<span class="n">A_BOX</span><span class="p">,</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">WS</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">)</span>     <span class="c1"># metal box, wall, aperture widths
</span><span class="n">FCEN_M</span> <span class="o">=</span> <span class="n">math</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> <span class="o">/</span> <span class="n">A_BOX</span>                        <span class="c1"># fundamental mode of the closed box
</span><span class="n">T_MAX</span> <span class="o">=</span> <span class="mf">6000.0</span>                                         <span class="c1"># cap on the dft_ldos run
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 파트 A의 두께 sweep과 해상도, 파트 B의 상자와 구멍 폭.</li>
    <li><strong>왜</strong>: 그림의 가로축은 물리 두께가 아니라 $t=nL/\lambda$다. 셀에는 $L=t\lambda/n$을 넣어야 한다. 상자의 기본 모드는 $\omega=\sqrt2\pi c/a$, 즉 $f=\sqrt{0.5}/a$이고 Harminv의 중심이 된다.</li>
    <li><strong>틀리면</strong>: $t$를 µm로 그대로 넣으면 거울 간격이 2.4배 넓어지고 Eq. 7과 비교할 수 없다.</li>
  </ul>

  <h3 id="pml---">② 재료와 구조 — 거울은 PML을 두지 않은 벽</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># part A, cavity: PML only in r (cyl) or x, y (3D). The z walls of the cell are Meep's default PEC = the mirrors.
</span><span class="n">pml</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">)]</span>
<span class="c1"># part A, bulk: PML on every side, same source, same medium
</span><span class="n">pml</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">)]</span>
<span class="c1"># part B: a metal shell, an air box, and an air block that cuts the aperture into the right wall
</span><span class="n">geometry</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">A_BOX</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">A_BOX</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">metal</span><span class="p">),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">A_BOX</span><span class="p">,</span> <span class="n">A_BOX</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">A_BOX</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">)]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 파트 A의 거울은 geometry가 아니다. z 방향에 PML이 없으면 셀 벽이 완전도체이고 그것이 거울이다. bulk run은 모든 방향을 PML로 열어 거울을 없앤다. 파트 B는 금속 블록 → 공기 블록 → 구멍 블록 순으로 덮어쓴다.</li>
    <li><strong>왜</strong>: Purcell 인자는 “거울이 있을 때 / 없을 때”의 비율이다. 두 run의 차이가 경계 조건 하나뿐이어야 한다.</li>
    <li><strong>틀리면</strong>: cavity run에 z PML을 두면 run은 더 빨리 끝나지만 거울이 없어진다. 10편의 반대 경우다. 그때는 <code class="language-plaintext highlighter-rouge">k_point</code> 때문에 벽이 거울이 아니었고, 여기서는 <code class="language-plaintext highlighter-rouge">k_point</code>가 없어 벽이 거울이다.</li>
  </ul>

  <h3 id="source--in-plane---">③ Source — in-plane 쌍극자의 두 표현</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># cyl: an x-dipole is the m = -1 family of Er; the axis r = 0 is singular, so offset by 1.5 pixels
</span><span class="n">src_pt</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">src_pt</span><span class="p">)]</span>
<span class="c1"># 3D: the same dipole as Ex at the origin
</span><span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 같은 물리 쌍극자를 cylindrical에서는 <code class="language-plaintext highlighter-rouge">Er</code>, <code class="language-plaintext highlighter-rouge">m = -1</code>로, 3D에서는 <code class="language-plaintext highlighter-rouge">Ex</code>로 둔다.</li>
    <li><strong>왜</strong>: x 방향 쌍극자의 방위각 의존성은 $e^{\pm i\phi}$, 즉 $m=\pm1$이다. 축 위에서는 r 방향 단위벡터가 정의되지 않으므로 1.5 픽셀 비킨다. 이 offset은 구조 변경이 아니라 좌표 특이점 회피다.</li>
    <li><strong>틀리면</strong>: offset을 µm 상수로 고정하면 해상도를 바꿀 때 픽셀 단위 표현이 달라진다. 13편에서 cylindrical 좌표를 본격적으로 다룬다.</li>
  </ul>

  <h3 id="simulation---cyl-m-3d-symmetry-">④ Simulation과 경계 — CYL의 m과 3D의 symmetry 위상</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_CYL</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cell_r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cell_z</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="n">pml</span><span class="p">,</span>
                    <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span> <span class="n">default_material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_CAV</span><span class="p">),</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">)</span>

<span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(...,</span> <span class="n">symmetries</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">)])</span>   <span class="c1"># 3D: Ex is odd under x
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: cylindrical은 <code class="language-plaintext highlighter-rouge">dimensions=mp.CYLINDRICAL</code>과 <code class="language-plaintext highlighter-rouge">m</code>. 3D는 세 거울 대칭으로 계산을 1/8로.</li>
    <li><strong>왜</strong>: <code class="language-plaintext highlighter-rouge">Ex</code>는 x 반전에서 부호가 바뀌고 y, z 반전에서는 그대로다. 위상은 geometry가 아니라 source 벡터의 parity다.</li>
    <li><strong>틀리면</strong>: 위상을 전부 +1로 두면 더 빠른 같은 계산이 아니라 다른 parity의 source를 계산한다. 10편의 image dipole에서 Ez가 odd였던 것과 같은 규칙이다.</li>
  </ul>

  <h3 id="monitor---monitor--source-">⑤ Monitor — 공간 monitor 없이 source 점에서</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="p">...)</span>          <span class="c1"># LDOS at one frequency, at the source point
</span><span class="n">ldos</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">ldos_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

<span class="n">h</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Harminv</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">FCEN_M</span><span class="p">,</span> <span class="n">DF_M</span><span class="p">)</span>                   <span class="c1"># part B: f and Q of the ringing field
</span><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">after_sources</span><span class="p">(</span><span class="n">h</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span>
<span class="n">f</span><span class="p">,</span> <span class="n">Q</span> <span class="o">=</span> <span class="n">h</span><span class="p">.</span><span class="n">modes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">freq</span><span class="p">,</span> <span class="n">h</span><span class="p">.</span><span class="n">modes</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">Q</span>
<span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="mi">8</span> <span class="o">*</span> <span class="n">f</span> <span class="o">/</span> <span class="n">Q</span><span class="p">,</span> <span class="mi">101</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="nb">min</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">Q</span> <span class="o">/</span> <span class="n">f</span><span class="p">,</span> <span class="n">T_MAX</span><span class="p">))</span>   <span class="c1"># spectrum +-4 linewidths around f
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: <code class="language-plaintext highlighter-rouge">dft_ldos</code>는 step function이다. source 점의 field와 전류의 DFT를 축적해 LDOS를 만든다. Harminv는 source가 꺼진 뒤의 감쇠에서 공진 주파수와 Q를 꺼낸다.</li>
    <li><strong>왜</strong>: LDOS는 flux가 아니라 source 자리의 일이다. 그래서 flux box가 필요 없고 source 점 하나면 된다. 파트 B에서는 Harminv의 f를 <code class="language-plaintext highlighter-rouge">dft_ldos</code>의 주파수로 넘기고, 스펙트럼의 폭으로 Q를 한 번 더 확인한다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">dft_ldos</code>의 주파수를 Harminv의 f가 아니라 처음의 fcen으로 두면 공진에서 조금 비껴 LDOS가 작게 나온다. Q가 수천이면 폭이 1e-4라 조금이 크다.</li>
  </ul>

  <h3 id="qf">⑥ 실행 — 감쇠 조건과 2Q/f</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">,</span> <span class="mf">1e-6</span><span class="p">)</span>    <span class="c1"># part A
</span><span class="n">until_after_sources</span><span class="o">=</span><span class="nb">min</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">Q</span> <span class="o">/</span> <span class="n">f</span><span class="p">,</span> <span class="n">T_MAX</span><span class="p">)</span>                                     <span class="c1"># part B
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 파트 A는 source 점의 field가 1e-6으로 줄 때까지. 파트 B는 Q로 정한 시간만큼.</li>
    <li><strong>왜</strong>: Fourier 불확정성 때문에 선폭 $f/Q$를 분해하려면 감쇠 시간 한 주기, $2Q/f$가 필요하다. w = 0.2의 Q는 8000 근처라 $2Q/f\approx 23000$이고, 이 글은 6000에서 자른다. 그 결과가 어떻게 틀리는지를 보여 주기 위해서다.</li>
    <li><strong>틀리면</strong>: cavity run을 bulk run처럼 짧게 끝내면 거울 사이에 남은 field가 LDOS에 다 더해지지 못한다. 파트 A의 cavity run이 bulk보다 오래 걸리는 것은 정상이다.</li>
  </ul>

  <h3 id="eq-7-qv">⑦ 후처리 — 비율, Eq. 7, Q/V</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">purcell</span> <span class="o">=</span> <span class="n">ldos_cavity</span> <span class="o">/</span> <span class="n">ldos_bulk</span>                                      <span class="c1"># same source, same medium, same coordinates
</span><span class="n">N</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fix</span><span class="p">(</span><span class="n">t</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">);</span> <span class="n">theory</span> <span class="o">=</span> <span class="mi">3</span> <span class="o">*</span> <span class="n">N</span> <span class="o">/</span> <span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">t</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">N</span><span class="o">**</span><span class="mi">3</span> <span class="o">-</span> <span class="n">N</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="mi">16</span> <span class="o">*</span> <span class="n">t</span><span class="o">**</span><span class="mi">3</span><span class="p">)</span>
<span class="n">cutoff</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">isclose</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">mod</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="mf">0.5</span><span class="p">)</span>                               <span class="c1"># exclude from the error statistics, keep the raw values
</span>
<span class="n">ldos_qv</span> <span class="o">=</span> <span class="n">Q</span> <span class="o">/</span> <span class="n">V_MODE</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">f</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="mf">0.5</span><span class="p">)</span>               <span class="c1"># 2Q / (pi w V), V = a^2 / 4
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: Purcell은 비율. Eq. 7과의 오차는 cutoff를 빼고 median과 max를 함께 적는다. 파트 B는 Q/V 추정과 직접 측정을 나란히 둔다.</li>
    <li><strong>왜</strong>: median만 적으면 $t=1.45$ 같은 국소 실패가 가려진다. cutoff 값은 버리지 않고 표로 남긴다.</li>
    <li><strong>틀리면</strong>: cutoff의 FDTD 값을 “틀렸다”고 분류하거나 유리한 쪽 계단으로 바꾸면 안 된다. 그 점의 해석값 자체가 두 개다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: Meep은 셀 크기를 픽셀 정수로 반올림한다. $L\times$res가 정수가 아니면 이웃한 두께가 같은 z 격자 수를 쓰게 되어 sweep 곡선에 작은 계단이 생긴다. cutoff 근처에서는 이 반올림이 열린 모드의 표현을 바꿀 수 있다. 로그의 “cell size will be rounded”는 무시할 문자열이 아니다.</p>
  </blockquote>

</details>

<details>
  <summary>원본 결과·검증 표·오류 진단·추가 탐구</summary>

  <h3 id="section-8">원본 §5 · 결과</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/03_purcell.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/03_purcell.png" alt="파트 A. 왼쪽: Purcell 인자 vs t. 검은 선이 Eq. 7, 빨간 점이 cylindrical sweep, 파란 네모가 3D 두 점. 점선이 cutoff. 오른쪽: cutoff를 뺀 상대오차. 회색 막대가 cutoff 세 점" loading="lazy" /></a>
<figcaption>파트 A. 왼쪽: Purcell 인자 vs $t$. 검은 선이 Eq. 7, 빨간 점이 cylindrical sweep, 파란 네모가 3D 두 점. 점선이 cutoff. 오른쪽: cutoff를 뺀 상대오차. 회색 막대가 cutoff 세 점이다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>$t$</th>
        <th>Eq. 7</th>
        <th>CYL</th>
        <th>3D (res 48)</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0.5</td>
        <td>3.000</td>
        <td>3.018</td>
        <td>—</td>
        <td>cutoff</td>
      </tr>
      <tr>
        <td>1.0</td>
        <td>0.9375</td>
        <td>0.912</td>
        <td>0.933</td>
        <td> </td>
      </tr>
      <tr>
        <td>1.5</td>
        <td>1.556 (위 계단) / 0.519 (아래)</td>
        <td>0.507</td>
        <td>—</td>
        <td>cutoff. FDTD는 아래 계단</td>
      </tr>
      <tr>
        <td>2.0</td>
        <td>0.9844</td>
        <td>0.988</td>
        <td>0.979</td>
        <td> </td>
      </tr>
      <tr>
        <td>2.5</td>
        <td>1.320 (위) / 0.728 (아래)</td>
        <td>1.172</td>
        <td>—</td>
        <td>cutoff</td>
      </tr>
      <tr>
        <td>cutoff 제외 18점</td>
        <td>—</td>
        <td>median 0.94%, max 3.6% (t = 0.70)</td>
        <td>—</td>
        <td> </td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/04_cavity_field.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/04_cavity_field.png" alt="거울 사이의 정상상태 Re(Er), r–z 평면(z를 늘려 그렸다). t=1.0에서는 z 방향으로 마디 없는 모드 하나가 r 방향으로 퍼져 나간다. t=2.0에서는 z 방향으로 마디가 둘인 모드가 겹쳐 위아래 lobe의 부호가 가운데" loading="lazy" /></a>
<figcaption>거울 사이의 정상상태 Re(Er), r–z 평면(z를 늘려 그렸다). $t=1.0$에서는 z 방향으로 마디 없는 모드 하나가 r 방향으로 퍼져 나간다. $t=2.0$에서는 z 방향으로 마디가 둘인 모드가 겹쳐 위아래 lobe의 부호가 가운데와 반대다. 초록 점이 쌍극자, 색 범위는 source 픽셀을 빼고 잘랐다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/11/05_metal_ldos.png" data-lightbox=""><img src="/meep-examples/assets/meep/11/05_metal_ldos.png" alt="파트 B. 왼쪽: 공진 주변의 `dft_ldos` 스펙트럼. 폭이 f/Q다. 가운데: Q/V 추정(파랑)과 직접 측정(빨강)을 a/w에 대해 semilog로. w = 0.2는 run을 잘라 미수렴. 오른쪽: w = 0.3의 공진 Ez" loading="lazy" /></a>
<figcaption>파트 B. 왼쪽: 공진 주변의 <code class="language-plaintext highlighter-rouge">dft_ldos</code> 스펙트럼. 폭이 $f/Q$다. 가운데: Q/V 추정(파랑)과 직접 측정(빨강)을 a/w에 대해 semilog로. w = 0.2는 run을 잘라 미수렴. 오른쪽: w = 0.3의 공진 Ez. 닫힌 상자의 기본 모드 $\sin(\pi x/a)\sin(\pi y/a)$에 구멍 쪽 누설이 더해진 모양.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>w</th>
        <th>f (Harminv)</th>
        <th>Q (Harminv)</th>
        <th>Q (스펙트럼 폭)</th>
        <th>2Q/f</th>
        <th>실행</th>
        <th>$2Q/(\pi\omega V)$</th>
        <th><code class="language-plaintext highlighter-rouge">dft_ldos</code></th>
        <th>비</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0.2</td>
        <td>0.6740</td>
        <td>8060</td>
        <td>5597 (잘린 run)</td>
        <td>23915</td>
        <td>6000 (cap)</td>
        <td>4846</td>
        <td>3499</td>
        <td>0.72</td>
      </tr>
      <tr>
        <td>0.3</td>
        <td>0.6688</td>
        <td>1271</td>
        <td>1324</td>
        <td>3802</td>
        <td>3802</td>
        <td>770</td>
        <td>686</td>
        <td>0.89</td>
      </tr>
      <tr>
        <td>0.4</td>
        <td>0.6569</td>
        <td>189</td>
        <td>196</td>
        <td>574</td>
        <td>574</td>
        <td>116</td>
        <td>98</td>
        <td>0.85</td>
      </tr>
      <tr>
        <td>0.5</td>
        <td>0.6465</td>
        <td>74</td>
        <td>78</td>
        <td>230</td>
        <td>230</td>
        <td>46.7</td>
        <td>37.6</td>
        <td>0.81</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-9">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$F_P(t=1.0)$</td>
        <td>0.94</td>
        <td>0.912</td>
        <td>✅ (2.7% 차)</td>
      </tr>
      <tr>
        <td>cutoff 제외 median 오차</td>
        <td>2% 안</td>
        <td>0.94%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>cutoff 세 점</td>
        <td>Eq. 7과 다름</td>
        <td>0.5: 3.018, 1.5: 0.507, 2.5: 1.172</td>
        <td>cutoff: 1.5는 아래쪽에 가깝고, 2.5는 두 극한 사이</td>
      </tr>
      <tr>
        <td>3D vs CYL</td>
        <td>3% 안</td>
        <td>2.3% / 0.9% (t = 1.0 / 2.0)</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>$Q$의 w 의존</td>
        <td>수십 배</td>
        <td>74 → 8060</td>
        <td>✅ (109배)</td>
      </tr>
      <tr>
        <td>$Q$(w = 0.2)</td>
        <td>8000 근처</td>
        <td>8060</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>converged LDOS vs Q/V</td>
        <td>20% 안</td>
        <td>0.81~0.89</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>w = 0.2 미수렴</td>
        <td>절반 아래</td>
        <td>0.72 (28% 부족)</td>
        <td>❌ (절반보다 위)</td>
      </tr>
      <tr>
        <td>스펙트럼 Q vs Harminv Q</td>
        <td>10% 안</td>
        <td>1324/1271, 196/189, 78/74 (4~5%)</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>아홉 예측 중 여덟이 맞았다. 틀린 것은 w = 0.2의 미수렴 정도다. 노트는 필요 시간의 8%(2000)만 돌려 62%가 모자랐고, 이 글은 25%(6000)를 돌려 28%가 모자랐다. run을 자르면 공진 봉우리의 꼬리가 DFT에 다 들어오지 못해 LDOS가 작아지고 스펙트럼은 넓어진다. 스펙트럼 폭으로 잰 Q가 5597로 Harminv의 8060보다 작은 것이 그 지문이다. 나머지 세 구멍에서는 스펙트럼 Q와 Harminv Q가 5% 안에서 같고, 직접 잰 LDOS는 Q/V 추정의 81~89%다. 남은 10~20%는 모드 부피 $a^2/4$가 닫힌 상자의 값이라 구멍이 넓을수록 실제 모드가 더 퍼지기 때문이고, 실제로 w가 넓어질수록 비가 0.89에서 0.81로 내려간다. 파트 A에서 $t=1.0$의 CYL 값 0.912는 Eq. 7의 0.9375보다 2.7% 낮지만 3D 값 0.933이 그 사이에 있어 좌표계 표현의 차이로 본다. cutoff에서는 예측대로 FDTD가 계단의 한쪽에 걸렸다. $t=0.5$는 위 계단(3.018 vs 3.0), $t=1.5$는 아래쪽 극한에 가깝고(0.507 vs 0.519), $t=2.5$의 1.172는 아래쪽 0.728과 위쪽 1.320 사이이다.</p>

  <h3 id="section-10">수렴성</h3>

  <table>
    <thead>
      <tr>
        <th>변수</th>
        <th>값</th>
        <th>결과</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>A sweep 간격</td>
        <td>0.1 (21점, 이 글) vs 0.05 (41점, 노트)</td>
        <td>median 0.94% vs 0.95%</td>
        <td>간격은 오차를 바꾸지 않는다. 각 점이 독립 run</td>
      </tr>
      <tr>
        <td>A 3D 해상도</td>
        <td>48 (이 글) vs 71 (노트)</td>
        <td>$t=1,2$에서 CYL과 2.3% / 0.9% (t = 1.0 / 2.0) vs 노트 median 1.3%</td>
        <td>노트의 3D max 11.4%($t=1.45$)는 이 글에서 재지 않았다</td>
      </tr>
      <tr>
        <td>B run 시간</td>
        <td>2Q/f (w ≥ 0.3) vs cap 6000 (w = 0.2)</td>
        <td>비 0.81~0.89 vs 0.72</td>
        <td>미수렴은 작은 오차가 아니라 다른 숫자</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-11">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: n = 2.4, 완전도체 거울, res 71에서 cylindrical <code class="language-plaintext highlighter-rouge">dft_ldos</code>의 Purcell 인자는 cutoff 밖에서 Eq. 7 대비 상대오차 중앙값 0.94%, 최대 3.6%이며, 3D 두 점과 2.3% / 0.9% (t = 1.0 / 2.0) 안에서 같다. 금속 상자에서 Harminv의 Q로 정한 시간만큼 돌리면 직접 잰 LDOS가 $2Q/(\pi\omega V)$와 0.81~0.89 안에서 같다.</li>
    <li>할 수 없는 것: cutoff 세 점의 값. 해석식 자체가 불연속이다. 노트가 본 3D의 국소 11% 오차($t=1.45$)는 이 글의 두 점에 없다. 손실 있는 거울이나 매질. 모드 부피 $a^2/4$는 닫힌 상자의 값이라 구멍이 넓어질수록 근사가 나빠진다. w = 0.2의 LDOS는 이 글의 run 시간으로는 모른다.</li>
  </ul>

  <h3 id="section-12">원본 §6 · 흔한 실수</h3>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Purcell이 전부 1 근처</td>
        <td>cavity run에 z PML을 둠(거울 없음)</td>
        <td>cavity는 횡방향만 PML, bulk는 전방향</td>
      </tr>
      <tr>
        <td>Purcell이 수십 배</td>
        <td>bulk 정규화를 빼먹고 raw LDOS를 봄</td>
        <td>같은 source로 bulk를 돌려 나눈다</td>
      </tr>
      <tr>
        <td>CYL run이 축에서 발산</td>
        <td><code class="language-plaintext highlighter-rouge">Er</code>를 r = 0에 둠</td>
        <td>1.5 픽셀 offset</td>
      </tr>
      <tr>
        <td>3D 결과가 CYL과 2배 다름</td>
        <td>symmetry 위상 전부 +1</td>
        <td><code class="language-plaintext highlighter-rouge">Ex</code>는 <code class="language-plaintext highlighter-rouge">Mirror(X, phase=-1)</code></td>
      </tr>
      <tr>
        <td>sweep 곡선의 작은 계단</td>
        <td>셀 두께가 픽셀로 반올림</td>
        <td>$L\times$res가 정수가 되게 고르거나 해상도를 올린다</td>
      </tr>
      <tr>
        <td>cutoff에서 50% 오차</td>
        <td>불연속점을 일반 점처럼 통계에 넣음</td>
        <td>raw 값은 남기고 median에서 뺀다</td>
      </tr>
      <tr>
        <td>직접 LDOS가 Q/V의 절반</td>
        <td><code class="language-plaintext highlighter-rouge">dft_ldos</code> run이 2Q/f보다 짧음</td>
        <td>Q를 먼저 재고 시간을 정한다</td>
      </tr>
      <tr>
        <td>r–z field 그림이 뒤집힘, 한 줄만 진함</td>
        <td>cylindrical의 <code class="language-plaintext highlighter-rouge">get_array</code>·<code class="language-plaintext highlighter-rouge">get_dft_array</code>는 (z, r) 순서</td>
        <td>2D처럼 전치하지 않는다. 진한 한 줄은 r = 0의 source 열</td>
      </tr>
      <tr>
        <td>field 그림이 거의 비어 보임</td>
        <td>source 픽셀이 색 범위의 최대값을 차지</td>
        <td>99 percentile로 색 범위를 자른다</td>
      </tr>
      <tr>
        <td>LDOS가 공진값보다 작음</td>
        <td><code class="language-plaintext highlighter-rouge">dft_ldos</code> 주파수를 Harminv의 f가 아니라 fcen으로</td>
        <td>Harminv f를 넘긴다</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-13">원본 §7 · 직접 해보기</h3>

  <table>
    <thead>
      <tr>
        <th>바꿀 것</th>
        <th>예상 변화</th>
        <th>확인할 수치</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>파트 A의 쌍극자를 z 방향(<code class="language-plaintext highlighter-rouge">Ez</code>, m = 0)으로</td>
        <td>수직 쌍극자는 거울 사이에서 다른 곡선</td>
        <td>$t&lt;0.5$에서 0이 아닌지</td>
      </tr>
      <tr>
        <td>sweep 간격 0.1 → 0.02, $t$ = 1.4~1.6</td>
        <td>cutoff 1.5 근처의 계단 모양</td>
        <td>어느 $t$에서 뛰는지</td>
      </tr>
      <tr>
        <td>파트 A 해상도 50 / 71 / 100</td>
        <td>cutoff 밖 median의 사다리</td>
        <td>0.94%가 어디서 정체하는지</td>
      </tr>
      <tr>
        <td>파트 B의 cap을 없애고 w = 0.2</td>
        <td>비가 1 근처로</td>
        <td>비, 걸린 시간</td>
      </tr>
      <tr>
        <td>파트 B에 w = 0.1</td>
        <td>Q 수만, 2Q/f 수십만</td>
        <td>Harminv만으로 Q/V 추정</td>
      </tr>
    </tbody>
  </table>

</details>

<details>
<summary>code/cavity_ldos.py 전체 (클릭하여 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 11 - A point dipole between two mirrors: LDOS and the Purcell factor.

Post 10 showed that one mirror rewrites the radiation pattern. Here the dipole sits between two mirrors and the
question is the emitted POWER itself, measured as the local density of states (LDOS) at the dipole position.
  A. Planar cavity (official planar_cavity_ldos.py): lossless metallic walls, dielectric n = 2.4, in-plane dipole.
     The Purcell factor F = LDOS(cavity) / LDOS(bulk) versus the normalized thickness t = n L / wl, swept in
     cylindrical coordinates (Er, m = -1 represents an x-dipole) and checked at two thicknesses in full 3D.
     Compared with the analytic Eq. 7 of Abram et al. (1998): F = 3N/(4t) + (4N^3 - N)/(16 t^3), N = fix(t + 1/2).
  B. Metal box with an aperture (official metal-cavity-ldos.py, 2D): Harminv gives f and Q of the fundamental mode;
     the LDOS at f is measured directly with dft_ldos and compared with the single-mode estimate 2Q/(pi w V).
     The required run time 2Q/f grows with Q; the narrowest aperture is deliberately left under-converged.

Run:  python cavity_ldos.py       (~15 min on one core)
Out:  00_source.png, 01_layout.png, 02_layout_cyl.png, 03_purcell.png, 04_cavity_field.png, 05_metal_ldos.png,
      06_anim_planar.gif, 07_anim_metal.gif, result.json   (-&gt; ../assets/11/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">math</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">_badge</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">HERE</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"11"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>

<span class="c1"># =================================================================== A. planar cavity with lossless metallic walls
# ---------------------------------------------------------------- (1) parameters (official values; 21-point sweep instead of 41)
</span><span class="n">WL</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">FCEN</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">WL</span>
<span class="n">FWIDTH</span> <span class="o">=</span> <span class="mf">0.2</span> <span class="o">*</span> <span class="n">FCEN</span>
<span class="n">N_CAV</span> <span class="o">=</span> <span class="mf">2.4</span>
<span class="n">RES_CYL</span> <span class="o">=</span> <span class="mi">71</span>
<span class="n">RES_3D</span> <span class="o">=</span> <span class="mi">48</span>                              <span class="c1"># 3D cross-check only (official: 71)
</span><span class="n">DPML</span> <span class="o">=</span> <span class="mf">0.5</span>
<span class="n">BULK_CYL</span><span class="p">,</span> <span class="n">BULK_3D</span> <span class="o">=</span> <span class="mf">6.0</span><span class="p">,</span> <span class="mf">3.0</span>
<span class="n">DECAY_TOL</span><span class="p">,</span> <span class="n">DECAY_PERIOD</span> <span class="o">=</span> <span class="mf">1e-6</span><span class="p">,</span> <span class="mi">20</span>
<span class="n">T_NORM</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">2.51</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">),</span> <span class="mi">2</span><span class="p">)</span>          <span class="c1"># t = n L / wl; cutoffs at 0.5, 1.5, 2.5
</span><span class="n">T_3D</span> <span class="o">=</span> <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">)</span>                                         <span class="c1"># thicknesses checked in full 3D
</span>

<span class="k">def</span> <span class="nf">purcell_theory</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
    <span class="n">N</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fix</span><span class="p">(</span><span class="n">t</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span>
    <span class="k">return</span> <span class="mi">3</span> <span class="o">*</span> <span class="n">N</span> <span class="o">/</span> <span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">t</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">N</span> <span class="o">**</span> <span class="mi">3</span> <span class="o">-</span> <span class="n">N</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="mi">16</span> <span class="o">*</span> <span class="n">t</span> <span class="o">**</span> <span class="mi">3</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">ldos_cyl</span><span class="p">(</span><span class="n">cavity_um</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">want_field</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="s">"""LDOS of an in-plane dipole (Er, m = -1) in cylindrical coordinates; bulk medium if cavity_um is None."""</span>
    <span class="k">if</span> <span class="n">cavity_um</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">cell_z</span><span class="p">,</span> <span class="n">pml</span> <span class="o">=</span> <span class="n">BULK_CYL</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">)]</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">cell_z</span><span class="p">,</span> <span class="n">pml</span> <span class="o">=</span> <span class="n">cavity_um</span><span class="p">,</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">)]</span>      <span class="c1"># no z PML: the cell walls are the mirrors
</span>    <span class="n">cell_r</span> <span class="o">=</span> <span class="n">BULK_CYL</span> <span class="o">+</span> <span class="n">DPML</span>
    <span class="n">src_pt</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>                                    <span class="c1"># Er at r = 0 is singular: offset by 1.5 px
</span>    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_CYL</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cell_r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cell_z</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="n">pml</span><span class="p">,</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span>
                        <span class="n">default_material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_CAV</span><span class="p">),</span>
                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">src_pt</span><span class="p">)])</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">],</span> <span class="n">FCEN</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">BULK_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">BULK_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cell_z</span><span class="p">))</span> <span class="k">if</span> <span class="n">want_field</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="n">DECAY_PERIOD</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">,</span> <span class="n">DECAY_TOL</span><span class="p">))</span>
    <span class="n">ldos</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="n">t_end</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">meep_time</span><span class="p">()</span>
    <span class="n">field</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="k">if</span> <span class="n">want_field</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">ldos</span><span class="p">,</span> <span class="n">t_end</span><span class="p">,</span> <span class="n">field</span><span class="p">)</span> <span class="k">if</span> <span class="n">want_field</span> <span class="k">else</span> <span class="p">(</span><span class="n">ldos</span><span class="p">,</span> <span class="n">t_end</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">ldos_3d</span><span class="p">(</span><span class="n">cavity_um</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="s">"""LDOS of an Ex dipole in full 3D (reduced resolution); bulk if cavity_um is None."""</span>
    <span class="k">if</span> <span class="n">cavity_um</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">size_z</span><span class="p">,</span> <span class="n">pml</span> <span class="o">=</span> <span class="n">BULK_3D</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">)]</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">size_z</span><span class="p">,</span> <span class="n">pml</span> <span class="o">=</span> <span class="n">cavity_um</span><span class="p">,</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)]</span>
    <span class="n">size_xy</span> <span class="o">=</span> <span class="n">BULK_3D</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_3D</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">size_xy</span><span class="p">,</span> <span class="n">size_xy</span><span class="p">,</span> <span class="n">size_z</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="n">pml</span><span class="p">,</span>
                        <span class="n">default_material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_CAV</span><span class="p">),</span>
                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())],</span>
                        <span class="n">symmetries</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">)])</span>      <span class="c1"># Ex is odd under x, even under y, z
</span>    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="n">DECAY_PERIOD</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">DECAY_TOL</span><span class="p">))</span>
    <span class="n">ldos</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="n">t_end</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">meep_time</span><span class="p">();</span> <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">ldos</span><span class="p">,</span> <span class="n">t_end</span>


<span class="n">source_figure</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">FWIDTH</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>

<span class="c1"># layout of the CYL cavity (r-z plane) at t = 1.0, drawn by hand: the cell is 6.5 x 0.42 um, far too thin for plot2D
</span><span class="n">L_demo</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_CAV</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">9.5</span><span class="p">,</span> <span class="mf">3.6</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">axvspan</span><span class="p">(</span><span class="n">BULK_CYL</span><span class="p">,</span> <span class="n">BULK_CYL</span> <span class="o">+</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"green"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.25</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">4</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">7</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">axvline</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"-."</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="k">for</span> <span class="n">xy</span><span class="p">,</span> <span class="n">step</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">txt</span><span class="p">,</span> <span class="n">txy</span> <span class="ow">in</span> <span class="p">(((</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span> <span class="o">-</span> <span class="mf">0.03</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"dimgray"</span><span class="p">,</span> <span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">WL</span><span class="si">}</span><span class="s"> um, n=</span><span class="si">{</span><span class="n">N_CAV</span><span class="si">}</span><span class="s">, res=</span><span class="si">{</span><span class="n">RES_CYL</span><span class="si">}</span><span class="se">\n</span><span class="s">cell r </span><span class="si">{</span><span class="n">BULK_CYL</span> <span class="o">+</span> <span class="n">DPML</span><span class="si">}</span><span class="s"> um x z L=</span><span class="si">{</span><span class="n">L_demo</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> um, m=-1"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.45</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span> <span class="o">-</span> <span class="mf">0.03</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span><span class="p">),</span> <span class="mi">2</span><span class="p">,</span> <span class="s">"black"</span><span class="p">,</span> <span class="s">"top/bottom cell walls: no PML here, so they are PEC = the two mirrors"</span><span class="p">,</span> <span class="p">(</span><span class="mf">3.2</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span> <span class="o">-</span> <span class="mf">0.035</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.035</span><span class="p">),</span> <span class="mi">3</span><span class="p">,</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"Er dipole (m = -1 = an in-plane dipole) at r = 1.5 px, the axis is singular"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.45</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.045</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="n">BULK_CYL</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"green"</span><span class="p">,</span> <span class="s">"PML (r only)"</span><span class="p">,</span> <span class="p">(</span><span class="n">BULK_CYL</span> <span class="o">+</span> <span class="mf">0.08</span><span class="p">,</span> <span class="mf">0.04</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.07</span><span class="p">),</span> <span class="mi">5</span><span class="p">,</span> <span class="s">"blue"</span><span class="p">,</span> <span class="s">"LDOS: dft_ldos at the source point (no spatial monitor); bulk run = same cell with PML on z too"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="mf">0.06</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="mf">0.11</span><span class="p">),</span> <span class="mi">6</span><span class="p">,</span> <span class="s">"purple"</span><span class="p">,</span> <span class="s">"decay watch point = source point"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.45</span><span class="p">,</span> <span class="mf">0.10</span><span class="p">))):</span>
    <span class="n">_badge</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">xy</span><span class="p">,</span> <span class="n">step</span><span class="p">,</span> <span class="n">color</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="o">*</span><span class="n">txy</span><span class="p">,</span> <span class="n">txt</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">,</span> <span class="n">va</span><span class="o">=</span><span class="s">"center"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="mf">0.05</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span> <span class="o">+</span> <span class="mf">0.01</span><span class="p">,</span> <span class="s">"r = 0 (axis)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">rotation</span><span class="o">=</span><span class="mi">90</span><span class="p">,</span> <span class="n">va</span><span class="o">=</span><span class="s">"bottom"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">BULK_CYL</span> <span class="o">+</span> <span class="n">DPML</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span> <span class="o">-</span> <span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L_demo</span> <span class="o">+</span> <span class="mf">0.02</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"r [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"z [um]  (stretched)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"part A: cylindrical r-z cell at t = 1.0. The z axis is stretched 6x; the real cell is a thin disc between two mirrors"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_layout_cyl.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="n">t_a</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">bulk_cyl</span><span class="p">,</span> <span class="n">t_bulk_cyl</span> <span class="o">=</span> <span class="n">ldos_cyl</span><span class="p">()</span>
<span class="n">purcell_cyl</span><span class="p">,</span> <span class="n">t_end_cyl</span><span class="p">,</span> <span class="n">fields</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">T_NORM</span><span class="p">:</span>
    <span class="n">L</span> <span class="o">=</span> <span class="n">t</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_CAV</span>
    <span class="k">if</span> <span class="n">t</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">):</span>
        <span class="n">ldos</span><span class="p">,</span> <span class="n">t_end</span><span class="p">,</span> <span class="n">fld</span> <span class="o">=</span> <span class="n">ldos_cyl</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">want_field</span><span class="o">=</span><span class="bp">True</span><span class="p">);</span> <span class="n">fields</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">fld</span><span class="p">,</span> <span class="n">L</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">ldos</span><span class="p">,</span> <span class="n">t_end</span> <span class="o">=</span> <span class="n">ldos_cyl</span><span class="p">(</span><span class="n">L</span><span class="p">)</span>
    <span class="n">purcell_cyl</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">ldos</span> <span class="o">/</span> <span class="n">bulk_cyl</span><span class="p">);</span> <span class="n">t_end_cyl</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">t_end</span><span class="p">)</span>
<span class="n">purcell_cyl</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">purcell_cyl</span><span class="p">)</span>
<span class="n">theory</span> <span class="o">=</span> <span class="n">purcell_theory</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">)</span>
<span class="n">cutoff</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">isclose</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">mod</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="mf">0.5</span><span class="p">)</span>
<span class="n">err_cyl</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">purcell_cyl</span> <span class="o">-</span> <span class="n">theory</span><span class="p">)</span> <span class="o">/</span> <span class="n">theory</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"A (cyl): bulk LDOS </span><span class="si">{</span><span class="n">bulk_cyl</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">f</span><span class="si">}</span><span class="s"> (t_end </span><span class="si">{</span><span class="n">t_bulk_cyl</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">); </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">)</span><span class="si">}</span><span class="s"> thicknesses in </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_a</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s; "</span>
      <span class="sa">f</span><span class="s">"rel error vs Eq. 7 away from cutoffs: median </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">median</span><span class="p">(</span><span class="n">err_cyl</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">])</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, max </span><span class="si">{</span><span class="n">err_cyl</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">].</span><span class="nb">max</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> at t = </span><span class="si">{</span><span class="n">T_NORM</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">][</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">err_cyl</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">])]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">; "</span>
      <span class="sa">f</span><span class="s">"at the cutoffs: "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"t=</span><span class="si">{</span><span class="n">t</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">: Meep </span><span class="si">{</span><span class="n">p</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> vs Eq.7 </span><span class="si">{</span><span class="n">th</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">t</span><span class="p">,</span> <span class="n">p</span><span class="p">,</span> <span class="n">th</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">[</span><span class="n">cutoff</span><span class="p">],</span> <span class="n">purcell_cyl</span><span class="p">[</span><span class="n">cutoff</span><span class="p">],</span> <span class="n">theory</span><span class="p">[</span><span class="n">cutoff</span><span class="p">])))</span>

<span class="n">t_a</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">bulk_3d</span><span class="p">,</span> <span class="n">t_bulk_3d</span> <span class="o">=</span> <span class="n">ldos_3d</span><span class="p">()</span>
<span class="n">purcell_3d</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">T_3D</span><span class="p">:</span>
    <span class="n">ldos</span><span class="p">,</span> <span class="n">t_end</span> <span class="o">=</span> <span class="n">ldos_3d</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_CAV</span><span class="p">)</span>
    <span class="n">purcell_3d</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">ldos</span> <span class="o">/</span> <span class="n">bulk_3d</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"A (3D, res </span><span class="si">{</span><span class="n">RES_3D</span><span class="si">}</span><span class="s">): bulk LDOS </span><span class="si">{</span><span class="n">bulk_3d</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">f</span><span class="si">}</span><span class="s"> (t_end </span><span class="si">{</span><span class="n">t_bulk_3d</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">); "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"t=</span><span class="si">{</span><span class="n">t</span><span class="si">}</span><span class="s">: 3D </span><span class="si">{</span><span class="n">purcell_3d</span><span class="p">[</span><span class="n">t</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> vs cyl </span><span class="si">{</span><span class="n">purcell_cyl</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">isclose</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">,</span> <span class="n">t</span><span class="p">)][</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> vs Eq.7 </span><span class="si">{</span><span class="n">purcell_theory</span><span class="p">(</span><span class="n">t</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">T_3D</span><span class="p">)</span>
      <span class="o">+</span> <span class="sa">f</span><span class="s">"; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_a</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mf">4.2</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"width_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">1.5</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
<span class="n">tt</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">,</span> <span class="mi">801</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">tt</span><span class="p">,</span> <span class="n">purcell_theory</span><span class="p">(</span><span class="n">tt</span><span class="p">),</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Eq. 7 (Abram 1998)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">,</span> <span class="n">purcell_cyl</span><span class="p">,</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"Meep cylindrical (Er, m = -1), res </span><span class="si">{</span><span class="n">RES_CYL</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">T_3D</span><span class="p">),</span> <span class="p">[</span><span class="n">purcell_3d</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">T_3D</span><span class="p">],</span> <span class="s">"s"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"Meep 3D (Ex), res </span><span class="si">{</span><span class="n">RES_3D</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">tc</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="n">tc</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="mf">2.3</span><span class="p">,</span> <span class="mf">1.03</span><span class="p">,</span> <span class="s">"bulk"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"normalized cavity thickness t = n L / wavelength"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"Purcell factor  LDOS(cavity) / LDOS(bulk)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"in-plane dipole between two lossless mirrors (n = 2.4): a new mode opens at every half-integer"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="mf">3.2</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">],</span> <span class="mi">100</span> <span class="o">*</span> <span class="n">err_cyl</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.07</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"cylindrical"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">[</span><span class="n">cutoff</span><span class="p">],</span> <span class="mi">100</span> <span class="o">*</span> <span class="n">err_cyl</span><span class="p">[</span><span class="n">cutoff</span><span class="p">],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.07</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lightgray"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"at a cutoff (excluded)"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">T_3D</span><span class="p">:</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="mi">100</span> <span class="o">*</span> <span class="nb">abs</span><span class="p">(</span><span class="n">purcell_3d</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">-</span> <span class="n">purcell_theory</span><span class="p">(</span><span class="n">t</span><span class="p">))</span> <span class="o">/</span> <span class="n">purcell_theory</span><span class="p">(</span><span class="n">t</span><span class="p">),</span> <span class="s">"s"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"t"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"|Meep - Eq. 7| / Eq. 7  [%]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"error: median </span><span class="si">{</span><span class="mi">100</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">median</span><span class="p">(</span><span class="n">err_cyl</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">])</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> % away from cutoffs"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_purcell.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">5.2</span><span class="p">))</span>
<span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">t</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">)):</span>
    <span class="n">fld</span><span class="p">,</span> <span class="n">L</span> <span class="o">=</span> <span class="n">fields</span><span class="p">[</span><span class="n">t</span><span class="p">]</span>
    <span class="c1"># NOTE: in cylindrical coordinates get_dft_array / get_array return (z, r), not (r, z): no transpose here
</span>    <span class="n">fld</span> <span class="o">=</span> <span class="n">fld</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="p">:]</span>                                      <span class="c1"># drop the two grid rows touching each mirror (boundary pixels of the DFT array)
</span>    <span class="n">nz</span> <span class="o">=</span> <span class="n">fld</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="n">dz</span> <span class="o">=</span> <span class="n">L</span> <span class="o">/</span> <span class="p">(</span><span class="n">nz</span> <span class="o">+</span> <span class="mi">4</span><span class="p">)</span>
    <span class="n">ext</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">BULK_CYL</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">dz</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">dz</span><span class="p">]</span>
    <span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">percentile</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fld</span><span class="p">),</span> <span class="mf">99.5</span><span class="p">))</span>           <span class="c1"># the source pixel dominates the maximum: clip the colour scale
</span>    <span class="n">a</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">fld</span><span class="p">),</span> <span class="n">extent</span><span class="o">=</span><span class="n">ext</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"auto"</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">2</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">2</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"Re(Er) at t = </span><span class="si">{</span><span class="n">t</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> (L = </span><span class="si">{</span><span class="n">L</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> um): F = </span><span class="si">{</span><span class="n">purcell_cyl</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">isclose</span><span class="p">(</span><span class="n">T_NORM</span><span class="p">,</span> <span class="n">t</span><span class="p">)][</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">   (thick black lines = mirrors)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"z [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"r [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"part A: steady-state field between the mirrors, cylindrical r-z plane"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_cavity_field.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># GIF: a short pulse between the mirrors at t = 1.0 (r-z plane)
</span><span class="n">L</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_CAV</span>
<span class="n">fw_anim</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">FCEN</span>
<span class="n">sim_g</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_CYL</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">BULK_CYL</span> <span class="o">+</span> <span class="n">DPML</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">L</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">)],</span>
                      <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span> <span class="n">default_material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_CAV</span><span class="p">),</span>
                      <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw_anim</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))])</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">vol_g</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">BULK_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">BULK_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">L</span><span class="p">))</span>
<span class="n">t0g</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="n">fw_anim</span>
<span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_g</span><span class="p">,</span> <span class="n">vol_g</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t0g</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">fw_anim</span><span class="p">,</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t0g</span> <span class="o">+</span> <span class="mf">1.1</span> <span class="o">*</span> <span class="n">BULK_CYL</span> <span class="o">*</span> <span class="n">N_CAV</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">frames</span> <span class="o">=</span> <span class="p">[</span><span class="n">f</span><span class="p">.</span><span class="n">T</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">frames</span><span class="p">]</span>                      <span class="c1"># cylindrical get_array returns (z, r); animate_fields expects (x, y) = (r, z)
</span><span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">BULK_CYL</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">],</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"06_anim_planar.gif"</span><span class="p">),</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">7.5</span><span class="p">,</span> <span class="mf">2.8</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"auto"</span><span class="p">,</span>
               <span class="n">component</span><span class="o">=</span><span class="s">"Er"</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">,</span> <span class="n">xlabel</span><span class="o">=</span><span class="s">"r [um]"</span><span class="p">,</span> <span class="n">ylabel</span><span class="o">=</span><span class="s">"z [um] (stretched)"</span><span class="p">,</span> <span class="n">clip_percentile</span><span class="o">=</span><span class="mf">99.0</span><span class="p">,</span>
               <span class="n">lines</span><span class="o">=</span><span class="p">[((</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">),</span> <span class="p">(</span><span class="n">BULK_CYL</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">),</span> <span class="s">"k"</span><span class="p">,</span> <span class="s">"mirrors (cell walls)"</span><span class="p">),</span> <span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">),</span> <span class="p">(</span><span class="n">BULK_CYL</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">),</span> <span class="s">"k"</span><span class="p">,</span> <span class="s">"_nolegend_"</span><span class="p">)],</span>
               <span class="n">points</span><span class="o">=</span><span class="p">[(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"dipole"</span><span class="p">)],</span> <span class="n">title</span><span class="o">=</span><span class="s">"planar cavity, t = 1.0"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"upper right"</span><span class="p">)</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="c1"># =================================================================== B. metal box with an aperture (2D), official metal-cavity-ldos.py
</span><span class="n">RES_M</span> <span class="o">=</span> <span class="mi">50</span>
<span class="n">A_BOX</span><span class="p">,</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">DPML_M</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">1.0</span>
<span class="n">SXY</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML_M</span>
<span class="n">FCEN_M</span> <span class="o">=</span> <span class="n">math</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> <span class="o">/</span> <span class="n">A_BOX</span>                      <span class="c1"># fundamental mode of the closed a x a box
</span><span class="n">DF_M</span> <span class="o">=</span> <span class="mf">0.2</span>
<span class="n">WS</span> <span class="o">=</span> <span class="p">(</span><span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">)</span>
<span class="n">T_MAX</span> <span class="o">=</span> <span class="mf">6000.0</span>                                        <span class="c1"># cap on the dft_ldos run (the official 2Q/f is not capped)
</span><span class="n">V_MODE</span> <span class="o">=</span> <span class="mf">0.25</span> <span class="o">*</span> <span class="n">A_BOX</span> <span class="o">**</span> <span class="mi">2</span>                            <span class="c1"># modal volume of the fundamental mode, analytic
</span>

<span class="k">def</span> <span class="nf">metal_box</span><span class="p">(</span><span class="n">w</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">A_BOX</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">A_BOX</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">metal</span><span class="p">),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">A_BOX</span><span class="p">,</span> <span class="n">A_BOX</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">A_BOX</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">T_WALL</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">)]</span>     <span class="c1"># the aperture in the right wall
</span>

<span class="k">def</span> <span class="nf">make_sim</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">sources</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SXY</span><span class="p">,</span> <span class="n">SXY</span><span class="p">),</span> <span class="n">geometry</span><span class="o">=</span><span class="n">metal_box</span><span class="p">(</span><span class="n">w</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML_M</span><span class="p">)],</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span>
                         <span class="n">symmetries</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES_M</span><span class="p">)</span>


<span class="n">src_M</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_M</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">DF_M</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())]</span>
<span class="n">sim_lay</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">src_M</span><span class="p">)</span>
<span class="n">sim_lay</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">FCEN_M</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="n">annotated_layout</span><span class="p">(</span><span class="n">sim_lay</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML_M</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">6.4</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span>
                 <span class="n">title</span><span class="o">=</span><span class="s">"part B: metal box 1 x 1 um, wall 0.1, aperture w = 0.3 (plot2D draws mp.metal white)"</span><span class="p">,</span>
                 <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"a=</span><span class="si">{</span><span class="n">A_BOX</span><span class="si">}</span><span class="s">, t=</span><span class="si">{</span><span class="n">T_WALL</span><span class="si">}</span><span class="s">, res=</span><span class="si">{</span><span class="n">RES_M</span><span class="si">}</span><span class="se">\n</span><span class="s">fcen=sqrt(0.5)/a=</span><span class="si">{</span><span class="n">FCEN_M</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">1.9</span><span class="p">,</span> <span class="mf">1.75</span><span class="p">),</span>
                 <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">1.9</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.5</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
                 <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"Ez dipole at the center: Harminv probe and dft_ldos point"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">1.9</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                         <span class="n">Label</span><span class="p">(</span><span class="s">"metal walls (mp.metal)"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.55</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">1.9</span><span class="p">,</span> <span class="mf">0.75</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                         <span class="n">Label</span><span class="p">(</span><span class="s">"aperture w: the only leak"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.75</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.9</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                         <span class="n">Label</span><span class="p">(</span><span class="s">"DFT Ez map (representative)"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.9</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.9</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">1.9</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
<span class="n">sim_lay</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="n">res_M</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">t_b</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">WS</span><span class="p">:</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">src_M</span><span class="p">)</span>
    <span class="n">h</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Harminv</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">FCEN_M</span><span class="p">,</span> <span class="n">DF_M</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">after_sources</span><span class="p">(</span><span class="n">h</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span>
    <span class="n">modes</span> <span class="o">=</span> <span class="p">[</span><span class="n">m</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">h</span><span class="p">.</span><span class="n">modes</span> <span class="k">if</span> <span class="n">m</span><span class="p">.</span><span class="n">Q</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">]</span>
    <span class="n">m</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">modes</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">mm</span><span class="p">:</span> <span class="n">mm</span><span class="p">.</span><span class="n">Q</span><span class="p">)</span>
    <span class="n">f</span><span class="p">,</span> <span class="n">Q</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">freq</span><span class="p">),</span> <span class="nb">float</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">Q</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">ldos_qv</span> <span class="o">=</span> <span class="n">Q</span> <span class="o">/</span> <span class="n">V_MODE</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">f</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="mf">0.5</span><span class="p">)</span>          <span class="c1"># 2Q / (pi w V), w = 2 pi f
</span>    <span class="n">T_req</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">Q</span> <span class="o">/</span> <span class="n">f</span>
    <span class="n">T_run</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">T_req</span><span class="p">,</span> <span class="n">T_MAX</span><span class="p">)</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">src_M</span><span class="p">)</span>
    <span class="n">nfreq</span> <span class="o">=</span> <span class="mi">101</span>
    <span class="n">df_spec</span> <span class="o">=</span> <span class="mi">8</span> <span class="o">*</span> <span class="n">f</span> <span class="o">/</span> <span class="n">Q</span>                                               <span class="c1"># spectrum: +-4 linewidths around the Harminv frequency
</span>    <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">f</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> <span class="k">if</span> <span class="n">w</span> <span class="o">==</span> <span class="mf">0.3</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">df_spec</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">T_run</span><span class="p">)</span>
    <span class="n">freqs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_freqs</span> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="s">"ldos_freqs"</span><span class="p">)</span> <span class="k">else</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">f</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">df_spec</span><span class="p">,</span> <span class="n">f</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">df_spec</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">))</span>
    <span class="n">spec</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_data</span><span class="p">)</span>
    <span class="n">ez</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="k">if</span> <span class="n">dft</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">ldos_f</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">spec</span><span class="p">[</span><span class="n">nfreq</span> <span class="o">//</span> <span class="mi">2</span><span class="p">])</span>
    <span class="n">half</span> <span class="o">=</span> <span class="n">spec</span> <span class="o">&gt;=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">spec</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span>
    <span class="n">fwhm</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">freqs</span><span class="p">[</span><span class="n">half</span><span class="p">].</span><span class="nb">max</span><span class="p">()</span> <span class="o">-</span> <span class="n">freqs</span><span class="p">[</span><span class="n">half</span><span class="p">].</span><span class="nb">min</span><span class="p">())</span> <span class="k">if</span> <span class="n">half</span><span class="p">.</span><span class="nb">sum</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">else</span> <span class="nb">float</span><span class="p">(</span><span class="s">"nan"</span><span class="p">)</span>
    <span class="n">res_M</span><span class="p">[</span><span class="n">w</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"f"</span><span class="p">:</span> <span class="n">f</span><span class="p">,</span> <span class="s">"Q"</span><span class="p">:</span> <span class="n">Q</span><span class="p">,</span> <span class="s">"ldos_qv"</span><span class="p">:</span> <span class="n">ldos_qv</span><span class="p">,</span> <span class="s">"ldos_dft"</span><span class="p">:</span> <span class="n">ldos_f</span><span class="p">,</span> <span class="s">"T_req"</span><span class="p">:</span> <span class="n">T_req</span><span class="p">,</span> <span class="s">"T_run"</span><span class="p">:</span> <span class="n">T_run</span><span class="p">,</span> <span class="s">"converged"</span><span class="p">:</span> <span class="n">T_run</span> <span class="o">&gt;=</span> <span class="n">T_req</span><span class="p">,</span>
                <span class="s">"spec_f"</span><span class="p">:</span> <span class="n">freqs</span><span class="p">,</span> <span class="s">"spec"</span><span class="p">:</span> <span class="n">spec</span><span class="p">,</span> <span class="s">"fwhm"</span><span class="p">:</span> <span class="n">fwhm</span><span class="p">,</span> <span class="s">"Q_spec"</span><span class="p">:</span> <span class="n">f</span> <span class="o">/</span> <span class="n">fwhm</span> <span class="k">if</span> <span class="n">fwhm</span> <span class="o">==</span> <span class="n">fwhm</span> <span class="k">else</span> <span class="nb">float</span><span class="p">(</span><span class="s">"nan"</span><span class="p">),</span> <span class="s">"ez"</span><span class="p">:</span> <span class="n">ez</span><span class="p">}</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"B [w = </span><span class="si">{</span><span class="n">w</span><span class="si">}</span><span class="s">]: Harminv f </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">f</span><span class="si">}</span><span class="s">, Q </span><span class="si">{</span><span class="n">Q</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">; 2Q/f = </span><span class="si">{</span><span class="n">T_req</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> -&gt; ran </span><span class="si">{</span><span class="n">T_run</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}{</span><span class="s">''</span> <span class="k">if</span> <span class="n">T_run</span> <span class="o">&gt;=</span> <span class="n">T_req</span> <span class="k">else</span> <span class="s">' (CAPPED, under-converged)'</span><span class="si">}</span><span class="s">; "</span>
          <span class="sa">f</span><span class="s">"LDOS: Q/V estimate </span><span class="si">{</span><span class="n">ldos_qv</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, dft_ldos </span><span class="si">{</span><span class="n">ldos_f</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, ratio </span><span class="si">{</span><span class="n">ldos_f</span> <span class="o">/</span> <span class="n">ldos_qv</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">; spectrum FWHM </span><span class="si">{</span><span class="n">fwhm</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">e</span><span class="si">}</span><span class="s"> -&gt; Q </span><span class="si">{</span><span class="n">f</span> <span class="o">/</span> <span class="n">fwhm</span> <span class="k">if</span> <span class="n">fwhm</span> <span class="o">==</span> <span class="n">fwhm</span> <span class="k">else</span> <span class="nb">float</span><span class="p">(</span><span class="s">'nan'</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"B done in </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_b</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">13.5</span><span class="p">,</span> <span class="mf">4.4</span><span class="p">))</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">for</span> <span class="n">w</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">WS</span><span class="p">,</span> <span class="p">(</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="s">"tab:orange"</span><span class="p">,</span> <span class="s">"tab:green"</span><span class="p">,</span> <span class="s">"tab:blue"</span><span class="p">)):</span>
    <span class="n">r</span> <span class="o">=</span> <span class="n">res_M</span><span class="p">[</span><span class="n">w</span><span class="p">]</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">((</span><span class="n">r</span><span class="p">[</span><span class="s">"spec_f"</span><span class="p">]</span> <span class="o">-</span> <span class="n">r</span><span class="p">[</span><span class="s">"f"</span><span class="p">])</span> <span class="o">/</span> <span class="n">r</span><span class="p">[</span><span class="s">"f"</span><span class="p">]</span> <span class="o">*</span> <span class="mf">1e3</span><span class="p">,</span> <span class="n">r</span><span class="p">[</span><span class="s">"spec"</span><span class="p">]</span> <span class="o">/</span> <span class="n">r</span><span class="p">[</span><span class="s">"spec"</span><span class="p">].</span><span class="nb">max</span><span class="p">(),</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">c</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.4</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"w = </span><span class="si">{</span><span class="n">w</span><span class="si">}</span><span class="s">: Q_Harminv </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'Q'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">, Q_spectrum </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'Q_spec'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="o">+</span> <span class="p">(</span><span class="s">""</span> <span class="k">if</span> <span class="n">r</span><span class="p">[</span><span class="s">"converged"</span><span class="p">]</span> <span class="k">else</span> <span class="s">" (capped)"</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"(f - f_res) / f_res  [x 1e-3]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"LDOS / peak"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"dft_ldos spectrum around the resonance: width = f / Q"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">inv_w</span> <span class="o">=</span> <span class="p">[</span><span class="n">A_BOX</span> <span class="o">/</span> <span class="n">w</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">WS</span><span class="p">]</span>
<span class="n">ax</span><span class="p">.</span><span class="n">semilogy</span><span class="p">(</span><span class="n">inv_w</span><span class="p">,</span> <span class="p">[</span><span class="n">res_M</span><span class="p">[</span><span class="n">w</span><span class="p">][</span><span class="s">"ldos_qv"</span><span class="p">]</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">WS</span><span class="p">],</span> <span class="s">"bo-"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"2Q / (pi w V)  (Harminv Q, analytic V)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">semilogy</span><span class="p">(</span><span class="n">inv_w</span><span class="p">,</span> <span class="p">[</span><span class="n">res_M</span><span class="p">[</span><span class="n">w</span><span class="p">][</span><span class="s">"ldos_dft"</span><span class="p">]</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">WS</span><span class="p">],</span> <span class="s">"rs-"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"dft_ldos at f_res"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">WS</span><span class="p">:</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">res_M</span><span class="p">[</span><span class="n">w</span><span class="p">][</span><span class="s">"converged"</span><span class="p">]:</span>
        <span class="n">ax</span><span class="p">.</span><span class="n">annotate</span><span class="p">(</span><span class="s">"under-converged</span><span class="se">\n</span><span class="s">(run capped)"</span><span class="p">,</span> <span class="p">(</span><span class="n">A_BOX</span> <span class="o">/</span> <span class="n">w</span><span class="p">,</span> <span class="n">res_M</span><span class="p">[</span><span class="n">w</span><span class="p">][</span><span class="s">"ldos_dft"</span><span class="p">]),</span> <span class="n">textcoords</span><span class="o">=</span><span class="s">"offset points"</span><span class="p">,</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mi">70</span><span class="p">,</span> <span class="o">-</span><span class="mi">28</span><span class="p">),</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">arrowstyle</span><span class="o">=</span><span class="s">"-&gt;"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"a / w"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"LDOS at the resonance"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"narrower aperture: higher Q, higher LDOS"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">"both"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">ez</span> <span class="o">=</span> <span class="n">res_M</span><span class="p">[</span><span class="mf">0.3</span><span class="p">][</span><span class="s">"ez"</span><span class="p">];</span> <span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">percentile</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez</span><span class="p">),</span> <span class="mf">96.0</span><span class="p">))</span>     <span class="c1"># clip: the source pixel dominates, and 3/4 of the map is outside the box
</span><span class="n">ax</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ez</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Rectangle</span><span class="p">((</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">));</span> <span class="n">ax</span><span class="p">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Rectangle</span><span class="p">((</span><span class="mf">0.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.15</span><span class="p">),</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"Re(Ez) at f_res, w = 0.3: fundamental mode sin(pi x/a) sin(pi y/a)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"part B: a point dipole in a metal box with one aperture"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">(</span><span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.93</span><span class="p">]);</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_metal_ldos.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># GIF: the box rings and leaks through the aperture (w = 0.4, monitor-free)
</span><span class="n">sim_g</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_M</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FCEN_M</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())])</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">vol_g</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="n">eps_g</span> <span class="o">=</span> <span class="n">sim_g</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">vol_g</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">eps_g</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">isfinite</span><span class="p">(</span><span class="n">eps_g</span><span class="p">),</span> <span class="n">eps_g</span><span class="p">,</span> <span class="mf">100.0</span><span class="p">)</span>
<span class="n">t0g</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FCEN_M</span><span class="p">)</span>
<span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_g</span><span class="p">,</span> <span class="n">vol_g</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t0g</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FCEN_M</span><span class="p">),</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t0g</span> <span class="o">+</span> <span class="mi">40</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"07_anim_metal.gif"</span><span class="p">),</span> <span class="n">eps</span><span class="o">=</span><span class="n">eps_g</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.4</span><span class="p">,</span> <span class="mf">4.8</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span> <span class="n">clip_percentile</span><span class="o">=</span><span class="mf">99.0</span><span class="p">,</span>
               <span class="n">points</span><span class="o">=</span><span class="p">[(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"dipole"</span><span class="p">)],</span> <span class="n">lines</span><span class="o">=</span><span class="p">[((</span><span class="mf">0.6</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.2</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">),</span> <span class="s">"blue"</span><span class="p">,</span> <span class="s">"aperture w = 0.4"</span><span class="p">)],</span> <span class="n">title</span><span class="o">=</span><span class="s">"metal box"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="k">if</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">():</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f_</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"A"</span><span class="p">:</span> <span class="p">{</span><span class="s">"wl"</span><span class="p">:</span> <span class="n">WL</span><span class="p">,</span> <span class="s">"n"</span><span class="p">:</span> <span class="n">N_CAV</span><span class="p">,</span> <span class="s">"res_cyl"</span><span class="p">:</span> <span class="n">RES_CYL</span><span class="p">,</span> <span class="s">"res_3d"</span><span class="p">:</span> <span class="n">RES_3D</span><span class="p">,</span> <span class="s">"t"</span><span class="p">:</span> <span class="n">T_NORM</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"purcell_cyl"</span><span class="p">:</span> <span class="n">purcell_cyl</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"theory"</span><span class="p">:</span> <span class="n">theory</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span>
                         <span class="s">"err_cyl"</span><span class="p">:</span> <span class="n">err_cyl</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"cutoff"</span><span class="p">:</span> <span class="n">cutoff</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"median_err_away"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">median</span><span class="p">(</span><span class="n">err_cyl</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">])),</span> <span class="s">"max_err_away"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">err_cyl</span><span class="p">[</span><span class="o">~</span><span class="n">cutoff</span><span class="p">].</span><span class="nb">max</span><span class="p">()),</span>
                         <span class="s">"bulk_cyl"</span><span class="p">:</span> <span class="n">bulk_cyl</span><span class="p">,</span> <span class="s">"bulk_3d"</span><span class="p">:</span> <span class="n">bulk_3d</span><span class="p">,</span> <span class="s">"purcell_3d"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="n">k</span><span class="p">):</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">purcell_3d</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span> <span class="s">"t_end_cyl"</span><span class="p">:</span> <span class="p">[</span><span class="nb">float</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">t_end_cyl</span><span class="p">]},</span>
                   <span class="s">"B"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="n">w</span><span class="p">):</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">v</span><span class="p">.</span><span class="n">tolist</span><span class="p">()</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">ndarray</span><span class="p">)</span> <span class="k">else</span> <span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">r</span><span class="p">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">k</span> <span class="o">!=</span> <span class="s">"ez"</span><span class="p">}</span> <span class="k">for</span> <span class="n">w</span><span class="p">,</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">res_M</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">},</span> <span class="n">f_</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"total </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span></code></pre></figure>

</details>

<details>
  <summary>원본 실행 기록과 재현 환경</summary>

  <p>§4의 발췌 코드와 달리 전체 코드에는 cylindrical 설계도, r–z field 그림, 스펙트럼 그림, GIF 두 개, result.json 기록이 들어 있다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

  <p><strong>실행 결과 (2026-10-23 실행)</strong>:</p>
  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A (cyl): bulk LDOS 0.41625 (t_end 80); 21 thicknesses in 138 s; rel error vs Eq. 7 away from cutoffs: median 0.0094, max 0.0360 at t = 0.70; at the cutoffs: t=0.5: Meep 3.018 vs Eq.7 3.000, t=1.5: Meep 0.507 vs Eq.7 1.556, t=2.5: Meep 1.172 vs Eq.7 1.320
A (3D, res 48): bulk LDOS 3.22287 (t_end 80); t=1.0: 3D 0.9330 vs cyl 0.9120 vs Eq.7 0.9375, t=2.0: 3D 0.9788 vs cyl 0.9879 vs Eq.7 0.9844; 127 s
B [w = 0.2]: Harminv f 0.67403, Q 8060; 2Q/f = 23915 -&gt; ran 6000 (CAPPED, under-converged); LDOS: Q/V estimate 4846.1525, dft_ldos 3499.1119, ratio 0.722; spectrum FWHM 1.20e-04 -&gt; Q 5597
B [w = 0.3]: Harminv f 0.66875, Q 1271; 2Q/f = 3802 -&gt; ran 3802; LDOS: Q/V estimate 770.3846, dft_ldos 685.5049, ratio 0.890; spectrum FWHM 5.05e-04 -&gt; Q 1324
B [w = 0.4]: Harminv f 0.65692, Q 189; 2Q/f = 574 -&gt; ran 574; LDOS: Q/V estimate 116.3766, dft_ldos 98.4505, ratio 0.846; spectrum FWHM 3.34e-03 -&gt; Q 196
B [w = 0.5]: Harminv f 0.64648, Q 74; 2Q/f = 230 -&gt; ran 230; LDOS: Q/V estimate 46.6641, dft_ldos 37.5608, ratio 0.805; spectrum FWHM 8.34e-03 -&gt; Q 78
B done in 118 s
total 396 s
</code></pre></div>  </div>

  <p><strong>재현 환경</strong>: meep 1.33.0 · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep</code> · 실행 <code class="language-plaintext highlighter-rouge">python cavity_ldos.py</code> (약 6.6 min, 단일 코어)</p>

</details>

<h3 id="공식-문서와-다음-글">공식 문서와 다음 글</h3>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Local_Density_of_States/">Local density of states 튜토리얼</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/planar_cavity_ldos.py">planar_cavity_ldos.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/metal-cavity-ldos.py">metal-cavity-ldos.py</a></li>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#ldos-spectra"><code class="language-plaintext highlighter-rouge">dft_ldos</code> 레퍼런스</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#harminv"><code class="language-plaintext highlighter-rouge">Harminv</code></a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Cylindrical_Coordinates/">cylindrical coordinates</a></li>
  <li>I. Abram et al., “Spontaneous emission control in semiconductor microcavities with metallic or Bragg mirrors,” IEEE J. Quantum Electron. 34, 71 (1998)</li>
  <li>이전 글: <a href="/meep-examples/dipole-pattern-3d/">10 · 점광원의 3D 방사 패턴</a> · 다음 글: <a href="/meep-examples/ring-resonator/">12 · 빛을 가두는 고리</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="ldos" /><category term="purcell" /><category term="cavity" /><category term="harminv" /><category term="dft_ldos" /><category term="cylindrical" /><summary type="html"><![CDATA[post 10 put one mirror next to a dipole and the pattern changed. Here the dipole sits between two mirrors and the question is the emitted power itself. Meep measures it as the local density of states (LDOS) at the source point with `dft_ldos`. Part A: an in-plane dipole in a dielectric slab (n = 2.4) between two lossless metallic mirrors, the Purcell factor F = LDOS(cavity)/LDOS(bulk) versus the normalized thickness t = nL/λ, swept in cylindrical coordinates and checked in 3D. Part B: a dipole in a 2D metal box with one aperture, where the LDOS at resonance is compared with the single-mode estimate 2Q/(πωV).]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/11/03_purcell.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/11/03_purcell.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 13 · 회전 대칭으로 3D를 계산하기 — cylindrical 좌표, m 급수, on/off-axis 쌍극자, 디스크 방사</title><link href="https://jin-castle.github.io/meep-examples/cylindrical-dipole/" rel="alternate" type="text/html" title="Meep Example 13 · 회전 대칭으로 3D를 계산하기 — cylindrical 좌표, m 급수, on/off-axis 쌍극자, 디스크 방사" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/cylindrical-dipole</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/cylindrical-dipole/"><![CDATA[<h2 id="observe">1. 먼저 보기: 축에서 벗어난 점광원은 몇 번 계산해야 할까?</h2>

<p>회전 대칭인 구조를 계산할 때도 source까지 항상 축 대칭인 것은 아닙니다. 축에서 0.5 µm 떨어진 점광원 하나를 표현하려면, 방위 차수 <strong>m을 바꾸어 여러 번 계산한 field를 합쳐야</strong> 합니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/04_off_axis.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/04_off_axis.png" alt="축에서 0.5 마이크로미터 떨어진 쌍극자의 m별 power와 부분합 패턴 오차 및 최종 방사 패턴" /></a>
<figcaption>실제 계산에서 m = 0…8까지 포함했고 마지막 항의 power는 최대의 9.49 × 10⁻⁶입니다. φ = 0 단면의 정규화 패턴은 해석 cos²θ와 상대 L2 오차 0.63%로 맞았습니다.</figcaption>
</figure>

<p class="lesson-note"><strong>부분합이 매번 좋아지는 것은 아닙니다.</strong> m = 0…2의 패턴 오차는 0.099였지만 m = 3을 더하면 0.141로 잠시 증가했습니다. 모양이 좋아 보이는 중간 결과에서 멈추지 말고, m별 power와 패턴을 함께 확인합니다. 다른 구조나 더 먼 source에서는 power가 한 번 작아진 뒤 다시 커질 수도 있습니다.</p>

<h2 id="predict">2. 먼저 예측하기: 회전 대칭 구조면 m = 0만 있으면 될까?</h2>

<fieldset class="prediction">
<legend>축 위에서 x 방향으로 진동하는 선편광 쌍극자를 표현하려면?</legend>
<label><input type="radio" name="cylindrical-prediction" value="zero" /> 구조가 회전 대칭이므로 m = 0 한 번이면 된다.</label>
<label><input type="radio" name="cylindrical-prediction" value="pair" /> source의 방향을 표현하는 m = +1과 −1이 필요하다.</label>
</fieldset>

<details>
  <summary>예측과 source 표현 비교하기</summary>

  <p>두 번째입니다. 구조가 회전 대칭이어도 x 방향은 방위각 φ에 따라 원통좌표의 r·φ 성분이 달라집니다. 이 예제는 m = +1과 −1에서 Er와 ±i Ep를 사용하고 두 field를 반씩 더합니다. 축 위의 z 방향 쌍극자는 m = 0 한 번으로 표현합니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기: 방위각을 m으로 나누어 계산하기</h2>

<p>구조가 φ에 무관하면 field를 <strong>E(r, φ, z) = Σ E_m(r, z) exp(imφ)</strong>로 쓸 수 있습니다. m 하나를 고르면 φ 미분은 im을 곱하는 것으로 바뀌고, Meep은 남은 r–z 단면을 계산합니다. 3D 공간의 효과를 버리는 것이 아니라 방위각 의존성을 별도로 표현하는 방법입니다.</p>

<figure class="lesson-figure">
<svg viewBox="0 0 320 220" role="img" aria-labelledby="cylindrical-concept-title" xmlns="http://www.w3.org/2000/svg">
<title id="cylindrical-concept-title">설명용 도식: 회전 대칭 구조의 r-z 단면을 방위 차수별로 계산하고 field를 합산한다</title>
<rect width="320" height="220" fill="#f5f8fa" />
<path d="M35 142V36M35 142H149M35 36l-5 11M35 36l5 11M149 142l-11-5M149 142l-11 5" stroke="#0d1b2a" fill="none" stroke-width="2" />
<rect x="36" y="77" width="70" height="45" fill="#e7f7fb" stroke="#0087ad" stroke-width="2" />
<circle cx="70" cy="98" r="6" fill="#0087ad" />
<path d="M172 87H290M290 87l-11-5M290 87l-11 5" stroke="#0087ad" fill="none" stroke-width="2" />
<g font-family="sans-serif" font-size="16" fill="#0d1b2a">
<text x="20" y="28">z</text><text x="143" y="165">r</text>
<text x="174" y="55">m마다 한 run</text>
<text x="171" y="115">exp(imφ) 반영</text>
<text x="31" y="186">r–z 단면 + 방위각 의존성</text>
<text x="31" y="209">field 합산 → 방향별 패턴</text>
</g>
</svg>
<figcaption>설명용 도식입니다. 사각형은 회전 대칭 구조의 단면, 점은 source 위치의 예시입니다. 색과 화살표는 실제 수치 field가 아닙니다. 각 m의 계산 결과에 방위각 의존성을 반영해 필요한 field를 구성합니다.</figcaption>
</figure>

<table>
  <thead>
    <tr>
      <th>source 또는 문제</th>
      <th>필요한 표현</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>축 위 z 쌍극자</td>
      <td>m = 0, Ez</td>
    </tr>
    <tr>
      <td>축 위 x 쌍극자</td>
      <td>m = +1과 −1, Er와 ±i Ep</td>
    </tr>
    <tr>
      <td>축 밖 점광원</td>
      <td>여러 m의 Fourier 급수</td>
    </tr>
    <tr>
      <td>정해진 방위 차수의 고리 모드</td>
      <td>해당 m 하나로 계산</td>
    </tr>
  </tbody>
</table>

<p><strong>패턴은 field를 더한 뒤 power를 구합니다.</strong> φ = 0 단면에서 m별 power만 더하면 항 사이의 간섭이 사라집니다. 반면 전체 방위각에 걸쳐 적분한 총 power는 서로 다른 m의 직교성 때문에 항별 power를 더할 수 있습니다. 이 예제는 m 항의 power가 최대값의 10⁻⁴ 아래인지로 급수 중단을 판단합니다.</p>

<p>이 중단 규칙은 여기의 진공 r₀ = 0.5 µm 예제에 대한 기준입니다. 더 먼 source나 구조가 있는 문제에서 <strong>처음으로 작은 항 하나</strong>를 발견했다고 이후의 모든 항이 작다고 보장할 수는 없습니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/07_anim_m3.gif" data-lightbox=""><img src="/meep-examples/assets/meep/13/07_anim_m3.gif" data-animation-src="/meep-examples/assets/meep/13/07_anim_m3.gif" data-static-src="/meep-examples/assets/meep/13/05_ring_cyl.png" alt="계산된 고리의 m=3 반지름 field에 방위각과 시간 위상을 반영해 복원한 회전 모드" /></a>
<button type="button" class="animation-toggle" hidden="">애니메이션 정지</button>
<figcaption>실제로 계산한 Ez(r)에 exp[i(3φ−ωt)]를 적용한 위상 복원 애니메이션입니다. 새로운 시간영역 3D 시뮬레이션이 아닙니다. m = −3 성분을 함께 구성하면 정상파를 만들 수 있습니다.</figcaption>
</figure>

<p class="lesson-note"><strong>고리 예제의 차원.</strong> 파트 C의 ring-cyl은 셀의 z 크기가 0입니다. 12편의 z로 무한한 2D 고리 문제를 다른 좌표로 푼 것으로, 유한 높이의 실제 3D ring을 검증한 것은 아닙니다. 반면 일반적인 cylindrical r–z 셀은 회전 대칭 3D 구조를 m별로 표현할 수 있습니다.</p>

<p>파트 D의 디스크는 굴절률 2.4, 반지름 1.2 µm이고 아래에 손실 없는 PEC ground plane이 있습니다. m = −1 하나의 ring source를 계산하며, 임의의 off-axis 점광원 전체를 계산한 결과는 아닙니다. ground plane 때문에 near2far 면은 위와 바깥 r만 포함하고 아래는 열려 있습니다.</p>

<h2 id="run">4. 직접 실행하기: m 급수의 중단 기준만 엄격하게 하기</h2>

<p>저장소를 내려받아 <code>code/</code> 폴더에서 실행합니다. <code>cylindrical_dipole.py</code>와 같은 폴더의 <code>blogfig.py</code>가 모두 필요합니다. Meep 1.33.0 MPI 환경과 Python·NumPy·Matplotlib을 사용한 원본 기록은 MPI 4개 프로세스에서 약 7.6분입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">OMP_NUM_THREADS</span><span class="o">=</span>1 mpirun <span class="nt">-np</span> 4 python cylindrical_dipole.py
</code></pre></div></div>

<p>먼저 원본 결과를 별도 폴더에 보관하세요. <strong>POWER_DECAY = 1e-4를 1e-5로만 바꾸고</strong> 같은 명령으로 다시 실행합니다. source 거리, 해상도, 나머지 파트의 설정은 그대로 둡니다.</p>

<p>파트 B 로그의 마지막 m, 마지막 항의 power 비율, 최종 패턴 오차를 비교합니다. 원본 m = 8의 비율은 이미 <strong>9.49e-6</strong>이므로 이 한 단계의 기준 변경만으로 마지막 m이 늘지 않을 수도 있습니다. 이를 미리 실패로 판단하지 말고 실제 종료 기록을 확인하세요. 새 측정값은 원본 0.63%와 구별해 기록합니다.</p>

<h2 id="interpret">5. 결과 해석하기: 무엇이 일치했고 무엇이 남았을까?</h2>

<table>
  <thead>
    <tr>
      <th>원본 비교</th>
      <th>실제 결과</th>
      <th>해석 범위</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>축 위 z 쌍극자 vs sin²θ</td>
      <td>상대 L2 0.43%</td>
      <td>φ = 0의 정규화 패턴</td>
    </tr>
    <tr>
      <td>축 위 x 쌍극자 vs cos²θ</td>
      <td>상대 L2 0.46%</td>
      <td>m = ±1 field 합산</td>
    </tr>
    <tr>
      <td>축 밖 r₀ = 0.5 µm</td>
      <td>m = 0…8, 상대 L2 0.63%</td>
      <td>이 진공 예제의 급수</td>
    </tr>
    <tr>
      <td>고리 m = 3, 4, 5 주파수</td>
      <td>12편과 약 0.02%, 0.07%, 0.10% 차이</td>
      <td>같은 2D 문제의 좌표계 비교</td>
    </tr>
  </tbody>
</table>

<p>고리 m = 5의 Q는 cylindrical에서 <strong>1627</strong>, 12편 Cartesian 해상도 20에서 <strong>2132</strong>였습니다. 주파수가 가깝다고 Q도 수렴했다고 볼 수 없습니다. 다른 해상도의 Cartesian 값 1675·1610이 cylindrical 쪽에 가깝지만, 이것만으로 차이의 원인을 계단 경계 하나로 확정하지는 않습니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/06_disc.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/06_disc.png" alt="ground plane 위 디스크에서 셀 반지름 6과 8 마이크로미터의 near flux와 far flux 차이 비교" loading="lazy" /></a>
<figcaption>파트 D의 실제 결과입니다. 셀 반지름을 6에서 8 µm로 늘리자 near–far 차이는 7.43%에서 6.41%로 줄었습니다. 아직 차이가 남아 far-field 총 power가 수렴했다고 할 수 없습니다.</figcaption>
</figure>

<table>
  <thead>
    <tr>
      <th>셀 반지름</th>
      <th style="text-align: right">near flux</th>
      <th style="text-align: right">far flux</th>
      <th style="text-align: right">상대 차이</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>6 µm</td>
      <td style="text-align: right">643.65</td>
      <td style="text-align: right">595.80</td>
      <td style="text-align: right">7.43%</td>
    </tr>
    <tr>
      <td>8 µm</td>
      <td style="text-align: right">643.28</td>
      <td style="text-align: right">602.05</td>
      <td style="text-align: right">6.41%</td>
    </tr>
  </tbody>
</table>

<p>near flux는 거의 유지되고 far flux가 증가했습니다. 이는 열린 면 바깥의 등가 전류가 잘리는 truncation 해석과 맞지만, 두 셀 크기만으로 참된 far-field 총 power를 확정하지는 못합니다. <strong>7.43%는 광추출 효율이 아니라 두 power 측정의 불일치</strong>입니다.</p>

<h2 id="check">6. 이해 확인하기</h2>

<ol>
  <li>축 위 x 쌍극자에서 m = 0 한 번으로 충분하지 않은 이유와, 방향별 패턴을 합산하는 순서를 설명해 보세요.</li>
  <li>디스크의 near–far 차이가 7.43%에서 6.41%로 줄었다면, far-field 총 power가 수렴했다고 말할 수 있나요?</li>
</ol>

<details>
  <summary>두 질문의 답 확인하기</summary>

  <ol>
    <li>x 방향의 원통좌표 성분은 φ에 의존하므로 m = +1과 −1이 필요합니다. 필요한 m들의 복소 field를 먼저 더하고 Poynting으로 패턴을 구해야 간섭을 보존합니다.</li>
    <li>아닙니다. 열린 near2far 면의 절단 효과가 줄어드는 해석과 일치할 뿐, 차이가 여전히 남아 있습니다. 더 넓은 면과 추가 수렴 확인 없이 참된 총 power나 광추출 효율로 보고할 수 없습니다.</li>
  </ol>

</details>

<h2 id="reference">7. 참고 자료와 전체 코드</h2>

<p>원본의 상세 물리식, m별 수치, 좌표계별 설정과 전체 실행 기록을 아래에 보관했습니다.</p>

<details>
  <summary>English summary</summary>

  <h3 id="tldr-english">TL;DR (English)</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/04_off_axis.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/04_off_axis.png" alt="원통좌표 계산의 hero 원본 그림" loading="lazy" /></a>
</figure>

  <ul>
    <li><strong>What</strong>: post 12’s ring was a 2D cross-section; real discs, rings, lenses and LED mesas are bodies of revolution. <code class="language-plaintext highlighter-rouge">dimensions=mp.CYLINDRICAL</code> solves them as one 2D (r, z) run per azimuthal order m, with fields ∝ exp(imφ). Four official examples: on-axis dipoles, an off-axis dipole as an m series, post 12’s ring as one radial run per m, and a disc on a ground plane radiating through an open near2far surface.</li>
    <li><strong>Result</strong>: an on-axis z-dipole (m = 0) and x-dipole (m = +1 and −1) reproduce sin²θ and cos²θ to 0.43% and 0.46%. A dipole 0.5 µm off the axis needs m = 0…8 before the last term drops below 10⁻⁴ of the largest; the summed pattern matches cos²θ to 0.63%. The ring’s m = 3, 4, 5 modes land within 0.1% of post 12’s 2D frequencies. The disc radiates 7.43% less in the far field than through the near monitor, 6.41% with a larger radial cell.</li>
    <li><strong>Takeaway</strong>: a linearly polarized in-plane dipole is never m = 0. Every point off the axis is a sum over m, each m a separate run, and power (not field) per m decides when to stop. An open near2far surface on a ground plane loses the currents beyond its edge, and that, not the solver, is the near–far gap.</li>
    <li><strong>Code</strong>: full script at the bottom, ~7.6 min (mpirun -np 4).</li>
  </ul>

</details>

<details>
  <summary>배경·물리식·파라미터 자세히 보기</summary>

  <h3 id="section">원본 §0 · 이 글에서 배우는 것</h3>

  <ul>
    <li><code class="language-plaintext highlighter-rouge">dimensions=mp.CYLINDRICAL</code>과 <code class="language-plaintext highlighter-rouge">m</code>: φ 방향을 계산하지 않고 field를 exp(imφ)로 쓰는 법. 셀은 (r, 0, z)</li>
    <li>축 위 z 쌍극자는 m = 0, x 쌍극자는 m = +1과 −1의 합. 원편광 둘을 더해 선편광을 만든다</li>
    <li>축에서 떨어진 점광원 = m = 0, 1, 2, …의 Fourier 급수. 각 m은 독립된 run이고, m마다의 방사 power로 언제 멈출지 정한다</li>
    <li>12편 고리를 m 하나당 1D 반지름 run으로 다시 풀고 2D 그림을 exp(imφ)로 복원하기</li>
    <li>바닥이 무한한 ground plane이면 near2far 면이 닫히지 않는다. near flux와 far flux의 차이가 무엇을 뜻하는가</li>
  </ul>

  <p><strong>전제 지식</strong>: 10편의 near2far와 방사 패턴, 12편의 방위 차수 m. <strong>공식 예제</strong>: <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Cylindrical_Coordinates/">Cylindrical coordinates 튜토리얼</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/#radiation-pattern-of-an-antenna-in-cylindrical-coordinates">antenna in cylindrical coordinates</a> · 스크립트 <a href="https://github.com/NanoComp/meep/blob/master/python/examples/dipole_in_vacuum_cyl_on_axis.py">dipole_in_vacuum_cyl_on_axis.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/dipole_in_vacuum_cyl_off_axis.py">dipole_in_vacuum_cyl_off_axis.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/ring-cyl.py">ring-cyl.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/disc_radiation_pattern.py">disc_radiation_pattern.py</a>. <strong>이전 글</strong>: <a href="/meep-examples/ring-resonator/">12 · 빛을 가두는 고리</a> · <strong>다음 글</strong>: 14 · 박막 속 점광원, 공기로 나오는 몫</p>

  <h3 id="section-1">원본 §1 · 무엇을 알고 싶은가</h3>

  <p>12편 끝 질문이었다. 고리는 2D 단면이었지만 실제 마이크로디스크, 렌즈, LED 메사는 축을 중심으로 돌려 만든 3D 구조다. 이런 구조를 3D 셀로 풀면 격자가 세제곱으로 늘어난다. 구조가 φ에 무관하면 field의 φ 의존성은 exp(imφ)의 합으로 쓸 수 있고, m이 정해지면 남는 것은 (r, z) 두 좌표뿐이다. 3D 문제가 m마다 2D 문제 하나로 바뀐다. 질문은 세 가지다. 축 위의 쌍극자는 어떤 m인가. 축에서 떨어진 점광원은 m을 몇 개 더해야 하는가. 그 결과는 3D와, 그리고 12편의 2D 고리와 맞는가.</p>

  <h3 id="section-2">어디에 쓰이는가</h3>

  <p>축 대칭은 발광·공진·집광 소자의 기본 형태다. cylindrical 좌표는 이런 소자를 3D 대신 2D 비용으로 계산하게 해 준다.</p>

  <table>
    <thead>
      <tr>
        <th>응용</th>
        <th>이 글의 어떤 것을 쓰는가</th>
        <th>그 다음에 필요한 것</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>LED·OLED·micro-LED 메사의 광추출</td>
        <td>축 위 쌍극자(m = ±1), 축 밖 쌍극자의 m 급수, 열린 near2far 면</td>
        <td>14편 광추출 효율</td>
      </tr>
      <tr>
        <td>microdisk·microring 레이저, 바이오센서</td>
        <td>방위 차수 m = whispering-gallery 차수, m마다 1D run</td>
        <td>12편과 비교, 26편 결함 공진기</td>
      </tr>
      <tr>
        <td>축 대칭 렌즈·zone plate·나노안테나</td>
        <td>m = ±1 원편광 입사, 축 대칭 far field</td>
        <td>16편 zone plate</td>
      </tr>
      <tr>
        <td>광섬유 단면, 원형 격자 결합기</td>
        <td>원통 도파 모드(m), r 방향 PML</td>
        <td>—</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-3">원본 §2 · 물리 한 페이지</h3>

  <p>구조가 φ에 무관하면 Maxwell 방정식의 φ 미분은 field에 $im$을 곱하는 것으로 바뀐다. field를 $\mathbf E(r,\phi,z)=\sum_m \mathbf E_m(r,z)\,e^{im\phi}$로 쓰면 m마다 독립된 (r, z) 문제가 된다. Meep은 m 하나를 받아 그 문제 하나를 푼다.</p>

\[\mathbf E(r,\phi,z)=\sum_{m}\mathbf E_m(r,z)\,e^{im\phi},\qquad
\hat x=\tfrac12\big[e^{i\phi}(\hat r+i\hat\phi)+e^{-i\phi}(\hat r-i\hat\phi)\big],\qquad
P=\sum_m P_m\]

  <p>축 위에서 z 방향 쌍극자는 φ에 무관하므로 m = 0이다. x 방향 쌍극자는 φ를 따라 방향이 돌기 때문에 m = 0이 아니다. 가운데 식처럼 x 방향은 $e^{\pm i\phi}$를 가진 두 원편광($E_r\pm iE_\phi$)의 합이라 m = +1과 m = −1 두 run을 반씩 더한다. 축에서 r₀만큼 떨어진 점광원은 φ에서 델타 함수이고, 델타 함수의 Fourier 급수에는 모든 m이 들어간다. 다행히 m이 $k r_0$보다 커지면 그 항은 빛을 거의 내지 않는다. 그래서 m을 0부터 늘려 가며 각 m의 방사 power가 최대값의 10⁻⁴ 아래로 내려가면 멈춘다. 서로 다른 m의 field는 직교하므로 총 power는 m별 power의 합이다.</p>

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$m$</td>
        <td>방위 차수, field ∝ $e^{im\phi}$</td>
        <td><code class="language-plaintext highlighter-rouge">m=</code></td>
      </tr>
      <tr>
        <td>$(r, z)$</td>
        <td>계산하는 단면. 셀은 <code class="language-plaintext highlighter-rouge">(sr, 0, sz)</code></td>
        <td><code class="language-plaintext highlighter-rouge">cell_size</code></td>
      </tr>
      <tr>
        <td>$r_0$</td>
        <td>점광원의 축 거리</td>
        <td><code class="language-plaintext highlighter-rouge">R_SRC</code></td>
      </tr>
      <tr>
        <td>$E_r\pm iE_\phi$</td>
        <td>m = ±1 원편광 쌍극자</td>
        <td><code class="language-plaintext highlighter-rouge">Er</code> + <code class="language-plaintext highlighter-rouge">Ep</code>(amp ±1j)</td>
      </tr>
      <tr>
        <td>$P_m$</td>
        <td>m 항 하나의 방사 power</td>
        <td><code class="language-plaintext highlighter-rouge">m_flux</code></td>
      </tr>
      <tr>
        <td>near / far</td>
        <td>가까운 monitor flux / 먼 반구 적분</td>
        <td><code class="language-plaintext highlighter-rouge">f_near</code>, <code class="language-plaintext highlighter-rouge">f_far</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 파트 A·B는 진공, 파장 1 µm, 해상도 50. 파트 C는 12편의 고리(n 3.4, a = 1 µm)를 2D 대신 축 대칭 3D로 본 것이 아니라 같은 2D 문제를 다른 좌표로 푼 것이다. ring-cyl의 셀은 z 방향 크기가 0이라 z로 무한한 원기둥이다. 파트 D는 n 2.4 디스크, 바닥은 완전도체 ground plane이고 m = −1 하나(ring source)만 계산한다.</p>

  <h3 id="section-4">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>축 위 z 쌍극자 vs sin²θ</td>
        <td>1% 안</td>
        <td>노트 0.43%</td>
      </tr>
      <tr>
        <td>축 위 x 쌍극자(m = ±1) vs cos²θ</td>
        <td>1% 안</td>
        <td>노트 0.46%</td>
      </tr>
      <tr>
        <td>r₀ = 0.5 µm 점광원에 필요한 m</td>
        <td>7~9</td>
        <td>$k r_0=\pi$, 노트 m = 8</td>
      </tr>
      <tr>
        <td>m 급수 패턴 오차의 감소</td>
        <td>단조 감소</td>
        <td>항을 더할수록 정확해진다</td>
      </tr>
      <tr>
        <td>ring-cyl m = 3/4/5 vs 12편 2D</td>
        <td>주파수 0.2% 안</td>
        <td>같은 문제, 다른 좌표</td>
      </tr>
      <tr>
        <td>ring-cyl Q(m = 5) vs 12편 2D(res 20)</td>
        <td>비슷하다</td>
        <td>같은 물리</td>
      </tr>
      <tr>
        <td>디스크 near vs far flux</td>
        <td>7% 차이</td>
        <td>노트 7.42%, 공식 7.43%</td>
      </tr>
      <tr>
        <td>반지름 셀 6 → 8 µm</td>
        <td>차이가 준다</td>
        <td>열린 면의 truncation이면</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: A가 5% 넘게 어긋나면 x 쌍극자의 $E_\phi$ 위상이나 m 부호를 의심한다. B에서 m을 다 더해도 오차가 1% 아래로 안 내려가면 −m 항(음의 주파수 field의 켤레)을 빠뜨린 것이다. D의 차이가 셀을 키워도 그대로면 truncation이 아니라 다른 원인이다.</p>

  <h3 id="section-5">원본 §3 · 시뮬레이션 설계도</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/01_layout.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/01_layout.png" alt="파트 D의 cylindrical (r, z) 셀. 왼쪽 끝이 r = 0(축)이다. 회색 블록이 n 2.4 디스크(반지름 1.2 µm), 빨간 점이 r = 0.6 µm의 Er ring source, 파란 선이 flux monitor와 " loading="lazy" /></a>
<figcaption>파트 D의 cylindrical (r, z) 셀. 왼쪽 끝이 r = 0(축)이다. 회색 블록이 n 2.4 디스크(반지름 1.2 µm), 빨간 점이 r = 0.6 µm의 Er ring source, 파란 선이 flux monitor와 near2far 면(위와 바깥 r). 아래 경계에는 PML이 없어 완전도체 ground plane이다. 녹색 빗금은 r 방향과 위쪽 PML, 파란 빗금은 대표 DFT field 영역이다. <code class="language-plaintext highlighter-rouge">plot2D</code>는 cylindrical 셀에서도 축 이름을 x, y로 쓰므로 x가 r, y가 z다. 동그라미 숫자는 §4의 단계 번호다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/02_layout_dipole.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/02_layout_dipole.png" alt="파트 A·B의 (r, z) 셀. 진공, 사방 PML 1 µm(축 쪽 제외). 쌍극자는 축 위(A) 또는 r = 0.5 µm(B). near2far 면은 위, 바깥 r, 아래(weight −1)의 세 조각이다. 축은 경계가 아니라 대칭" loading="lazy" /></a>
<figcaption>파트 A·B의 (r, z) 셀. 진공, 사방 PML 1 µm(축 쪽 제외). 쌍극자는 축 위(A) 또는 r = 0.5 µm(B). near2far 면은 위, 바깥 r, 아래(weight −1)의 세 조각이다. 축은 경계가 아니라 대칭축이라 면이 필요 없다. 이 그림은 monitor를 붙이기 전의 셀이라 near2far 면은 그려지지 않았다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>A·B 셀</td>
        <td>r 2 + PML 1, z 4 + PML 2</td>
        <td>공식 값</td>
        <td>near2far 면이 PML에 닿으면 안 된다</td>
      </tr>
      <tr>
        <td>A·B 해상도</td>
        <td>50</td>
        <td>공식 값</td>
        <td>Er source offset 1.5/res도 같이 바뀐다</td>
      </tr>
      <tr>
        <td>A x 쌍극자</td>
        <td>Er + Ep(±1j), m = ±1, r = 1.5/res</td>
        <td>원편광 둘의 합. r = 0의 Er은 버그(meep #2704)</td>
        <td>m = 0으로 두면 x 쌍극자가 아니다</td>
      </tr>
      <tr>
        <td>B source</td>
        <td>Er at r₀ = 0.5, +f와 −f 두 source</td>
        <td>+f가 +m, −f의 켤레가 −m 항</td>
        <td>−f를 빼면 −m 항이 없다</td>
      </tr>
      <tr>
        <td>B 종료 기준</td>
        <td>m 항 power / 최대 &lt; 10⁻⁴</td>
        <td>공식 값</td>
        <td>너무 느슨하면 14편의 함정(되튐)</td>
      </tr>
      <tr>
        <td>C 고리</td>
        <td>n 3.4, R 1, w 1, PML 32, res 20</td>
        <td>공식 ring-cyl.py</td>
        <td>셀이 r 한 줄이라 PML이 두꺼워도 싸다</td>
      </tr>
      <tr>
        <td>D 디스크</td>
        <td>n 2.4, R 1.2, t = 0.7λ/n, res 100</td>
        <td>공식 값</td>
        <td>t를 바꾸면 패턴의 lobe가 바뀐다</td>
      </tr>
      <tr>
        <td>D 반지름 셀</td>
        <td>6 µm(공식), 8 µm</td>
        <td>truncation 확인</td>
        <td>셀이 클수록 열린 면이 덜 잃는다</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/00_source.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/00_source.png" alt="source 파형과 스펙트럼(1000 nm, fwidth 0.1 fcen). 모든 파트가 같은 상대 대역폭을 쓴다." loading="lazy" /></a>
<figcaption>source 파형과 스펙트럼(1000 nm, fwidth 0.1 fcen). 모든 파트가 같은 상대 대역폭을 쓴다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 강의 범위 밖이다. 10_sources의 노트들은 네 예제를 각각 따로 재현했다. 이 글은 한 스크립트에서 네 예제를 돌리고, B에서는 m 항을 하나 더할 때마다 패턴 오차를 재서 급수가 어떻게 수렴하는지 보이며, C에서는 12편 2D 결과와 같은 표에 올린다.</p>

</details>

<details>
  <summary>원본 코드 단계별 설명</summary>

  <h3 id="section-6">원본 §4 · 코드 따라가기</h3>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
이번 글의 새 요소는 ④의 <code class="language-plaintext highlighter-rouge">dimensions=mp.CYLINDRICAL, m=</code>과 ⑦의 m 합산이다.</p>
  </blockquote>

  <h3 id="section-7">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WL</span><span class="p">,</span> <span class="n">RES_D</span><span class="p">,</span> <span class="n">PML_D</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mf">1.0</span>
<span class="n">SR_D</span><span class="p">,</span> <span class="n">SZ_D</span> <span class="o">=</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">4.0</span>                       <span class="c1"># near2far box: r 0..2, z -2..2
</span><span class="n">R_FF</span><span class="p">,</span> <span class="n">NPTS</span> <span class="o">=</span> <span class="mf">1e6</span> <span class="o">*</span> <span class="n">WL</span><span class="p">,</span> <span class="mi">50</span>                   <span class="c1"># far-field radius and polar samples
</span><span class="n">THETA</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="n">NPTS</span><span class="p">)</span>   <span class="c1"># 0 = +z (pole), pi/2 = +r (equator), in the phi = 0 plane
</span><span class="n">POWER_DECAY</span> <span class="o">=</span> <span class="mf">1e-4</span>                          <span class="c1"># stop the m series when the last term is this small
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 공식 값. 각도는 +z에서 잰 극각이고 φ = 0 평면의 단면이다.</li>
    <li><strong>왜</strong>: cylindrical 셀에서는 x가 r, z가 z다. y 크기는 항상 0이다.</li>
    <li><strong>틀리면</strong>: 셀을 (sr, sz, 0)처럼 3D 습관으로 쓰면 z 크기 0의 다른 문제가 된다(파트 C는 일부러 그렇게 쓴다).</li>
  </ul>

  <h3 id="r--0--">② 재료와 구조 — r ≥ 0 반쪽만 그린다</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_DISC</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DISC_R</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DISC_T</span><span class="p">),</span>
         <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">DISC_R</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DISC_T</span><span class="p">))</span>                                         <span class="c1"># D: a disc = a block from r 0 to R
</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_IN</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">W</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_RING</span><span class="p">))</span>   <span class="c1"># C: a ring = a block from r 1 to 2
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 디스크는 r = 0부터 R까지의 블록, 고리는 r = 1부터 2까지의 블록이다. φ 방향 크기는 <code class="language-plaintext highlighter-rouge">mp.inf</code>.</li>
    <li><strong>왜</strong>: (r, z) 단면에서 축 대칭 물체는 직사각형이다. 12편처럼 원기둥 두 개를 덮어쓸 필요가 없다.</li>
    <li><strong>틀리면</strong>: 블록 center를 r = 0에 두고 size를 2R로 주면 음의 r 쪽은 셀 밖이라 버려진다. 결과는 같지만 의도가 흐려진다.</li>
  </ul>

  <h3 id="source--m--source-">③ Source — m에 따라 source가 다르다</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())</span>                              <span class="c1"># A: z-dipole on the axis, m = 0
</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">r_off</span><span class="p">)),</span>                       <span class="c1"># A: x-dipole = Er + (+-i) Ep, run with m = +1 and m = -1
</span> <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ep</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">r_off</span><span class="p">),</span> <span class="n">amplitude</span><span class="o">=</span><span class="mf">1j</span> <span class="k">if</span> <span class="n">m</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="o">-</span><span class="mf">1j</span><span class="p">)]</span>
<span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">)),</span>                       <span class="c1"># B: off-axis, +f gives the +m term ...
</span> <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="o">-</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">))]</span>                      <span class="c1"># ... -f gives the -m term after conjugation
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 축 위 z 쌍극자는 Ez 하나. x 쌍극자는 m = ±1 run마다 Er과 ±i Ep의 쌍. 축 밖 점광원은 m마다 +f와 −f 두 source.</li>
    <li><strong>왜</strong>: 세 번째 줄의 요령은 $e^{-im\phi}$ 항을 따로 돌리지 않으려는 것이다. 음의 주파수 field의 켤레가 −m 항과 같아서 run 하나로 ±m을 얻는다.</li>
    <li><strong>틀리면</strong>: x 쌍극자를 m = 0의 Er 하나로 두면 축 대칭 방사(ring dipole)가 나오고 cos²θ와 전혀 다르다. 선편광은 m = 0이 아니다.</li>
  </ul>

  <h3 id="simulation-----">④ Simulation과 경계 — 축은 경계가 아니다</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_D</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SR_D</span> <span class="o">+</span> <span class="n">PML_D</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">SZ_D</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">PML_D</span><span class="p">),</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=</span><span class="n">m</span><span class="p">,</span>
              <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">PML_D</span><span class="p">)],</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span> <span class="n">force_complex_fields</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">PML_DISC</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">PML_DISC</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)]</span>   <span class="c1"># D: no PML at the bottom -&gt; ground plane
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: <code class="language-plaintext highlighter-rouge">dimensions=mp.CYLINDRICAL</code>과 <code class="language-plaintext highlighter-rouge">m</code>. PML은 r 바깥과 z 양쪽에 붙고 축(r = 0)에는 붙지 않는다. 파트 D는 아래에 PML이 없어 그 벽이 ground plane이다.</li>
    <li><strong>왜</strong>: m ≠ 0이면 field가 복소수이므로 <code class="language-plaintext highlighter-rouge">force_complex_fields=True</code>. 11편과 같은 규칙으로 PML을 두지 않은 셀 벽은 완전도체다.</li>
    <li><strong>틀리면</strong>: 10편에서는 <code class="language-plaintext highlighter-rouge">k_point</code>가 벽을 주기 경계로 바꿔 거울이 사라졌다. cylindrical에는 <code class="language-plaintext highlighter-rouge">k_point</code>가 없으므로 바닥 벽이 그대로 거울이다.</li>
  </ul>

  <h3 id="monitor--near2far----">⑤ Monitor — near2far 면은 축을 닫지 않는다</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>                  <span class="c1"># top
</span><span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">))</span>                                 <span class="c1"># outer r
</span><span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">)</span>     <span class="c1"># bottom (A, B only)
</span><span class="n">ff</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_farfield</span><span class="p">(</span><span class="n">n2f</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_FF</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">th</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">R_FF</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">th</span><span class="p">)),</span> <span class="n">GREENCYL_TOL</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: A·B는 위·바깥·아래 세 조각, D는 위·바깥 두 조각(아래는 ground plane이라 둘 수 없다). far field는 φ = 0 평면의 (r, z) 점에서 구한다.</li>
    <li><strong>왜</strong>: 축은 대칭축이라 닫을 면이 없다. 회전하면 위·아래 원판과 옆 원통이 닫힌 면이 된다. <code class="language-plaintext highlighter-rouge">GREENCYL_TOL</code>은 φ 방향 적분의 허용 오차다.</li>
    <li><strong>틀리면</strong>: D처럼 아래가 열려 있으면 ground plane 위 바깥 r 너머의 등가 전류가 빠진다. 이것이 §5의 near–far 차이다.</li>
  </ul>

  <h3 id="m-run-">⑥ 실행 — m마다 run 하나</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">m</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">dipole_sim</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">src</span><span class="p">);</span> <span class="p">...;</span> <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="k">if</span> <span class="n">m</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">P_m</span> <span class="o">/</span> <span class="n">P_max</span> <span class="o">&lt;</span> <span class="n">POWER_DECAY</span><span class="p">:</span>
        <span class="k">break</span>
    <span class="n">m</span> <span class="o">+=</span> <span class="mi">1</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: m을 0부터 늘려 가며 run을 반복한다. 각 run은 독립이라 병렬로 돌려도 된다.</li>
    <li><strong>왜</strong>: 필요한 m의 수는 $k r_0$로 어림된다. r₀ = 0.5 µm, k = 2π/µm이면 $kr_0\approx3.1$이고, power는 m = 5 근처부터 급히 준다.</li>
    <li><strong>틀리면</strong>: 공식 코드의 종료 조건은 “처음으로 작아진 m”이다. 축에서 먼 점광원이나 구조가 있는 셀에서는 power가 줄다가 다시 커질 수 있다(10_sources Point Dipole CYL: r 3.5 µm에서 m 32의 0.5%가 m 41에서 38%로). 14편에서 다룬다.</li>
  </ul>

  <h3 id="field--power-">⑦ 후처리 — field를 더하고 power를 잰다</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">e_tot</span> <span class="o">+=</span> <span class="n">ep</span><span class="p">;</span> <span class="n">h_tot</span> <span class="o">+=</span> <span class="n">hp</span>                         <span class="c1"># +m term (exp(i m phi) = 1 at phi = 0)
</span><span class="k">if</span> <span class="n">m</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
    <span class="n">e_tot</span> <span class="o">+=</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">em</span><span class="p">);</span> <span class="n">h_tot</span> <span class="o">+=</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">hm</span><span class="p">)</span>   <span class="c1"># -m term from the negative-frequency run
</span><span class="n">pattern</span> <span class="o">=</span> <span class="n">radial_flux</span><span class="p">(</span><span class="n">e_tot</span><span class="p">,</span> <span class="n">h_tot</span><span class="p">)</span>              <span class="c1"># |Re(E x H*)| on the far-field arc
</span><span class="n">P_m</span> <span class="o">=</span> <span class="n">total_flux</span><span class="p">(</span><span class="n">radial_flux</span><span class="p">(</span><span class="n">ep</span><span class="p">,</span> <span class="n">hp</span><span class="p">))</span>            <span class="c1"># power of this m alone: decides when to stop
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: φ = 0에서 field를 m에 대해 더하고 Poynting으로 패턴을 만든다. 종료 판단은 m 항 하나의 power로 한다.</li>
    <li><strong>왜</strong>: 패턴은 field의 합이어야 간섭이 들어간다. 총 power는 m끼리 직교하므로 power의 합으로도 같다.</li>
    <li><strong>틀리면</strong>: 패턴을 m별 power의 합으로 만들면 간섭이 빠져 φ 의존성이 없는 평균 패턴이 나온다. x 쌍극자의 cos²θ는 간섭의 결과다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: cylindrical 셀의 <code class="language-plaintext highlighter-rouge">get_array</code>와 <code class="language-plaintext highlighter-rouge">get_dft_array</code>는 이 Meep 버전에서 (z, r) 순서로 돌려준다(11편). 2D처럼 전치하면 그림이 뒤집힌다. 이 글의 스크립트는 기대 크기와 비교해 방향을 맞추는 <code class="language-plaintext highlighter-rouge">orient_rz</code>를 쓴다.</p>
  </blockquote>

</details>

<details>
  <summary>원본 결과·검증 표·오류 진단·추가 탐구</summary>

  <h3 id="section-8">원본 §5 · 결과</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/03_on_axis.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/03_on_axis.png" alt="파트 A. 축 위 쌍극자의 φ = 0 단면 패턴(0°가 +z). 왼쪽: z 쌍극자, m = 0 한 run. 오른쪽: x 쌍극자, m = +1과 −1 두 run을 반씩 더한 것." loading="lazy" /></a>
<figcaption>파트 A. 축 위 쌍극자의 φ = 0 단면 패턴(0°가 +z). 왼쪽: z 쌍극자, m = 0 한 run. 오른쪽: x 쌍극자, m = +1과 −1 두 run을 반씩 더한 것.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>쌍극자</th>
        <th>m</th>
        <th>해석 패턴</th>
        <th>상대 L2</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>z, 축 위</td>
        <td>0</td>
        <td>sin²θ</td>
        <td>0.43%</td>
      </tr>
      <tr>
        <td>x, 축 위</td>
        <td>+1, −1</td>
        <td>cos²θ</td>
        <td>0.46%</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/04_off_axis.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/04_off_axis.png" alt="파트 B. r₀ = 0.5 µm의 x 쌍극자. 왼쪽: m 항 하나의 방사 power(최대로 나눔). 가운데: m을 하나씩 더할 때마다 잰 패턴 오차. 오른쪽: m = 0…8을 다 더한 패턴과 cos²θ." loading="lazy" /></a>
<figcaption>파트 B. r₀ = 0.5 µm의 x 쌍극자. 왼쪽: m 항 하나의 방사 power(최대로 나눔). 가운데: m을 하나씩 더할 때마다 잰 패턴 오차. 오른쪽: m = 0…8을 다 더한 패턴과 cos²θ.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>m</th>
        <th>0</th>
        <th>1</th>
        <th>2</th>
        <th>3</th>
        <th>4</th>
        <th>5</th>
        <th>6</th>
        <th>7</th>
        <th>8</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$P_m/P_{\max}$</td>
        <td>1.00</td>
        <td>0.94</td>
        <td>1.00</td>
        <td>0.64</td>
        <td>0.18</td>
        <td>2.8e-2</td>
        <td>2.8e-3</td>
        <td>1.9e-4</td>
        <td>9.5e-6</td>
      </tr>
      <tr>
        <td>0…m 합의 패턴 오차</td>
        <td>0.589</td>
        <td>0.409</td>
        <td>0.099</td>
        <td>0.141</td>
        <td>0.030</td>
        <td>0.0087</td>
        <td>0.0064</td>
        <td>0.0064</td>
        <td>0.0063</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/05_ring_cyl.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/05_ring_cyl.png" alt="파트 C. 12편의 고리를 m마다 1D 반지름 run으로. 위: Ez(r)과 고리 위치(회색). 아래: Re[Ez(r)e^imφ]로 복원한 x–y 그림. 부호 lobe가 2m개다." loading="lazy" /></a>
<figcaption>파트 C. 12편의 고리를 m마다 1D 반지름 run으로. 위: Ez(r)과 고리 위치(회색). 아래: Re[Ez(r)e^{imφ}]로 복원한 x–y 그림. 부호 lobe가 2m개다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>m</th>
        <th>f (cylindrical)</th>
        <th>Q (cylindrical)</th>
        <th>f (12편 2D, res 20)</th>
        <th>Q (12편)</th>
        <th>Δf/f</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>3</td>
        <td>0.11821</td>
        <td>77</td>
        <td>0.11818</td>
        <td>79</td>
        <td>+0.02%</td>
      </tr>
      <tr>
        <td>4</td>
        <td>0.14746</td>
        <td>343</td>
        <td>0.14736</td>
        <td>342</td>
        <td>+0.07%</td>
      </tr>
      <tr>
        <td>5</td>
        <td>0.17582</td>
        <td>1627</td>
        <td>0.17564</td>
        <td>2132</td>
        <td>+0.10%</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/13/06_disc.png" data-lightbox=""><img src="/meep-examples/assets/meep/13/06_disc.png" alt="파트 D. 왼쪽: ground plane 위 디스크의 far-field 패턴(두 셀 크기). 가운데: near monitor flux와 far 반구 적분. 오른쪽: log&#124;Er&#124;의 (r, z) 분포. 흰 사각형이 디스크." loading="lazy" /></a>
<figcaption>파트 D. 왼쪽: ground plane 위 디스크의 far-field 패턴(두 셀 크기). 가운데: near monitor flux와 far 반구 적분. 오른쪽: log|Er|의 (r, z) 분포. 흰 사각형이 디스크.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>반지름 셀</th>
        <th>near flux</th>
        <th>far flux</th>
        <th>차이</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>6 µm (공식)</td>
        <td>643.65</td>
        <td>595.80</td>
        <td>7.43% (공식 문서 7.43%)</td>
      </tr>
      <tr>
        <td>8 µm</td>
        <td>643.28</td>
        <td>602.05</td>
        <td>6.41%</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-9">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>z 쌍극자 vs sin²θ</td>
        <td>1% 안</td>
        <td>0.43%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>x 쌍극자(m = ±1) vs cos²θ</td>
        <td>1% 안</td>
        <td>0.46%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>r₀ = 0.5 µm에 필요한 m</td>
        <td>7~9</td>
        <td>8</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>m 급수 오차 감소</td>
        <td>단조</td>
        <td>m = 2 → 3에서 0.099 → 0.141로 증가 후 감소</td>
        <td>❌</td>
      </tr>
      <tr>
        <td>ring-cyl vs 12편 주파수</td>
        <td>0.2% 안</td>
        <td>0.1%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>ring-cyl Q(m = 5) vs 12편</td>
        <td>비슷</td>
        <td>1627 vs 2132</td>
        <td>❌</td>
      </tr>
      <tr>
        <td>디스크 near vs far</td>
        <td>7%</td>
        <td>7.43%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>셀 6 → 8 µm</td>
        <td>차이 감소</td>
        <td>6.41%</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>여덟 예측 중 여섯이 맞았고 둘이 빗나갔다. 첫째, m 급수의 오차는 단조로 줄지 않았다. m = 0…2까지 더한 패턴(오차 0.099)이 m = 3을 더한 패턴(0.141)보다 cos²θ에 가깝다. 급수의 부분합은 해석 패턴에 한 방향으로 다가가지 않는다. m = 3 항이 아직 큰 power(0.64)를 가진 채 더해져 일시적으로 모양을 흔들고, m = 4·5가 더해진 뒤에야 맞춰진다. 그래서 “오차가 작아 보이는 중간 m에서 멈추기”는 안 되고 각 m의 power로 멈춰야 한다. 둘째, 고리의 m = 5 Q가 cylindrical에서 1627, 12편 2D(res 20)에서 2132로 30% 다르다. 그런데 12편의 2D는 res 10에서 1675, res 30에서 1610이었다. 원을 계단으로 자르지 않는 cylindrical 값은 res 10·30의 2D 값과 같은 쪽이고, 튀었던 것은 2D res 20이다. 12편에서 Q가 해상도에 비단조라고 적은 이유가 계단 경계라는 해석과 맞는다. 주파수는 세 모드 모두 0.1% 안에서 같다. 디스크의 near–far 차이는 셀 6 µm에서 공식 문서와 같은 7.43%였고 8 µm에서 6.41%로 줄었다. 열린 면이 ground plane 위 셀 바깥의 등가 전류를 잃는다는 해석과 맞는다. near flux는 셀 크기에 거의 그대로(643.65 → 643.28)라서, 줄어든 차이는 far flux 쪽이 늘어난 것이다.</p>

  <h3 id="section-10">수렴성</h3>

  <table>
    <thead>
      <tr>
        <th>변수</th>
        <th>값</th>
        <th>결과</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>B: 포함한 m</td>
        <td>0…4 / 0…5 / 0…8</td>
        <td>오차 0.030 / 0.0087 / 0.0063</td>
        <td>m = 6 이후 오차는 해상도가 정한다</td>
      </tr>
      <tr>
        <td>C: 좌표계</td>
        <td>2D Cartesian(12편, res 10/20/30) vs cylindrical(res 20)</td>
        <td>Q(m = 5) 1675/2132/1610 vs 1627</td>
        <td>계단 경계가 없는 cylindrical이 res 10·30 쪽과 같다</td>
      </tr>
      <tr>
        <td>D: 반지름 셀</td>
        <td>6 / 8 µm</td>
        <td>7.43% / 6.41%</td>
        <td>차이가 셀 크기를 따라가면 truncation</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-11">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: 진공에서 축 위 쌍극자의 패턴은 m = 0(z) 또는 m = ±1(x)로 0.5% 안에서 맞는다. 축에서 0.5 µm 떨어진 x 쌍극자는 m = 0…8의 합으로 0.6% 안에서 맞는다. 12편 고리의 주파수는 cylindrical 좌표와 2D Cartesian이 0.1% 안에서 같다. ground plane 위 디스크의 near–far 차이는 반지름 셀을 키우면 줄어드는 truncation이다.</li>
    <li>할 수 없는 것: 축에서 먼 점광원이나 구조가 있는 셀에서 “power가 처음 10⁻⁴ 아래로 내려간 m”이 급수의 끝이라는 것(14편의 반례). 디스크의 진짜 far-field 총 power(열린 면 때문에 모른다). 2D Cartesian의 Q가 해상도마다 다른 이유를 staircase 하나로 확정하는 것(이 글은 일치하는 쪽을 보였을 뿐이다).</li>
  </ul>

  <h3 id="section-12">원본 §6 · 흔한 실수</h3>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>x 쌍극자 패턴이 축 대칭</td>
        <td>m = 0의 Er 하나로 둠</td>
        <td>m = +1과 −1, 각각 Er + (±i)Ep</td>
      </tr>
      <tr>
        <td>Er source에서 field가 발산</td>
        <td>r = 0에 정확히 둠(meep #2704)</td>
        <td>1.5/res만큼 비킨다</td>
      </tr>
      <tr>
        <td>m을 다 더해도 오차 30%</td>
        <td>−m 항(−f 켤레)을 빼먹음</td>
        <td>m &gt; 0에서 conj(minus field)를 더한다</td>
      </tr>
      <tr>
        <td>패턴에 간섭이 없음</td>
        <td>m별 power를 더함</td>
        <td>패턴은 field를 더하고, power는 종료 판단에만</td>
      </tr>
      <tr>
        <td>2D 그림이 뒤집힘</td>
        <td>cylindrical 배열은 (z, r)</td>
        <td>기대 크기로 방향 확인</td>
      </tr>
      <tr>
        <td>디스크 near·far가 7% 다름</td>
        <td>열린 near2far 면</td>
        <td>셀을 키워 차이가 주는지 확인</td>
      </tr>
      <tr>
        <td>바닥 거울이 사라짐</td>
        <td>아래에도 PML</td>
        <td>ground plane 쪽은 PML 없이</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-13">원본 §7 · 직접 해보기</h3>

  <table>
    <thead>
      <tr>
        <th>바꿀 것</th>
        <th>예상 변화</th>
        <th>확인할 수치</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>B의 r₀ 0.5 → 1.5 µm</td>
        <td>필요한 m이 약 3배(kr₀에 비례)</td>
        <td>마지막 m, 각 m power의 되튐</td>
      </tr>
      <tr>
        <td>B를 y 쌍극자(Ep)로</td>
        <td>패턴이 상수</td>
        <td>상대 L2 vs 1</td>
      </tr>
      <tr>
        <td>C에서 m = 2</td>
        <td>대역 0.10~0.20 밖, 낮은 Q</td>
        <td>Harminv 결과</td>
      </tr>
      <tr>
        <td>D의 반지름 셀 12 µm</td>
        <td>차이가 더 준다</td>
        <td>near·far 차이</td>
      </tr>
      <tr>
        <td>D의 디스크 두께 0.7λ/n → 0.5λ/n</td>
        <td>lobe가 바뀐다</td>
        <td>패턴</td>
      </tr>
    </tbody>
  </table>

</details>

<details>
  <summary>code/cylindrical_dipole.py 전체 (클릭하여 펼치기)</summary>

  <figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 13 - Computing 3D with rotational symmetry: cylindrical coordinates and the m series.

Post 12's ring was a 2D cross-section. A real disc or ring is a body of revolution, and Meep's
dimensions=mp.CYLINDRICAL solves it as one 2D (r, z) run per azimuthal order m, with fields ~ exp(i m phi).
  A. On-axis dipoles in vacuum (official dipole_in_vacuum_cyl_on_axis.py): a z-dipole is m = 0 (Ez);
     an x-dipole is NOT m = 0 but the sum of m = +1 and m = -1 (Er + i Ep, Er - i Ep). Far-field
     patterns vs the analytic cos^2(theta) and sin^2(theta).
  B. An off-axis x-dipole at r = 0.5 um (official dipole_in_vacuum_cyl_off_axis.py): a point away from
     the axis is a Fourier series over m = 0, 1, 2, ... The series is summed until the power of the last
     m drops below 1e-4 of the largest; the pattern is checked after every added m.
  C. The ring of post 12 in cylindrical coordinates (official ring-cyl.py): one 1D radial run per m.
     Frequencies and Q compared with post 12's 2D Cartesian values; the m = 3 field rebuilt in the
     x-y plane from Ez(r) exp(i m phi).
  D. A dielectric disc on a ground plane (official disc_radiation_pattern.py): a ring source (m = -1),
     near flux vs far-field flux; the 7 % gap comes from the open near2far surface, checked by
     enlarging the radial cell.
MPI-safe: collective calls on every rank, figures on the master only.

Run:  mpirun -np 4 python cylindrical_dipole.py     (~6 min)
Out:  00_source.png, 01_layout.png, 02_layout_dipole.png, 03_on_axis.png, 04_off_axis.png, 05_ring_cyl.png,
      06_disc.png, 07_anim_m3.gif, result.json   (-&gt; ../assets/13/)
"""</span>
<span class="kn">import</span> <span class="nn">cmath</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">math</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">animation</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">HERE</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"13"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">MASTER</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">()</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">say</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">rel_l2</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">b</span><span class="p">))</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">b</span><span class="p">)))</span>


<span class="k">def</span> <span class="nf">orient_rz</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">nr</span><span class="p">):</span>
    <span class="s">"""Cylindrical get_array/get_dft_array return (z, r) in this Meep version; return (r, z) whatever the order."""</span>
    <span class="n">arr</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">arr</span><span class="p">.</span><span class="n">ndim</span> <span class="o">==</span> <span class="mi">2</span> <span class="ow">and</span> <span class="nb">abs</span><span class="p">(</span><span class="n">arr</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">nr</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">abs</span><span class="p">(</span><span class="n">arr</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">nr</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">arr</span><span class="p">.</span><span class="n">T</span>
    <span class="k">return</span> <span class="n">arr</span>


<span class="c1"># ---------------------------------------------------------------- (1) parameters shared by A and B (official values, um)
</span><span class="n">WL</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">FREQ</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">WL</span>
<span class="n">RES_D</span> <span class="o">=</span> <span class="mi">50</span>
<span class="n">PML_D</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">SR_D</span><span class="p">,</span> <span class="n">SZ_D</span> <span class="o">=</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">4.0</span>                       <span class="c1"># near2far box: r 0..2, z -2..2
</span><span class="n">R_FF</span> <span class="o">=</span> <span class="mf">1e6</span> <span class="o">*</span> <span class="n">WL</span>
<span class="n">NPTS</span> <span class="o">=</span> <span class="mi">50</span>
<span class="n">THETA</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="n">NPTS</span><span class="p">)</span>   <span class="c1"># 0 = +z (pole), pi/2 = +r (equator), in the phi = 0 plane
</span><span class="n">GREENCYL_TOL</span> <span class="o">=</span> <span class="mf">1e-6</span>
<span class="n">POWER_DECAY</span> <span class="o">=</span> <span class="mf">1e-4</span>


<span class="k">def</span> <span class="nf">n2f_regions</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="n">sz</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">)),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">)]</span>


<span class="k">def</span> <span class="nf">farfields</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">n2f</span><span class="p">,</span> <span class="n">tol</span><span class="o">=</span><span class="n">GREENCYL_TOL</span><span class="p">,</span> <span class="n">theta</span><span class="o">=</span><span class="n">THETA</span><span class="p">,</span> <span class="n">r_ff</span><span class="o">=</span><span class="n">R_FF</span><span class="p">):</span>
    <span class="n">e</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> <span class="mi">3</span><span class="p">),</span> <span class="nb">complex</span><span class="p">);</span> <span class="n">h</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> <span class="mi">3</span><span class="p">),</span> <span class="nb">complex</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">n</span><span class="p">,</span> <span class="n">th</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">theta</span><span class="p">):</span>
        <span class="n">ff</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_farfield</span><span class="p">(</span><span class="n">n2f</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">r_ff</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">th</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">r_ff</span> <span class="o">*</span> <span class="n">math</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">th</span><span class="p">)),</span> <span class="n">tol</span><span class="p">)</span>
        <span class="n">e</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="n">ff</span><span class="p">[:</span><span class="mi">3</span><span class="p">];</span> <span class="n">h</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="n">ff</span><span class="p">[</span><span class="mi">3</span><span class="p">:]</span>
    <span class="k">return</span> <span class="n">e</span><span class="p">,</span> <span class="n">h</span>


<span class="k">def</span> <span class="nf">radial_flux</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">h</span><span class="p">):</span>
    <span class="n">fx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">e</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">h</span><span class="p">[:,</span> <span class="mi">2</span><span class="p">])</span> <span class="o">-</span> <span class="n">e</span><span class="p">[:,</span> <span class="mi">2</span><span class="p">]</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">h</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">]))</span>
    <span class="n">fz</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">e</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">h</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">])</span> <span class="o">-</span> <span class="n">e</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">h</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]))</span>
    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">fx</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">fz</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">total_flux</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">theta</span><span class="o">=</span><span class="n">THETA</span><span class="p">,</span> <span class="n">r_ff</span><span class="o">=</span><span class="n">R_FF</span><span class="p">):</span>
    <span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">r_ff</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">trapezoid</span><span class="p">(</span><span class="n">pattern</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> <span class="n">theta</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">dipole_sim</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">sources</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_D</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SR_D</span> <span class="o">+</span> <span class="n">PML_D</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">SZ_D</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">PML_D</span><span class="p">),</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=</span><span class="n">m</span><span class="p">,</span>
                         <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">PML_D</span><span class="p">)],</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span> <span class="n">force_complex_fields</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>


<span class="c1"># ================================================================ A. on-axis dipoles
</span><span class="n">t_a</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">r_off</span> <span class="o">=</span> <span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_D</span>                          <span class="c1"># an Er source exactly at r = 0 hits a known bug (meep issue 2704): offset by 1.5 px
</span><span class="n">gs</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.1</span> <span class="o">*</span> <span class="nb">abs</span><span class="p">(</span><span class="n">f</span><span class="p">))</span>
<span class="n">on</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># z-dipole: m = 0, Ez on the axis
</span><span class="n">sim</span> <span class="o">=</span> <span class="n">dipole_sim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())])</span>
<span class="n">annotated_layout</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_layout_dipole.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">PML_D</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.4</span><span class="p">,</span> <span class="mf">7.6</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">,</span>
                 <span class="n">title</span><span class="o">=</span><span class="s">"parts A, B: cylindrical (r, z) cell; r = 0 is the left edge (the axis)"</span><span class="p">,</span>
                 <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">WL</span><span class="si">}</span><span class="s"> um, res=</span><span class="si">{</span><span class="n">RES_D</span><span class="si">}</span><span class="se">\n</span><span class="s">m = 0, +-1 (A)</span><span class="se">\n</span><span class="s">m = 0..8 (B)"</span><span class="p">,</span> <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.15</span><span class="p">,</span> <span class="mf">3.75</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.15</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.5</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
                 <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"dipole on the axis (A) or at r = 0.5 (B)"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.03</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                         <span class="n">Label</span><span class="p">(</span><span class="s">"near2far: top, outer r, bottom (weight -1)"</span><span class="p">,</span> <span class="p">(</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="mf">2.6</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">),</span>
                         <span class="n">Label</span><span class="p">(</span><span class="s">"vacuum: no geometry"</span><span class="p">,</span> <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.4</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">)])</span>
<span class="n">n2f</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">*</span><span class="n">n2f_regions</span><span class="p">(</span><span class="n">SR_D</span><span class="p">,</span> <span class="n">SZ_D</span><span class="p">))</span>
<span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="mf">1e-6</span><span class="p">))</span>
<span class="n">on</span><span class="p">[</span><span class="s">"z"</span><span class="p">]</span> <span class="o">=</span> <span class="n">farfields</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">n2f</span><span class="p">);</span> <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
<span class="c1"># x-dipole: m = +1 and m = -1, each Er + (+-i) Ep, combined with weight 1/2 and exp(+-i phi) at phi = 0
</span><span class="n">ex</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">NPTS</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="nb">complex</span><span class="p">);</span> <span class="n">hx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">NPTS</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="nb">complex</span><span class="p">)</span>
<span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">(</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
    <span class="n">src</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">r_off</span><span class="p">)),</span>
           <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ep</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">r_off</span><span class="p">),</span> <span class="n">amplitude</span><span class="o">=</span><span class="mf">1j</span> <span class="k">if</span> <span class="n">m</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="o">-</span><span class="mf">1j</span><span class="p">)]</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">dipole_sim</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">src</span><span class="p">)</span>
    <span class="n">n2f</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">*</span><span class="n">n2f_regions</span><span class="p">(</span><span class="n">SR_D</span><span class="p">,</span> <span class="n">SZ_D</span><span class="p">))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">r_off</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">e</span><span class="p">,</span> <span class="n">h</span> <span class="o">=</span> <span class="n">farfields</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">n2f</span><span class="p">);</span> <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">ex</span> <span class="o">+=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">e</span><span class="p">;</span> <span class="n">hx</span> <span class="o">+=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">h</span>
<span class="n">on</span><span class="p">[</span><span class="s">"x"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">ex</span><span class="p">,</span> <span class="n">hx</span><span class="p">)</span>
<span class="n">pat_on</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">radial_flux</span><span class="p">(</span><span class="o">*</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">on</span><span class="p">.</span><span class="n">items</span><span class="p">()}</span>
<span class="n">an_on</span> <span class="o">=</span> <span class="p">{</span><span class="s">"x"</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">THETA</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">,</span> <span class="s">"z"</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">THETA</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">}</span>
<span class="n">err_on</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">pat_on</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">/</span> <span class="n">pat_on</span><span class="p">[</span><span class="n">k</span><span class="p">].</span><span class="nb">max</span><span class="p">(),</span> <span class="n">an_on</span><span class="p">[</span><span class="n">k</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">on</span><span class="p">}</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"A: on-axis z-dipole (m = 0) vs sin^2: rel L2 </span><span class="si">{</span><span class="n">err_on</span><span class="p">[</span><span class="s">'z'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; x-dipole (m = +1 and -1) vs cos^2: </span><span class="si">{</span><span class="n">err_on</span><span class="p">[</span><span class="s">'x'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_a</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
    <span class="n">source_figure</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>

<span class="c1"># ================================================================ B. off-axis x-dipole: the m series
</span><span class="n">t_b</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">R_SRC</span> <span class="o">=</span> <span class="mf">0.5</span>
<span class="n">e_tot</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">NPTS</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="nb">complex</span><span class="p">);</span> <span class="n">h_tot</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">NPTS</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="nb">complex</span><span class="p">)</span>
<span class="n">m_flux</span><span class="p">,</span> <span class="n">m_err</span><span class="p">,</span> <span class="n">flux_max</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="mf">0.0</span>
<span class="n">m</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="n">src</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">)),</span>
           <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">gs</span><span class="p">(</span><span class="o">-</span><span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">))]</span>          <span class="c1"># +f gives the +m term, -f the -m term (conjugated)
</span>    <span class="n">sim</span> <span class="o">=</span> <span class="n">dipole_sim</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">src</span><span class="p">)</span>
    <span class="n">n2p</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">*</span><span class="n">n2f_regions</span><span class="p">(</span><span class="n">SR_D</span><span class="p">,</span> <span class="n">SZ_D</span><span class="p">))</span>
    <span class="n">n2m</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="o">-</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">*</span><span class="n">n2f_regions</span><span class="p">(</span><span class="n">SR_D</span><span class="p">,</span> <span class="n">SZ_D</span><span class="p">))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">ep</span><span class="p">,</span> <span class="n">hp</span> <span class="o">=</span> <span class="n">farfields</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">n2p</span><span class="p">);</span> <span class="n">em</span><span class="p">,</span> <span class="n">hm</span> <span class="o">=</span> <span class="n">farfields</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">n2m</span><span class="p">);</span> <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">e_tot</span> <span class="o">+=</span> <span class="n">ep</span><span class="p">;</span> <span class="n">h_tot</span> <span class="o">+=</span> <span class="n">hp</span>                                   <span class="c1"># exp(i m phi) = 1 at phi = 0
</span>    <span class="k">if</span> <span class="n">m</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">e_tot</span> <span class="o">+=</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">em</span><span class="p">);</span> <span class="n">h_tot</span> <span class="o">+=</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">hm</span><span class="p">)</span>
    <span class="n">fl</span> <span class="o">=</span> <span class="n">total_flux</span><span class="p">(</span><span class="n">radial_flux</span><span class="p">(</span><span class="n">ep</span><span class="p">,</span> <span class="n">hp</span><span class="p">))</span>
    <span class="n">flux_max</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">flux_max</span><span class="p">,</span> <span class="n">fl</span><span class="p">)</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">radial_flux</span><span class="p">(</span><span class="n">e_tot</span><span class="p">,</span> <span class="n">h_tot</span><span class="p">)</span>
    <span class="n">m_flux</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">fl</span><span class="p">);</span> <span class="n">m_err</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">rel_l2</span><span class="p">(</span><span class="n">p</span> <span class="o">/</span> <span class="n">p</span><span class="p">.</span><span class="nb">max</span><span class="p">(),</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">THETA</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">))</span>
    <span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"B: m = </span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">: power of this m / max = </span><span class="si">{</span><span class="n">fl</span> <span class="o">/</span> <span class="n">flux_max</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">e</span><span class="si">}</span><span class="s">; pattern error after summing 0..</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">m_err</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">m</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">fl</span> <span class="o">/</span> <span class="n">flux_max</span> <span class="o">&lt;</span> <span class="n">POWER_DECAY</span><span class="p">:</span>
        <span class="k">break</span>
    <span class="n">m</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">pat_off</span> <span class="o">=</span> <span class="n">radial_flux</span><span class="p">(</span><span class="n">e_tot</span><span class="p">,</span> <span class="n">h_tot</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"B: off-axis x-dipole at r = </span><span class="si">{</span><span class="n">R_SRC</span><span class="si">}</span><span class="s">: stopped at m = </span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">; final rel L2 vs cos^2 </span><span class="si">{</span><span class="n">m_err</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_b</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="c1"># ================================================================ C. post 12's ring in cylindrical coordinates
</span><span class="n">t_c</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">N_RING</span><span class="p">,</span> <span class="n">W</span><span class="p">,</span> <span class="n">R_IN</span><span class="p">,</span> <span class="n">PAD</span><span class="p">,</span> <span class="n">DPML_R</span> <span class="o">=</span> <span class="mf">3.4</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">32.0</span>
<span class="n">SR_R</span> <span class="o">=</span> <span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span> <span class="o">+</span> <span class="n">PAD</span> <span class="o">+</span> <span class="n">DPML_R</span>
<span class="n">RES_R</span> <span class="o">=</span> <span class="mi">20</span>
<span class="n">FC</span><span class="p">,</span> <span class="n">DFC</span> <span class="o">=</span> <span class="mf">0.15</span><span class="p">,</span> <span class="mf">0.1</span>
<span class="n">POST12</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">:</span> <span class="p">(</span><span class="mf">0.11818</span><span class="p">,</span> <span class="mi">79</span><span class="p">),</span> <span class="mi">4</span><span class="p">:</span> <span class="p">(</span><span class="mf">0.14736</span><span class="p">,</span> <span class="mi">342</span><span class="p">),</span> <span class="mi">5</span><span class="p">:</span> <span class="p">(</span><span class="mf">0.17564</span><span class="p">,</span> <span class="mi">2132</span><span class="p">)}</span>     <span class="c1"># 2D Cartesian, res 20 (post 12)
</span><span class="n">ring</span> <span class="o">=</span> <span class="p">{}</span>


<span class="k">def</span> <span class="nf">ring_sim</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">df</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SR_R</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES_R</span><span class="p">,</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=</span><span class="n">m</span><span class="p">,</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML_R</span><span class="p">)],</span>
                         <span class="n">geometry</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_IN</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">W</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_RING</span><span class="p">))],</span>
                         <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">df</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_IN</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">))])</span>


<span class="k">for</span> <span class="n">mm</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">):</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">ring_sim</span><span class="p">(</span><span class="n">mm</span><span class="p">,</span> <span class="n">FC</span><span class="p">,</span> <span class="n">DFC</span><span class="p">)</span>
    <span class="n">hv</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Harminv</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_IN</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">),</span> <span class="n">FC</span><span class="p">,</span> <span class="n">DFC</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">after_sources</span><span class="p">(</span><span class="n">hv</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
    <span class="n">modes</span> <span class="o">=</span> <span class="p">[</span><span class="n">md</span> <span class="k">for</span> <span class="n">md</span> <span class="ow">in</span> <span class="n">hv</span><span class="p">.</span><span class="n">modes</span> <span class="k">if</span> <span class="n">md</span><span class="p">.</span><span class="n">Q</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">FC</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DFC</span> <span class="o">&lt;</span> <span class="n">md</span><span class="p">.</span><span class="n">freq</span> <span class="o">&lt;</span> <span class="n">FC</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DFC</span><span class="p">]</span>
    <span class="n">md</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">modes</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="nb">abs</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">amp</span><span class="p">));</span> <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">f</span><span class="p">,</span> <span class="n">Q</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">md</span><span class="p">.</span><span class="n">freq</span><span class="p">),</span> <span class="nb">float</span><span class="p">(</span><span class="n">md</span><span class="p">.</span><span class="n">Q</span><span class="p">)</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">ring_sim</span><span class="p">(</span><span class="n">mm</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="mf">0.01</span><span class="p">)</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">f</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span> <span class="o">+</span> <span class="n">PAD</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span> <span class="o">+</span> <span class="n">PAD</span><span class="p">))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_IN</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">ezr</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">squeeze</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span> <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">ring</span><span class="p">[</span><span class="n">mm</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"f"</span><span class="p">:</span> <span class="n">f</span><span class="p">,</span> <span class="s">"Q"</span><span class="p">:</span> <span class="n">Q</span><span class="p">,</span> <span class="s">"ez_r"</span><span class="p">:</span> <span class="n">ezr</span><span class="p">}</span>
    <span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"C: m = </span><span class="si">{</span><span class="n">mm</span><span class="si">}</span><span class="s">: cylindrical f </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">f</span><span class="si">}</span><span class="s"> Q </span><span class="si">{</span><span class="n">Q</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> | post 12 (2D, res 20): f </span><span class="si">{</span><span class="n">POST12</span><span class="p">[</span><span class="n">mm</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">f</span><span class="si">}</span><span class="s"> Q </span><span class="si">{</span><span class="n">POST12</span><span class="p">[</span><span class="n">mm</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s"> -&gt; df/f </span><span class="si">{</span><span class="p">(</span><span class="n">f</span> <span class="o">-</span> <span class="n">POST12</span><span class="p">[</span><span class="n">mm</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="n">POST12</span><span class="p">[</span><span class="n">mm</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">2</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"C done in </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_c</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="c1"># ================================================================ D. disc on a ground plane, near vs far flux
</span><span class="n">t_d</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">RES_DISC</span><span class="p">,</span> <span class="n">PML_DISC</span><span class="p">,</span> <span class="n">AIR</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">1.0</span>
<span class="n">DISC_R</span><span class="p">,</span> <span class="n">N_DISC</span> <span class="o">=</span> <span class="mf">1.2</span><span class="p">,</span> <span class="mf">2.4</span>
<span class="n">DISC_T</span> <span class="o">=</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_DISC</span>
<span class="n">NPOL</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">THETA_D</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="n">NPOL</span><span class="p">)</span>
<span class="n">disc</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">cell_r</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">6.0</span><span class="p">,</span> <span class="mf">8.0</span><span class="p">):</span>
    <span class="n">sr</span> <span class="o">=</span> <span class="n">cell_r</span> <span class="o">+</span> <span class="n">PML_DISC</span><span class="p">;</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">DISC_T</span> <span class="o">+</span> <span class="n">AIR</span> <span class="o">+</span> <span class="n">PML_DISC</span>
    <span class="n">src_pt</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DISC_R</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DISC_T</span><span class="p">)</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_DISC</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">),</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span>
                        <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">PML_DISC</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">PML_DISC</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)],</span>   <span class="c1"># no PML at the bottom: PEC ground plane
</span>                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.1</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">src_pt</span><span class="p">)],</span>
                        <span class="n">geometry</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_DISC</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DISC_R</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DISC_T</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">DISC_R</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DISC_T</span><span class="p">))])</span>
    <span class="n">regs</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">cell_r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">PML_DISC</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cell_r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cell_r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">PML_DISC</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">AIR</span> <span class="o">+</span> <span class="n">DISC_T</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">AIR</span> <span class="o">+</span> <span class="n">DISC_T</span><span class="p">))]</span>
    <span class="n">flux</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
    <span class="n">n2f</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="k">if</span> <span class="n">cell_r</span> <span class="o">==</span> <span class="mf">6.0</span><span class="p">:</span>
        <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">],</span> <span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">cell_r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">PML_DISC</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cell_r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">PML_DISC</span><span class="p">))</span>
        <span class="n">annotated_layout</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">PML_DISC</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mf">3.8</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">,</span>
                         <span class="n">title</span><span class="o">=</span><span class="s">"part D: disc (n = 2.4, R = 1.2 um) on a ground plane, cylindrical (r, z); bottom edge = PEC (no PML)"</span><span class="p">,</span>
                         <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">WL</span><span class="si">}</span><span class="s"> um, res=</span><span class="si">{</span><span class="n">RES_DISC</span><span class="si">}</span><span class="se">\n</span><span class="s">m = -1, t = </span><span class="si">{</span><span class="n">DISC_T</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> um"</span><span class="p">,</span> <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">3.4</span><span class="p">,</span> <span class="mf">0.33</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">6.05</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.6</span><span class="p">),</span>
                         <span class="n">decay_point</span><span class="o">=</span><span class="p">(</span><span class="n">src_pt</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">.</span><span class="n">z</span><span class="p">),</span> <span class="n">decay_text_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.45</span><span class="p">),</span>
                         <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"disc"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.9</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">.</span><span class="n">z</span> <span class="o">+</span> <span class="mf">0.05</span><span class="p">),</span> <span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"Er ring source at r = 0.6"</span><span class="p">,</span> <span class="p">(</span><span class="n">src_pt</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">.</span><span class="n">z</span><span class="p">),</span> <span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"flux + near2far: top and outer r (open at the bottom)"</span><span class="p">,</span> <span class="p">(</span><span class="mf">5.0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">PML_DISC</span><span class="p">),</span> <span class="p">(</span><span class="mf">3.4</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">,</span> <span class="mf">1e-8</span><span class="p">))</span>
    <span class="n">f_near</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">flux</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">e</span><span class="p">,</span> <span class="n">h</span> <span class="o">=</span> <span class="n">farfields</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">n2f</span><span class="p">,</span> <span class="n">tol</span><span class="o">=</span><span class="mf">1e-8</span><span class="p">,</span> <span class="n">theta</span><span class="o">=</span><span class="n">THETA_D</span><span class="p">)</span>
    <span class="n">pat</span> <span class="o">=</span> <span class="n">radial_flux</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">h</span><span class="p">)</span>
    <span class="n">f_far</span> <span class="o">=</span> <span class="n">total_flux</span><span class="p">(</span><span class="n">pat</span><span class="p">,</span> <span class="n">theta</span><span class="o">=</span><span class="n">THETA_D</span><span class="p">)</span>
    <span class="n">er</span> <span class="o">=</span> <span class="n">orient_rz</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="nb">round</span><span class="p">(</span><span class="n">cell_r</span> <span class="o">*</span> <span class="n">RES_DISC</span><span class="p">)))</span> <span class="k">if</span> <span class="n">dft</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">disc</span><span class="p">[</span><span class="n">cell_r</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"near"</span><span class="p">:</span> <span class="n">f_near</span><span class="p">,</span> <span class="s">"far"</span><span class="p">:</span> <span class="n">f_far</span><span class="p">,</span> <span class="s">"gap"</span><span class="p">:</span> <span class="nb">abs</span><span class="p">(</span><span class="n">f_near</span> <span class="o">-</span> <span class="n">f_far</span><span class="p">)</span> <span class="o">/</span> <span class="n">f_near</span><span class="p">,</span> <span class="s">"pattern"</span><span class="p">:</span> <span class="n">pat</span><span class="p">,</span> <span class="s">"er"</span><span class="p">:</span> <span class="n">er</span><span class="p">,</span> <span class="s">"sz"</span><span class="p">:</span> <span class="n">sz</span><span class="p">}</span>
    <span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"D: cell r </span><span class="si">{</span><span class="n">cell_r</span><span class="si">}</span><span class="s">: near flux </span><span class="si">{</span><span class="n">f_near</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, far flux </span><span class="si">{</span><span class="n">f_far</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, gap </span><span class="si">{</span><span class="mi">100</span> <span class="o">*</span> <span class="n">disc</span><span class="p">[</span><span class="n">cell_r</span><span class="p">][</span><span class="s">'gap'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> %"</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"D done in </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_d</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="c1"># ================================================================ figures (master only)
</span><span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
    <span class="c1"># A
</span>    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">4.6</span><span class="p">),</span> <span class="n">subplot_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"projection"</span><span class="p">:</span> <span class="s">"polar"</span><span class="p">})</span>
    <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">lab</span> <span class="ow">in</span> <span class="p">((</span><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s">"z"</span><span class="p">,</span> <span class="s">"z-dipole: m = 0 (Ez)  vs sin^2"</span><span class="p">),</span> <span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s">"x"</span><span class="p">,</span> <span class="s">"x-dipole: m = +1 and m = -1  vs cos^2"</span><span class="p">)):</span>
        <span class="n">a</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">THETA</span><span class="p">,</span> <span class="n">pat_on</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">/</span> <span class="n">pat_on</span><span class="p">[</span><span class="n">k</span><span class="p">].</span><span class="nb">max</span><span class="p">(),</span> <span class="s">"b-"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.6</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Meep (cylindrical)"</span><span class="p">)</span>
        <span class="n">a</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">THETA</span><span class="p">,</span> <span class="n">an_on</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="s">"r--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"analytic"</span><span class="p">)</span>
        <span class="n">a</span><span class="p">.</span><span class="n">set_theta_zero_location</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_theta_direction</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_thetamin</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_thetamax</span><span class="p">(</span><span class="mi">90</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_rmax</span><span class="p">(</span><span class="mf">1.05</span><span class="p">)</span>
        <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">lab</span><span class="si">}</span><span class="se">\n</span><span class="s">rel L2 </span><span class="si">{</span><span class="n">err_on</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"part A: on-axis dipoles (angle from +z, phi = 0 plane). A linearly polarized in-plane dipole is two m runs"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_on_axis.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
    <span class="c1"># B
</span>    <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">4.4</span><span class="p">))</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">ms</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">m_flux</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">semilogy</span><span class="p">(</span><span class="n">ms</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">m_flux</span><span class="p">)</span> <span class="o">/</span> <span class="nb">max</span><span class="p">(</span><span class="n">m_flux</span><span class="p">),</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="n">POWER_DECAY</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"stop: 1e-4 of the max"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"azimuthal order m"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"far-field power of the m term / max"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"dipole at r = </span><span class="si">{</span><span class="n">R_SRC</span><span class="si">}</span><span class="s"> um: how much each m radiates"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">"both"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">semilogy</span><span class="p">(</span><span class="n">ms</span><span class="p">,</span> <span class="n">m_err</span><span class="p">,</span> <span class="s">"s-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"m included up to"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"rel L2 of the summed pattern vs cos^2"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"the pattern converges as m terms are added"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">"both"</span><span class="p">)</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">"polar"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">THETA</span><span class="p">,</span> <span class="n">pat_off</span> <span class="o">/</span> <span class="n">pat_off</span><span class="p">.</span><span class="nb">max</span><span class="p">(),</span> <span class="s">"b-"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.6</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"Meep, m = 0..</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">THETA</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">THETA</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">,</span> <span class="s">"r--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"cos^2"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_zero_location</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_direction</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamin</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamax</span><span class="p">(</span><span class="mi">90</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_rmax</span><span class="p">(</span><span class="mf">1.05</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"off-axis x-dipole: rel L2 </span><span class="si">{</span><span class="n">m_err</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"part B: a point away from the axis is a Fourier series over m; each m is one 2D (r, z) run"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_off_axis.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
    <span class="c1"># C: Ez(r) and the x-y reconstruction for m = 3, 4, 5
</span>    <span class="n">rr</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span> <span class="o">+</span> <span class="n">PAD</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">ring</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">"ez_r"</span><span class="p">]))</span>
    <span class="n">L</span> <span class="o">=</span> <span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span> <span class="o">+</span> <span class="mf">1.5</span>
    <span class="n">xg</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="n">L</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="mi">301</span><span class="p">);</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">meshgrid</span><span class="p">(</span><span class="n">xg</span><span class="p">,</span> <span class="n">xg</span><span class="p">,</span> <span class="n">indexing</span><span class="o">=</span><span class="s">"ij"</span><span class="p">);</span> <span class="n">RG</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">hypot</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">);</span> <span class="n">PH</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arctan2</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">12.5</span><span class="p">,</span> <span class="mf">7.8</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"height_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">]})</span>
    <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">mm</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">)):</span>
        <span class="n">d</span> <span class="o">=</span> <span class="n">ring</span><span class="p">[</span><span class="n">mm</span><span class="p">];</span> <span class="n">ez</span> <span class="o">=</span> <span class="n">d</span><span class="p">[</span><span class="s">"ez_r"</span><span class="p">]</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="s">"ez_r"</span><span class="p">]))</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">rr</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ez</span><span class="p">),</span> <span class="s">"b-"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Re"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">rr</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez</span><span class="p">),</span> <span class="s">"k-"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"|Ez|"</span><span class="p">)</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">axvspan</span><span class="p">(</span><span class="n">R_IN</span><span class="p">,</span> <span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.25</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"r [a]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"m = </span><span class="si">{</span><span class="n">mm</span><span class="si">}</span><span class="s">: f = </span><span class="si">{</span><span class="n">d</span><span class="p">[</span><span class="s">'f'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, Q = </span><span class="si">{</span><span class="n">d</span><span class="p">[</span><span class="s">'Q'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> (one 1D radial run)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
        <span class="n">field</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">RG</span><span class="p">,</span> <span class="n">rr</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ez</span><span class="p">))</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">mm</span> <span class="o">*</span> <span class="n">PH</span><span class="p">)</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">RG</span><span class="p">,</span> <span class="n">rr</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">imag</span><span class="p">(</span><span class="n">ez</span><span class="p">))</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">mm</span> <span class="o">*</span> <span class="n">PH</span><span class="p">))</span>
        <span class="n">field</span><span class="p">[</span><span class="n">RG</span> <span class="o">&gt;</span> <span class="n">rr</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">lim</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field</span><span class="p">))</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">field</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="o">-</span><span class="n">L</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="o">-</span><span class="n">L</span><span class="p">,</span> <span class="n">L</span><span class="p">],</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">rc</span> <span class="ow">in</span> <span class="p">(</span><span class="n">R_IN</span><span class="p">,</span> <span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span><span class="p">):</span>
            <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Circle</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">rc</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">))</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"Re[Ez(r) exp(i </span><span class="si">{</span><span class="n">mm</span><span class="si">}</span><span class="s"> phi)]: </span><span class="si">{</span><span class="mi">2</span> <span class="o">*</span> <span class="n">mm</span><span class="si">}</span><span class="s"> sign lobes; post 12: f </span><span class="si">{</span><span class="n">POST12</span><span class="p">[</span><span class="n">mm</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [a]"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [a]"</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"part C: post 12's ring as one radial run per m; the 2D picture is rebuilt from exp(i m phi)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_ring_cyl.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
    <span class="c1"># D
</span>    <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">13.5</span><span class="p">,</span> <span class="mf">4.4</span><span class="p">))</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">"polar"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">cr</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">((</span><span class="mf">6.0</span><span class="p">,</span> <span class="s">"tab:blue"</span><span class="p">),</span> <span class="p">(</span><span class="mf">8.0</span><span class="p">,</span> <span class="s">"tab:orange"</span><span class="p">)):</span>
        <span class="n">p</span> <span class="o">=</span> <span class="n">disc</span><span class="p">[</span><span class="n">cr</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">];</span> <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">THETA_D</span><span class="p">,</span> <span class="n">p</span> <span class="o">/</span> <span class="n">disc</span><span class="p">[</span><span class="mf">6.0</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">].</span><span class="nb">max</span><span class="p">(),</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">c</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.4</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"cell r </span><span class="si">{</span><span class="n">cr</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> um"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_zero_location</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_direction</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamin</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamax</span><span class="p">(</span><span class="mi">90</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"disc on a ground plane: far-field pattern"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
    <span class="n">idx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">disc</span><span class="p">[</span><span class="n">c</span><span class="p">][</span><span class="s">"near"</span><span class="p">]</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">6.0</span><span class="p">,</span> <span class="mf">8.0</span><span class="p">)],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"near flux (monitor)"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">disc</span><span class="p">[</span><span class="n">c</span><span class="p">][</span><span class="s">"far"</span><span class="p">]</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">6.0</span><span class="p">,</span> <span class="mf">8.0</span><span class="p">)],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"far flux (hemisphere integral)"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">((</span><span class="mf">6.0</span><span class="p">,</span> <span class="mf">8.0</span><span class="p">)):</span>
        <span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="nb">max</span><span class="p">(</span><span class="n">disc</span><span class="p">[</span><span class="n">c</span><span class="p">][</span><span class="s">"near"</span><span class="p">],</span> <span class="n">disc</span><span class="p">[</span><span class="n">c</span><span class="p">][</span><span class="s">"far"</span><span class="p">])</span> <span class="o">*</span> <span class="mf">1.02</span><span class="p">,</span> <span class="sa">f</span><span class="s">"gap </span><span class="si">{</span><span class="mi">100</span> <span class="o">*</span> <span class="n">disc</span><span class="p">[</span><span class="n">c</span><span class="p">][</span><span class="s">'gap'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> %"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_xticklabels</span><span class="p">([</span><span class="s">"cell r 6 um"</span><span class="p">,</span> <span class="s">"cell r 8 um"</span><span class="p">]);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"power (a.u.)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"the open near2far surface misses currents on the ground plane"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
    <span class="n">er</span> <span class="o">=</span> <span class="n">disc</span><span class="p">[</span><span class="mf">6.0</span><span class="p">][</span><span class="s">"er"</span><span class="p">];</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">disc</span><span class="p">[</span><span class="mf">6.0</span><span class="p">][</span><span class="s">"sz"</span><span class="p">]</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">log10</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">er</span><span class="p">)</span> <span class="o">+</span> <span class="mf">1e-12</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">PML_DISC</span><span class="p">],</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"auto"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Rectangle</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span><span class="p">),</span> <span class="n">DISC_R</span><span class="p">,</span> <span class="n">DISC_T</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"r [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"z [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"log10 |Er| at 1 um (r, z plane)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"part D: near vs far flux; the gap shrinks when the radial cell grows"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"06_disc.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
    <span class="c1"># GIF: m = 3 mode rotating: Re[Ez(r) exp(i (3 phi - w t))]
</span>    <span class="n">d</span> <span class="o">=</span> <span class="n">ring</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> <span class="n">ez</span> <span class="o">=</span> <span class="n">d</span><span class="p">[</span><span class="s">"ez_r"</span><span class="p">]</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="s">"ez_r"</span><span class="p">]))</span>
    <span class="n">Er_</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">RG</span><span class="p">,</span> <span class="n">rr</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ez</span><span class="p">));</span> <span class="n">Ei_</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">RG</span><span class="p">,</span> <span class="n">rr</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">imag</span><span class="p">(</span><span class="n">ez</span><span class="p">));</span> <span class="n">amp</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">RG</span> <span class="o">&gt;</span> <span class="n">rr</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">fig_g</span><span class="p">,</span> <span class="n">ax_g</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">4.8</span><span class="p">,</span> <span class="mf">4.4</span><span class="p">))</span>
    <span class="n">im</span> <span class="o">=</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">zeros_like</span><span class="p">(</span><span class="n">RG</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="o">-</span><span class="n">L</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="o">-</span><span class="n">L</span><span class="p">,</span> <span class="n">L</span><span class="p">],</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">rc</span> <span class="ow">in</span> <span class="p">(</span><span class="n">R_IN</span><span class="p">,</span> <span class="n">R_IN</span> <span class="o">+</span> <span class="n">W</span><span class="p">):</span>
        <span class="n">ax_g</span><span class="p">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Circle</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">rc</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">))</span>
    <span class="n">ax_g</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [a]"</span><span class="p">);</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [a]"</span><span class="p">);</span> <span class="n">ttl</span> <span class="o">=</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">fig_g</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">()</span>
    <span class="n">NF</span> <span class="o">=</span> <span class="mi">36</span>

    <span class="k">def</span> <span class="nf">upd</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
        <span class="n">wt</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">i</span> <span class="o">/</span> <span class="n">NF</span>
        <span class="n">fld</span> <span class="o">=</span> <span class="n">amp</span> <span class="o">*</span> <span class="p">(</span><span class="n">Er_</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="mi">3</span> <span class="o">*</span> <span class="n">PH</span> <span class="o">-</span> <span class="n">wt</span><span class="p">)</span> <span class="o">-</span> <span class="n">Ei_</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="mi">3</span> <span class="o">*</span> <span class="n">PH</span> <span class="o">-</span> <span class="n">wt</span><span class="p">))</span>
        <span class="n">im</span><span class="p">.</span><span class="n">set_data</span><span class="p">((</span><span class="n">fld</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fld</span><span class="p">))).</span><span class="n">T</span><span class="p">);</span> <span class="n">ttl</span><span class="p">.</span><span class="n">set_text</span><span class="p">(</span><span class="sa">f</span><span class="s">"m = 3 mode, Re[Ez(r) exp(i(3 phi - wt))], wt = </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">wt</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">im</span><span class="p">,</span> <span class="n">ttl</span>

    <span class="n">animation</span><span class="p">.</span><span class="n">FuncAnimation</span><span class="p">(</span><span class="n">fig_g</span><span class="p">,</span> <span class="n">upd</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="n">NF</span><span class="p">,</span> <span class="n">blit</span><span class="o">=</span><span class="bp">False</span><span class="p">).</span><span class="n">save</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"07_anim_m3.gif"</span><span class="p">),</span> <span class="n">writer</span><span class="o">=</span><span class="n">animation</span><span class="p">.</span><span class="n">PillowWriter</span><span class="p">(</span><span class="n">fps</span><span class="o">=</span><span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">75</span><span class="p">)</span>
    <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig_g</span><span class="p">)</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f_</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"A"</span><span class="p">:</span> <span class="p">{</span><span class="s">"err_z"</span><span class="p">:</span> <span class="n">err_on</span><span class="p">[</span><span class="s">"z"</span><span class="p">],</span> <span class="s">"err_x"</span><span class="p">:</span> <span class="n">err_on</span><span class="p">[</span><span class="s">"x"</span><span class="p">]},</span>
                   <span class="s">"B"</span><span class="p">:</span> <span class="p">{</span><span class="s">"r_src"</span><span class="p">:</span> <span class="n">R_SRC</span><span class="p">,</span> <span class="s">"m_last"</span><span class="p">:</span> <span class="n">m</span><span class="p">,</span> <span class="s">"m_flux_rel"</span><span class="p">:</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">m_flux</span><span class="p">)</span> <span class="o">/</span> <span class="nb">max</span><span class="p">(</span><span class="n">m_flux</span><span class="p">)).</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"m_err"</span><span class="p">:</span> <span class="n">m_err</span><span class="p">},</span>
                   <span class="s">"C"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="n">k</span><span class="p">):</span> <span class="p">{</span><span class="s">"f"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"f"</span><span class="p">],</span> <span class="s">"Q"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"Q"</span><span class="p">],</span> <span class="s">"post12_f"</span><span class="p">:</span> <span class="n">POST12</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="s">"post12_Q"</span><span class="p">:</span> <span class="n">POST12</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="mi">1</span><span class="p">]}</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">ring</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"D"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="n">k</span><span class="p">):</span> <span class="p">{</span><span class="s">"near"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"near"</span><span class="p">],</span> <span class="s">"far"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"far"</span><span class="p">],</span> <span class="s">"gap"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"gap"</span><span class="p">]}</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">disc</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"np"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">count_processors</span><span class="p">(),</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">},</span> <span class="n">f_</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"total </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s on </span><span class="si">{</span><span class="n">mp</span><span class="p">.</span><span class="n">count_processors</span><span class="p">()</span><span class="si">}</span><span class="s"> process(es)"</span><span class="p">)</span></code></pre></figure>

</details>
<details>
  <summary>원본 실행 기록과 재현 환경</summary>

  <p>§4의 발췌 코드와 달리 전체 코드에는 두 layout 그림, m 급수 수렴 그림, 고리의 x–y 복원, 디스크 field, GIF, result.json 기록이 들어 있다. MPI로 돌릴 수 있게 collective 호출(run, get_farfield, get_dft_array)은 모든 rank에서, 그림 저장은 master에서만 한다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

  <p><strong>실행 결과 (2026-10-23 실행, mpirun -np 4)</strong>:</p>
  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A: on-axis z-dipole (m = 0) vs sin^2: rel L2 0.0043; x-dipole (m = +1 and -1) vs cos^2: 0.0046; 53 s
B: m = 0: power of this m / max = 1.00e+00; pattern error after summing 0..0: 0.5890
B: m = 1: power of this m / max = 9.36e-01; pattern error after summing 0..1: 0.4094
B: m = 2: power of this m / max = 1.00e+00; pattern error after summing 0..2: 0.0987
B: m = 3: power of this m / max = 6.36e-01; pattern error after summing 0..3: 0.1405
B: m = 4: power of this m / max = 1.80e-01; pattern error after summing 0..4: 0.0298
B: m = 5: power of this m / max = 2.79e-02; pattern error after summing 0..5: 0.0087
B: m = 6: power of this m / max = 2.78e-03; pattern error after summing 0..6: 0.0064
B: m = 7: power of this m / max = 1.90e-04; pattern error after summing 0..7: 0.0064
B: m = 8: power of this m / max = 9.49e-06; pattern error after summing 0..8: 0.0063
B: off-axis x-dipole at r = 0.5: stopped at m = 8; final rel L2 vs cos^2 0.0063; 139 s
C: m = 3: cylindrical f 0.11821 Q 77 | post 12 (2D, res 20): f 0.11818 Q 79 -&gt; df/f +2.30e-04
C: m = 4: cylindrical f 0.14746 Q 343 | post 12 (2D, res 20): f 0.14736 Q 342 -&gt; df/f +6.62e-04
C: m = 5: cylindrical f 0.17582 Q 1627 | post 12 (2D, res 20): f 0.17564 Q 2132 -&gt; df/f +1.02e-03
D: cell r 6.0: near flux 643.6506, far flux 595.8024, gap 7.43 %
D: cell r 8.0: near flux 643.2784, far flux 602.0512, gap 6.41 %
total 457 s on 4 process(es)
</code></pre></div>  </div>

  <p><strong>재현 환경</strong>: meep 1.33.0 (MPI) · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep=*=mpi_mpich_*</code> · 실행 <code class="language-plaintext highlighter-rouge">mpirun -np 4 python cylindrical_dipole.py</code> (약 7.6 min (mpirun -np 4))</p>

</details>

<h3 id="공식-문서와-다음-글">공식 문서와 다음 글</h3>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Cylindrical_Coordinates/">Cylindrical coordinates 튜토리얼</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/#radiation-pattern-of-an-antenna-in-cylindrical-coordinates">antenna in cylindrical coordinates</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/#radiation-pattern-of-a-disc-in-cylindrical-coordinates">disc in cylindrical coordinates</a></li>
  <li>스크립트: <a href="https://github.com/NanoComp/meep/blob/master/python/examples/dipole_in_vacuum_cyl_on_axis.py">dipole_in_vacuum_cyl_on_axis.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/dipole_in_vacuum_cyl_off_axis.py">dipole_in_vacuum_cyl_off_axis.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/ring-cyl.py">ring-cyl.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/disc_radiation_pattern.py">disc_radiation_pattern.py</a> · <a href="https://github.com/NanoComp/meep/issues/2704">meep issue 2704 (Er at r = 0)</a></li>
  <li>이전 글: <a href="/meep-examples/ring-resonator/">12 · 빛을 가두는 고리</a> · near2far와 거울: <a href="/meep-examples/dipole-pattern-3d/">10 · 점광원의 3D 방사 패턴</a> · 다음 글: 14 · 박막 속 점광원, 공기로 나오는 몫</li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="cylindrical" /><category term="azimuthal-order" /><category term="near2far" /><category term="dipole" /><category term="disc" /><category term="ring-resonator" /><summary type="html"><![CDATA[post 12's ring was a 2D cross-section; real discs, rings, lenses and LED mesas are bodies of revolution. `dimensions=mp.CYLINDRICAL` solves them as one 2D (r, z) run per azimuthal order m, with fields ∝ exp(imφ). Four official examples: on-axis dipoles, an off-axis dipole as an m series, post 12's ring as one radial run per m, and a disc on a ground plane radiating through an open near2far surface.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/13/04_off_axis.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/13/04_off_axis.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 10 · 점광원의 3D 방사 패턴 — Bloch 1D run 묶음과 PEC 거울의 image dipole</title><link href="https://jin-castle.github.io/meep-examples/dipole-pattern-3d/" rel="alternate" type="text/html" title="Meep Example 10 · 점광원의 3D 방사 패턴 — Bloch 1D run 묶음과 PEC 거울의 image dipole" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/dipole-pattern-3d</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/dipole-pattern-3d/"><![CDATA[<h2 id="observe">1. 먼저 보기: 점광원은 모든 방향으로 똑같이 빛날까?</h2>

<p>01편의 2D 점원에서 한 걸음 나아가, <strong>진동하는 축이 있는 3D 쌍극자</strong>를 봅니다. x 방향으로 진동하면 x축 방향은 어둡고, 그 축에 수직인 면에서는 고르게 빛납니다. 이를 큰 3D 셀 대신 방향별 1D 계산을 모아 재현할 수 있습니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/03_vacuum_pattern.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/03_vacuum_pattern.png" alt="240개 Bloch 1D 계산으로 재구성한 진공 x 쌍극자의 3D 방사 패턴과 해석해 비교" /></a>
<figcaption>계산한 240개 방향에서 올바르게 환산한 패턴의 상대 L2 오차는 0.22%입니다. 아래 지도의 회색 띠는 계산하지 않은 각도이며, 빛이 나오지 않는 영역이라는 뜻이 아닙니다.</figcaption>
</figure>

<p class="lesson-note"><strong>3D 패턴과 2D 그림을 구별하세요.</strong> 파트 A·C는 Bloch 1D run 묶음으로 3D Ex 쌍극자의 방향별 성분을 구합니다. 파트 B의 거울 애니메이션은 별도의 2D Ez 모델입니다. 모든 패턴 비교는 최대값으로 정규화한 모양이며 절대 방출 power나 directivity를 검증한 결과는 아닙니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/06_anim_pec.gif" data-lightbox=""><img src="/meep-examples/assets/meep/10/06_anim_pec.gif" data-animation-src="/meep-examples/assets/meep/10/06_anim_pec.gif" data-static-src="/meep-examples/assets/meep/10/04_pec_field.png" alt="2D Ez 쌍극자와 반대 부호의 image가 거울면에서 상쇄하는 펄스 전파" /></a>
<button type="button" class="animation-toggle" hidden="">애니메이션 정지</button>
<figcaption>파트 B의 실제 2D 펄스입니다. 위쪽 source와 아래쪽 image가 y = 0에서 상쇄합니다. 위쪽 절반만 거울 위의 물리적 공간입니다.</figcaption>
</figure>

<h2 id="predict">2. 먼저 예측하기: 계산하지 않은 방향을 어떻게 읽을까?</h2>

<fieldset class="prediction">
<legend>방사 패턴 지도에서 약 72° 이상의 방향이 회색으로 비어 있다면?</legend>
<label><input type="radio" name="dipole-prediction" value="null" /> 그 방향으로는 빛이 전혀 나가지 않는다.</label>
<label><input type="radio" name="dipole-prediction" value="missing" /> 계산하지 않은 표본이므로 방사 세기를 판단할 수 없다.</label>
</fieldset>

<details>
  <summary>예측과 계산 조건 비교하기</summary>

  <p>두 번째입니다. 파트 A는 sin θ &gt; 0.95인 방향을 건너뜁니다. 거의 옆으로 진행하는 파는 z 방향 PML에 비스듬하게 들어가 흡수가 어려워집니다. 이 빈칸을 0으로 채워 해석해와 비교하면 물리적인 null과 누락된 데이터를 혼동합니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기: 한 방향씩 계산하고, 거울은 image로 보기</h2>

<p>점광원의 field를 평면파 성분으로 나누면, 횡방향 파수 <code>k_point</code> 하나가 나가는 방향 하나에 대응합니다. 각 방향에서 z축을 따라 계산하고, 얻은 flux를 <strong>S_r = S_z cos θ</strong>로 환산한 뒤 모읍니다. θ는 +z축으로부터 잰 각도입니다.</p>

<figure class="lesson-figure">
<svg viewBox="0 0 320 210" role="img" aria-labelledby="dipole-bloch-title" xmlns="http://www.w3.org/2000/svg">
<title id="dipole-bloch-title">설명용 도식: z축만 계산하고 k_point로 비스듬한 전파 방향을 지정한다</title>
<rect width="320" height="210" fill="#f5f8fa" />
<path d="M68 180V28M68 28l-6 12M68 28l6 12" stroke="#0d1b2a" fill="none" stroke-width="2" />
<rect x="53" y="46" width="30" height="119" fill="#e7f7fb" stroke="#0087ad" />
<circle cx="68" cy="151" r="6" fill="#0087ad" />
<path d="M74 146L208 64M208 64l-15 1M208 64l-7 14" stroke="#0087ad" fill="none" stroke-width="3" />
<path d="M68 119Q89 117 96 132" fill="none" stroke="#526579" stroke-width="2" />
<g font-family="sans-serif" font-size="16" fill="#0d1b2a">
<text x="30" y="26">+z</text><text x="93" y="119">θ</text>
<text x="109" y="42">k_point → 방향</text>
<text x="109" y="171">1D 셀은 z만 계산</text>
<text x="18" y="200">방향별 표본 → 환산 → 3D 패턴</text>
</g>
</svg>
<figcaption>설명용 도식입니다. 화살표는 수치 field가 아니라 하나의 평면파 방향을 나타냅니다. 방향을 바꿔 반복한 여러 1D run이 3D 패턴을 구성합니다.</figcaption>
</figure>

<p>cos θ는 단순히 z flux를 진행 방향으로 돌리는 투영만으로 정해지는 값이 아닙니다. 횡방향 파수 공간의 표본을 입체각당 power로 바꾸는 Jacobian까지 포함합니다. 원본 계산에서 곱하면 오차 0.22%, 그대로 쓰면 53%, 나누면 76%였습니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/07_anim_1d.gif" data-lightbox=""><img src="/meep-examples/assets/meep/10/07_anim_1d.gif" data-animation-src="/meep-examples/assets/meep/10/07_anim_1d.gif" data-static-src="/meep-examples/assets/meep/10/02_layout_1d.png" alt="45도 방향을 나타내는 한 Bloch 1D 계산에서 z축을 따라 이동하는 Ex 펄스" /></a>
<button type="button" class="animation-toggle" hidden="">애니메이션 정지</button>
<figcaption>파트 A의 실제 1D run 한 개, θ = 45°입니다. 비스듬한 평면파 성분을 z축에서 관찰한 모습으로, 3D 공간 전체의 애니메이션은 아닙니다.</figcaption>
</figure>

<p>거울 옆에서는 반사된 field가 source의 field와 더해집니다. 거울에 평행한 전기 쌍극자는 거울 아래 같은 거리에 <strong>부호가 반대인 image</strong>를 놓아 설명할 수 있습니다. 둘의 경로차 2h cos θ가 방향마다 달라서 밝은 방향과 어두운 방향이 번갈아 생깁니다.</p>

<figure class="lesson-figure">
<svg viewBox="0 0 320 210" role="img" aria-labelledby="dipole-image-title" xmlns="http://www.w3.org/2000/svg">
<title id="dipole-image-title">설명용 도식: PEC 위 쌍극자와 거울 아래 반대 부호 image의 대칭 위치</title>
<rect width="320" height="210" fill="#f5f8fa" />
<path d="M22 107H296" stroke="#0d1b2a" stroke-width="5" />
<circle cx="86" cy="58" r="8" fill="#0087ad" /><circle cx="86" cy="156" r="8" fill="#526579" />
<path d="M86 68V97M86 117V146" stroke="#526579" stroke-dasharray="4 4" stroke-width="2" />
<g font-family="sans-serif" font-size="16" fill="#0d1b2a">
<text x="111" y="62">실제 쌍극자 (+)</text><text x="111" y="161">image (−)</text>
<text x="40" y="85">h</text><text x="40" y="139">h</text>
<text x="175" y="98">PEC 면</text><text x="23" y="199">접선 전기장이 거울면에서 상쇄</text>
</g>
</svg>
<figcaption>거울의 경계 조건을 설명하는 도식이며, 아래쪽 image는 실제로 추가한 광원이 아닙니다. 파트 B는 이 대칭으로 2D 거울 문제를 풉니다.</figcaption>
</figure>

<p>파트 B는 2D Ez·배경 n = 1.2·파장 650 nm·높이 h = 1.25 µm입니다. 반면 파트 C의 Bloch 계산은 <code>k_point</code> 때문에 셀 벽이 주기경계이므로, 아래쪽에 <strong>명시적인 mp.metal 블록</strong>을 넣어 거울을 만듭니다. 모든 거울은 손실 없는 PEC입니다.</p>

<h2 id="run">4. 직접 실행하기: 거울과의 거리만 줄이기</h2>

<p>Meep 1.33.0이 있는 환경에서 저장소의 <code>code/</code> 폴더에서 원본을 실행하고 결과를 따로 보관합니다. 단일 코어의 기존 실행 기록은 약 4.3분입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">OMP_NUM_THREADS</span><span class="o">=</span>1 python dipole_pattern_3d.py
</code></pre></div></div>

<p><strong>높이 H만 1.25에서 0.3 µm로 바꿔</strong> 같은 명령을 실행하세요. 전체 코드의 <code>H = 1.25</code>를 <code>H = 0.3</code>으로 바꿉니다. 파트 B와 C가 공유하는 높이이므로 두 방법에 같은 변화가 적용됩니다.</p>

<p><code>05_pec_pattern.png</code>에서 밝은 봉우리(lobe)의 개수와 각도를 원본과 비교하세요. h가 작아지면 위상차의 변화 폭도 작아져 봉우리가 줄어들 것으로 예상할 수 있습니다. 새 봉우리 위치와 오차는 실행 결과에서 읽고, 진공인 파트 A의 0.22%와 거울 계산의 오차를 섞지 마세요.</p>

<h2 id="interpret">5. 결과 해석하기: 정확한 패턴에도 적용 범위가 있다</h2>

<table>
  <thead>
    <tr>
      <th>원본에서 비교한 것</th>
      <th style="text-align: right">상대 L2 오차</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>진공 3D 패턴, 계산한 240개 방향</td>
      <td style="text-align: right">0.22%</td>
    </tr>
    <tr>
      <td>2D near2far와 해석 array factor</td>
      <td style="text-align: right">0.66%</td>
    </tr>
    <tr>
      <td>거울 위 1D Bloch와 2D, 72° 아래</td>
      <td style="text-align: right">6.4%</td>
    </tr>
    <tr>
      <td>거울 위 1D Bloch φ = 90°와 해석해, 85°까지</td>
      <td style="text-align: right">10.5%</td>
    </tr>
  </tbody>
</table>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/05_pec_pattern.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/05_pec_pattern.png" alt="거울 위 쌍극자의 다섯 방사 봉우리와 2D near2far 및 Bloch 1D 결과의 차이" loading="lazy" /></a>
<figcaption>원본 높이 1.25 µm에서 다섯 lobe가 보이며 최대 봉우리는 12.9°입니다. 회색 띠는 72° 이상의 영역입니다. 서로 다른 모델을 정규화한 패턴의 적절한 단면에서 비교합니다.</figcaption>
</figure>

<p>거울이 없는 경우의 0.22%를 거울 문제 전체의 정확도로 가져오면 안 됩니다. 거울 계산은 72° 아래에서도 두 방법이 6.4% 다릅니다. 원문은 거울 위치의 격자 반 칸 오차와 각도 표본 간격을 가능한 원인으로 해석하며, 여기서 두 효과를 독립적으로 검증한 것은 아닙니다.</p>

<p class="lesson-note"><strong>말할 수 없는 범위.</strong> 72° 이상의 1D 방사 세기, 절대 power와 directivity, 손실 금속 거울의 응답은 검증하지 않았습니다. 2D near2far도 그 큰 각도 영역의 수렴성을 별도로 확인하지 않았습니다.</p>

<h2 id="check">6. 이해 확인하기</h2>

<ol>
  <li>1D run 하나로 3D 패턴 전체를 얻을 수 있나요? 필요한 반복과 환산을 설명해 보세요.</li>
  <li>2D 거울 애니메이션과 3D 패턴을 비교할 때, 회색 빈칸과 6.4% 오차를 어떻게 해석해야 하나요?</li>
</ol>

<details>
  <summary>두 질문의 답 확인하기</summary>

  <ol>
    <li>한 run은 한 방향의 표본입니다. 여러 <code>k_point</code>로 반복하고 z flux에 cos θ를 곱해 방향별 패턴을 구성합니다.</li>
    <li>2D Ez와 3D Ex의 적절한 단면을 정규화한 모양으로 비교합니다. 회색은 계산하지 않은 영역이고, 6.4%는 72° 아래에서도 남은 두 방법의 차이입니다. 절대 방출량의 일치를 뜻하지 않습니다.</li>
  </ol>

</details>

<h2 id="reference">7. 참고 자료와 전체 코드</h2>

<p>방향별 계산 설정, 원본의 실패 사례와 상세 수치, 전체 프로그램을 아래에 보관했습니다.</p>

<details>
  <summary>English summary</summary>

  <h3 id="tldr-english">TL;DR (English)</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/05_pec_pattern.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/05_pec_pattern.png" alt="점광원의 빛은 어느 방향으로 나갈까? — hero 원본 그림" loading="lazy" /></a>
</figure>

  <ul>
    <li><strong>What</strong>: post 01 left the point source radiating equally in all directions, in 2D. This post asks the 3D question twice. First, the 3D pattern of an x-polarized dipole in vacuum without a 3D cell: one 1D simulation per direction, with the direction encoded in a transverse Bloch wavevector. Second, the same dipole above a perfect-electric-conductor mirror, solved in 2D with an opposite-sign image dipole and a closed near2far box, and again with the 1D method.</li>
    <li><strong>Result</strong>: 240 one-dimensional runs reproduce the dipole pattern $1-\sin^2\theta\cos^2\phi$ with 0.22% relative error on the computed hemisphere; multiplying the z flux by $\cos\theta$ is the right conversion (dividing gives 76%). Above the mirror the 2D near2far pattern matches the two-element array factor $\sin^2(kh\cos\theta)$ to 0.66% with five lobes; the 1D method agrees with it to 6.4% below 72°, and breaks down at grazing angles where the PML cannot absorb a wave travelling almost parallel to it.</li>
    <li><strong>Takeaway</strong>: a 3D pattern can be bought with many cheap 1D runs, but only away from grazing angles, and the per-direction flux needs a Jacobian. An infinite mirror is never put inside a near2far box: it is replaced by an image source and a symmetry. A mirror does not just reflect; it rewrites the pattern of the source next to it.</li>
    <li><strong>Code</strong>: full script at the bottom, ~4.3 min on one core.</li>
  </ul>

</details>

<details>
  <summary>배경·물리식·파라미터 자세히 보기</summary>

  <h3 id="section">원본 §0 · 이 글에서 배우는 것</h3>

  <ul>
    <li>3D 점광원의 방사 패턴을 3D 셀 없이 얻는 법: 방향 하나 = <code class="language-plaintext highlighter-rouge">k_point</code>가 다른 1D run 하나</li>
    <li>1D run의 z flux를 입체각당 power로 바꾸는 환산 인자 $\cos\theta$와, 그것을 틀리게 잡으면 어떻게 보이는지</li>
    <li>glancing angle(72° 이상)을 공식 예제가 계산하지 않는 이유. 0으로 남은 표본은 방사 null이 아니다</li>
    <li>무한 PEC 거울을 near2far box 안에 넣을 수 없을 때: 부호가 반대인 image dipole과 <code class="language-plaintext highlighter-rouge">Mirror(Y, phase=-1)</code></li>
    <li><code class="language-plaintext highlighter-rouge">Near2FarRegion</code> 네 조각의 <code class="language-plaintext highlighter-rouge">weight</code>가 닫힌 면의 바깥 법선이라는 것</li>
    <li>두 방법(2D near2far, 1D Bloch)이 같은 array factor를 내는지, 어디서 갈라지는지</li>
  </ul>

  <p><strong>전제 지식</strong>: 01편의 점원과 flux box, 03편의 reference run. <strong>공식 예제</strong>: <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/">Near-to-far field spectra 튜토리얼</a>의 <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/#radiation-pattern-of-an-antenna-above-a-perfect-electric-conductor-ground-plane">antenna above a PEC ground plane</a>과 <a href="https://github.com/NanoComp/meep/blob/master/python/examples/dipole_in_vacuum_1D.py">dipole_in_vacuum_1D.py</a>. <strong>이전 글</strong>: <a href="/meep-examples/bend-inverse/">09 · Waveguide bend inverse design</a> · <strong>다음 글</strong>: <a href="/meep-examples/cavity-ldos/">11 · 두 거울 사이의 점광원</a></p>

  <h3 id="section-1">원본 §1 · 무엇을 알고 싶은가</h3>

  <p>01편은 2D 점원이 네 면으로 25%씩 나간다는 데서 끝났다. 실제 점광원은 3D이고 축이 있다. x 방향으로 진동하는 쌍극자는 x축 방향으로는 빛을 내지 않고 그에 수직한 면에서는 고르게 낸다. 이것을 Meep으로 확인하려면 3D 셀이 필요할 것 같지만, 공식 예제는 1D run 수백 개로 같은 답을 얻는다. 왜 그것이 가능한지, 그리고 어디서 안 되는지가 첫 질문이다. 두 번째 질문은 시즌 2의 출발점이다. 점광원 옆에 거울 하나를 두면 방사 패턴은 어떻게 바뀌는가.</p>

  <h3 id="section-2">어디에 쓰이는가</h3>

  <p>거울 위의 쌍극자는 OLED와 LED의 발광층 그 자체다. 반사 전극 위에 놓인 발광 분자의 방사 패턴이 outcoupling의 출발점이고, 1D Bloch run 묶음은 다층 OLED의 광추출 계산에서 실제로 쓰는 방법이다.</p>

  <table>
    <thead>
      <tr>
        <th>응용</th>
        <th>이 글의 어떤 것을 쓰는가</th>
        <th>그 다음에 필요한 것</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>OLED·LED: 반사 전극 위의 발광층</td>
        <td>거울 위 쌍극자의 패턴, 1D Bloch 방법(다층으로 확장 가능)</td>
        <td>14편 광추출 효율</td>
      </tr>
      <tr>
        <td>패치·모노폴 안테나(ground plane 위)</td>
        <td>image 이론, array factor sin²(kh cosθ)</td>
        <td>—</td>
      </tr>
      <tr>
        <td>양자점·단일광자원의 방출 방향</td>
        <td>3D 쌍극자 패턴, 편광 축</td>
        <td>11편 LDOS</td>
      </tr>
      <tr>
        <td>메타표면·격자의 far field</td>
        <td>닫힌 near2far box의 규칙</td>
        <td>16편 far field</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-3">원본 §2 · 물리 한 페이지</h3>

  <p>점광원의 field는 평면파의 합이다. 횡방향 파수 $\mathbf k_\perp=(k_x,k_y)$를 하나 고정하면 Maxwell 방정식은 z만 남은 1D 문제가 되고, 그 1D 해는 $e^{i\mathbf k_\perp\cdot\mathbf r_\perp}$를 곱한 평면파다. Meep에서 이것이 <code class="language-plaintext highlighter-rouge">k_point</code>다. 방향 $(\theta,\phi)$로 나가는 평면파는 $\mathbf k_\perp=f\sin\theta\,(\cos\phi,\sin\phi)$를 가지므로, 1D 셀에 쌍극자를 두고 <code class="language-plaintext highlighter-rouge">k_point</code>를 바꿔 가며 돌리면 run 하나가 방향 하나의 표본이 된다. 1D run이 주는 것은 그 평면파 성분의 z 방향 flux $S_z$다. 입체각당 power로 바꾸려면 $d^2k_\perp=f^2\cos\theta\,d\Omega$의 Jacobian이 들어가 $S_r=S_z\cos\theta$가 된다.</p>

\[\frac{dP}{d\Omega}\Big\lvert _{x\text{-dipole}}\propto 1-\sin^2\theta\cos^2\phi,\qquad
S_r(\theta,\phi)=S_z(\theta,\phi)\cos\theta,\qquad
\big\lvert 1-e^{\,i\,2kh\cos\theta}\big\lvert ^2=4\sin^2(kh\cos\theta),\quad k=\frac{2\pi n}{\lambda}\]

  <p>$\theta$가 90°에 가까우면 평면파가 PML과 거의 평행하게 진행한다. PML은 법선 방향으로 들어오는 파를 흡수하도록 만든 층이라 이 파는 흡수되지 않고 셀을 오간다. 공식 예제는 $|\mathbf k_\perp|&gt;0.95f$, 즉 $\theta&gt;71.8°$를 계산하지 않는다.</p>

  <p>거울 위의 쌍극자는 image 이론으로 푼다. 거울에 접한 전기장은 0이어야 하므로 거울 아래 같은 거리에 부호가 반대인 쌍극자를 두면 거울면에서 두 field가 상쇄된다. 거울을 지우고 쌍극자 둘을 두는 것과 같다. 둘의 경로차가 $2h\cos\theta$이므로 방사 패턴에 array factor $4\sin^2(kh\cos\theta)$가 곱해진다. 2D Ez 쌍극자의 자체 패턴은 등방이라 2D에서는 이 인자가 패턴의 전부다.</p>

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$\theta,\phi$</td>
        <td>극각(+z 또는 거울 법선에서), 방위각(x축에서)</td>
        <td><code class="language-plaintext highlighter-rouge">POLAR</code>, <code class="language-plaintext highlighter-rouge">AZIM</code>, <code class="language-plaintext highlighter-rouge">THETA_B</code></td>
      </tr>
      <tr>
        <td>$\mathbf k_\perp$</td>
        <td>횡방향 Bloch 파수 $f\sin\theta(\cos\phi,\sin\phi)$</td>
        <td><code class="language-plaintext highlighter-rouge">k_point</code></td>
      </tr>
      <tr>
        <td>$S_z$, $S_r$</td>
        <td>1D run의 z flux, 환산한 radial flux</td>
        <td><code class="language-plaintext highlighter-rouge">flux_z</code>, <code class="language-plaintext highlighter-rouge">radial</code></td>
      </tr>
      <tr>
        <td>$h$</td>
        <td>쌍극자와 거울 사이 거리</td>
        <td><code class="language-plaintext highlighter-rouge">H</code></td>
      </tr>
      <tr>
        <td>$kh$</td>
        <td>경로차의 위상 척도</td>
        <td><code class="language-plaintext highlighter-rouge">K_B * H</code></td>
      </tr>
      <tr>
        <td>image</td>
        <td>부호 −1인 두 번째 source</td>
        <td><code class="language-plaintext highlighter-rouge">amplitude=-1.0</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 파트 A는 진공, 단일 주파수, Ex 편광. 파트 B는 2D Ez(거울에 접한 편광), 배경 n = 1.2, 파장 650 nm, 거울은 손실 없는 PEC. 파트 C는 3D Ex 쌍극자이고 거울은 1D 셀 아래쪽의 명시적인 <code class="language-plaintext highlighter-rouge">mp.metal</code> 블록이다. <code class="language-plaintext highlighter-rouge">k_point</code>가 있으면 셀 벽 자체는 Bloch 주기경계다. 패턴은 모두 최대값으로 정규화한 모양 비교이며 절대 power는 다루지 않는다.</p>

  <h3 id="section-4">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1D run 묶음 vs 해석 패턴 (계산한 반구)</td>
        <td>2% 안</td>
        <td>10_sources 노트의 10×12 격자에서 1.99%</td>
      </tr>
      <tr>
        <td>z flux → radial flux 환산</td>
        <td>$\cos\theta$를 곱한다</td>
        <td>Jacobian $d^2k_\perp=f^2\cos\theta\,d\Omega$</td>
      </tr>
      <tr>
        <td>$\phi=90°$ 단면</td>
        <td>상수(등방)</td>
        <td>쌍극자 축에 수직한 면</td>
      </tr>
      <tr>
        <td>2D PEC near2far vs array factor</td>
        <td>1% 안</td>
        <td>노트의 res 100에서 0.47%</td>
      </tr>
      <tr>
        <td>거울면 $y=0$의 $\lvert E_z\rvert$</td>
        <td>0</td>
        <td>odd symmetry가 강제</td>
      </tr>
      <tr>
        <td>0~90°의 lobe 수</td>
        <td>5개 (12.8°, 40.7°, 57.2°, 71.0°, 83.8°)</td>
        <td>$kh=14.5$, 극대는 $kh\cos\theta=(m+\tfrac12)\pi$</td>
      </tr>
      <tr>
        <td>1D Bloch PEC($\phi=90°$) vs 2D near2far</td>
        <td>72° 아래에서 2% 안</td>
        <td>같은 array factor, 쌍극자 인자는 그 면에서 1</td>
      </tr>
      <tr>
        <td>72° 위의 1D run</td>
        <td>틀어진다</td>
        <td>PML이 평행파를 흡수하지 못한다</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: 계산한 반구의 상대 L2 &gt; 5%면 환산 인자나 <code class="language-plaintext highlighter-rouge">k_point</code>를 의심한다. $y=0$의 $\lvert E_z\rvert$가 최대의 수 % 이상이면 symmetry 위상이 틀렸다(격자 반 칸 때문에 정확히 0은 아니다). 두 방법이 72° 아래에서 10% 이상 다르면 한쪽의 거울이나 monitor 위치를 의심한다.</p>

  <h3 id="section-5">원본 §3 · 시뮬레이션 설계도</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/02_layout_1d.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/02_layout_1d.png" alt="파트 A·C의 1D 셀. z축만 계산한다. 양 끝 PML(파트 C는 위쪽만, 아래는 PEC), 빨간 선 = Ex 쌍극자, 파란 네모 = flux 점. 보라색 화살표가 `k_point`로 정해지는 전파 방향이다. 동그라미 숫자는 §4의" loading="lazy" /></a>
<figcaption>파트 A·C의 1D 셀. z축만 계산한다. 양 끝 PML(파트 C는 위쪽만, 아래는 PEC), 빨간 선 = Ex 쌍극자, 파란 네모 = flux 점. 보라색 화살표가 <code class="language-plaintext highlighter-rouge">k_point</code>로 정해지는 전파 방향이다. 동그라미 숫자는 §4의 단계 번호다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/01_layout.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/01_layout.png" alt="파트 B의 2D 셀(7 × 7 µm, n = 1.2). 빨간 점 두 개가 물리 쌍극자(y = +1.25)와 image 쌍극자(y = −1.25, 진폭 −1), 파란 사각형이 닫힌 near2far box, 녹색 빗금이 PML. y = " loading="lazy" /></a>
<figcaption>파트 B의 2D 셀(7 × 7 µm, n = 1.2). 빨간 점 두 개가 물리 쌍극자(y = +1.25)와 image 쌍극자(y = −1.25, 진폭 −1), 파란 사각형이 닫힌 near2far box, 녹색 빗금이 PML. y = 0이 유효 PEC 면이고 위쪽 절반만 물리적이다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>A 파장, 해상도, 공기층</td>
        <td>1 µm, res 50, 10 µm</td>
        <td>패턴은 스케일에 무관. 공식 예제 값</td>
        <td>해상도는 환산 인자와 무관하다</td>
      </tr>
      <tr>
        <td>A 각도 격자</td>
        <td>극각 13 × 방위각 24</td>
        <td>공식 30 × 50의 축소판. 7.5°·15° 간격</td>
        <td>촘촘할수록 run 수에 비례해 느려진다</td>
      </tr>
      <tr>
        <td>A glancing 한계</td>
        <td>$\sin\theta&gt;0.95$ 건너뜀</td>
        <td>공식 규칙. PML 평행파</td>
        <td>계산하면 run이 오래 걸리고 값이 틀린다(파트 C에서 보임)</td>
      </tr>
      <tr>
        <td>A 종료</td>
        <td>Ex 감쇠 1e-6 (25 단위 창)</td>
        <td>공식 예제 값</td>
        <td>설정이 맞으면 run당 1초 안에 끝난다</td>
      </tr>
      <tr>
        <td>A <code class="language-plaintext highlighter-rouge">k_point</code></td>
        <td>$nf(\sin\theta\cos\phi,\ \sin\theta\sin\phi,\ \cos\theta)$</td>
        <td>z 성분으로 항상 $\mathbf k\neq0$</td>
        <td>§4 ③</td>
      </tr>
      <tr>
        <td>B 파장, n, h</td>
        <td>650 nm, 1.2, 1.25 µm</td>
        <td>공식 예제 값. $kh=14.5$</td>
        <td>h가 작아지면 lobe가 줄어든다</td>
      </tr>
      <tr>
        <td>B 해상도</td>
        <td>100</td>
        <td>노트와 같다. 파장당 83칸</td>
        <td>50이면 L2가 커진다</td>
      </tr>
      <tr>
        <td>B near2far box</td>
        <td>반폭 2 µm</td>
        <td>두 쌍극자(±1.25)를 감싼다</td>
        <td>box가 한쪽 쌍극자만 감싸면 image 이론이 깨진다</td>
      </tr>
      <tr>
        <td>B 원거리 반지름</td>
        <td>1000 λ</td>
        <td>far field 근사</td>
        <td>—</td>
      </tr>
      <tr>
        <td>C 셀</td>
        <td>metal 0.5 + h 1.25 + 공기 10 + PML 1 µm</td>
        <td><code class="language-plaintext highlighter-rouge">k_point</code>가 있으면 셀 벽은 Bloch 주기라 거울은 <code class="language-plaintext highlighter-rouge">mp.metal</code> 블록으로</td>
        <td>벽을 거울로 믿으면 거울이 없다(§4 ④)</td>
      </tr>
      <tr>
        <td>C 종료</td>
        <td>고정 150 time unit</td>
        <td>85°의 파가 공기 10 µm(n 1.2)를 가로지르는 시간 140</td>
        <td>감쇠 조건은 glancing에서 정체</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/00_source.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/00_source.png" alt="파트 B의 source 파형과 스펙트럼(650 nm, fwidth 0.2 fcen). 파트 A는 파장 1 µm에 같은 상대 대역폭이다." loading="lazy" /></a>
<figcaption>파트 B의 source 파형과 스펙트럼(650 nm, fwidth 0.2 fcen). 파트 A는 파장 1 µm에 같은 상대 대역폭이다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 강의 범위 밖이다. 01편(강의 week 2)의 점광원을 3D와 거울로 확장한다. 10_sources의 두 PEC 노트가 각각 2D near2far(L2 0.47%)와 1D Bloch(상관 0.947)를 따로 다뤘는데, 이 글은 둘을 같은 축에 올려 어디서 갈라지는지 본다.</p>

</details>

<details>
  <summary>원본 코드 단계별 설명</summary>

  <h3 id="section-6">원본 §4 · 코드 따라가기</h3>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
파트 A·C는 1D라 ②가 없고, 파트 B는 ②가 “거울 대신 image + symmetry”다.</p>
  </blockquote>

  <h3 id="section-7">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">POLAR</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">90.1</span><span class="p">,</span> <span class="mf">7.5</span><span class="p">))</span>      <span class="c1"># 13 polar angles (0 = +z)
</span><span class="n">AZIM</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">360.0</span><span class="p">,</span> <span class="mf">15.0</span><span class="p">))</span>     <span class="c1"># 24 azimuth angles
</span><span class="n">GLANCING</span> <span class="o">=</span> <span class="mf">0.95</span>                                     <span class="c1"># skip k_perp &gt; 0.95 f (official rule)
</span><span class="n">T_AFTER</span> <span class="o">=</span> <span class="mf">60.0</span>                                      <span class="c1"># run time after the source turns off
</span>
<span class="n">WL_B</span><span class="p">,</span> <span class="n">N_B</span><span class="p">,</span> <span class="n">H</span><span class="p">,</span> <span class="n">RES_B</span> <span class="o">=</span> <span class="mf">0.65</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">,</span> <span class="mf">1.25</span><span class="p">,</span> <span class="mi">100</span>          <span class="c1"># PEC mirror part: wavelength, background index, height, resolution
</span><span class="n">K_B</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">N_B</span> <span class="o">/</span> <span class="n">WL_B</span>                        <span class="c1"># k h = 14.5 sets the lobes
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 파트 A의 각도 격자와 glancing 한계, 파트 B의 거울 문제 파라미터.</li>
    <li><strong>왜</strong>: 각도 격자는 run 수다. 13 × 24에서 glancing 3행을 빼면 240 run. $kh$는 lobe의 수와 위치를 정하므로 파장·굴절률·높이 셋을 한 묶음으로 적는다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">K_B</code>에 배경 굴절률을 빼먹으면 array factor의 lobe가 다른 각도에 온다.</li>
  </ul>

  <h3 id="image-symmetry">② 재료와 구조 — 거울 대신 image와 symmetry</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sources_B</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH_B</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">H</span><span class="p">)),</span>
             <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH_B</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">H</span><span class="p">),</span> <span class="n">amplitude</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">)]</span>
<span class="n">symB</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">)]</span>        <span class="c1"># odd in y -&gt; Ez = 0 on y = 0 (the PEC plane)
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 거울은 geometry에 없다. 부호가 반대인 두 번째 쌍극자와 y에 대한 odd mirror symmetry가 거울이다.</li>
    <li><strong>왜</strong>: 무한 PEC 판을 near2far box가 가로지를 수 없다. 두 쌍극자를 box가 감싸게 하면 변환 가정이 유지된다. symmetry는 계산을 1/4로 줄이고 $y=0$의 $E_z=0$을 정확히 강제한다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">phase=-1</code>을 빼면 두 쌍극자가 같은 부호로 더해져 $y=0$이 node가 아니라 antinode가 되고, 패턴은 $\cos^2$ 형이 된다. Hz 편광이면 image 부호와 parity가 반대다.</li>
  </ul>

  <h3 id="source--1d---kpoint">③ Source — 1D 셀의 쌍극자와 k_point</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">bloch_k</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">phi</span><span class="p">,</span> <span class="n">fcen</span><span class="p">,</span> <span class="n">n_index</span><span class="o">=</span><span class="mf">1.0</span><span class="p">):</span>          <span class="c1"># full wavevector of the outgoing plane wave, |k| = n f
</span>    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">n_index</span> <span class="o">*</span> <span class="n">fcen</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">phi</span><span class="p">),</span> <span class="n">n_index</span> <span class="o">*</span> <span class="n">fcen</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">phi</span><span class="p">),</span> <span class="n">n_index</span> <span class="o">*</span> <span class="n">fcen</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">))</span>

<span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES_A</span><span class="p">,</span> <span class="n">k_point</span><span class="o">=</span><span class="n">bloch_k</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">phi</span><span class="p">,</span> <span class="n">fcen</span><span class="p">,</span> <span class="n">n_index</span><span class="p">),</span>   <span class="c1"># no dimensions=1 (see below)
</span>                    <span class="n">default_material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">n_index</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML_A</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">)],</span>
                    <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z_src</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())])</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 셀은 z 한 줄이고 source는 그 위의 한 점이다. <code class="language-plaintext highlighter-rouge">k_point</code>가 나가는 평면파의 파수 벡터 전체(횡방향 두 성분과 z 성분)를 준다.</li>
    <li><strong>왜</strong>: 같은 1D 구조에서 <code class="language-plaintext highlighter-rouge">k_point</code>만 바꾸면 다른 방향의 평면파 성분이 된다. 3D 셀을 돌리지 않고 방향별 표본을 얻는 원리다. z 성분은 PML이 흡수하는 방향이라 물리에는 영향이 없지만, $\theta=0$에서도 $\mathbf k\neq0$이 되게 해 모든 run이 복소 field를 쓰도록 만든다.</li>
    <li><strong>틀리면</strong>: 두 가지를 이 글에서 직접 겪었다. <code class="language-plaintext highlighter-rouge">dimensions=1</code>을 명시하면 횡방향 k가 조용히 무시되어 flux가 각도에 무관해진다(패턴 L2 35%). z 성분 없이 $\theta=0$을 돌리면 그 run만 실수 field가 되어 power가 1/4로 나온다. 셀 크기 <code class="language-plaintext highlighter-rouge">(0, 0, sz)</code>만으로 1D가 되므로 <code class="language-plaintext highlighter-rouge">dimensions</code>는 쓰지 않는다.</li>
  </ul>

  <h3 id="simulation---pml--">④ Simulation과 경계 — PML의 방향과 거울</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML_A</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">)]</span>                     <span class="c1"># part A: both ends of z
</span><span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML_A</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)]</span>       <span class="c1"># part C: PML on top only ...
</span><span class="n">mirror</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">Z_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DMETAL</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DMETAL</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">metal</span><span class="p">)]</span>   <span class="c1"># ... and a PEC block at the bottom
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 파트 A는 양 끝 PML. 파트 C는 위쪽만 PML이고 아래에는 <code class="language-plaintext highlighter-rouge">mp.metal</code>(완전도체) 블록을 둔다. 그 블록의 윗면이 거울이다.</li>
    <li><strong>왜</strong>: 01편에서는 PML 없는 셀 벽이 거울이었다. 그러나 <code class="language-plaintext highlighter-rouge">k_point</code>를 주면 모든 셀 벽이 Bloch 주기 경계로 바뀌므로 아래 벽은 더 이상 완전도체가 아니다. 거울은 geometry로 넣어야 한다.</li>
    <li><strong>틀리면</strong>: 이 글의 두 번째 실행이 그랬다. 아래 벽을 거울로 믿고 PML만 위에 두었더니 패턴이 array factor와 43% 어긋났다. 아래 벽이 위쪽 PML로 이어지는 주기 경계였기 때문이다.</li>
  </ul>

  <h3 id="monitor--1d-flux--2d-near2far-box">⑤ Monitor — 1D의 flux 점과 2D의 near2far box</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mon</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z_mon</span><span class="p">)))</span>          <span class="c1"># a point in 1D: Poynting z-flux
</span>
<span class="n">n2f</span> <span class="o">=</span> <span class="n">sim_B</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">BOX</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">BOX</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span>
        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">)),</span>
        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mi">1</span><span class="p">))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 1D에서는 flux monitor가 점 하나다. 2D에서는 네 조각이 닫힌 사각형을 이루고 아래·왼쪽 조각의 <code class="language-plaintext highlighter-rouge">weight=-1</code>이 바깥 법선을 맞춘다.</li>
    <li><strong>왜</strong>: near2far 변환은 닫힌 면 위의 등가 전류에서 먼 field를 계산한다. 면이 열려 있거나 법선 부호가 틀리면 변환이 성립하지 않는다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">weight</code>를 빼면 아래 조각이 안쪽을 보게 되어 패턴이 뒤틀린다. 01편의 flux box에서 면의 방향을 맞춘 것과 같은 규칙이다.</li>
  </ul>

  <h3 id="section-8">⑥ 실행 — 감쇠 조건과 고정 시간</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">mon_pt</span><span class="p">,</span> <span class="mf">1e-6</span><span class="p">))</span>   <span class="c1"># part A (official): until Ex at the flux point has decayed
</span><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">T_C</span><span class="p">)</span>                                                    <span class="c1"># part C: fixed 150 time units (grazing angles included)
</span><span class="n">sim_B</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_dft_decayed</span><span class="p">(</span><span class="n">tol</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">))</span>                   <span class="c1"># part B: until the DFT monitors stop changing
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 파트 A는 공식 예제처럼 flux 점의 Ex가 감쇠할 때까지. 파트 C는 고정 시간. 파트 B는 DFT 수렴까지.</li>
    <li><strong>왜</strong>: 파트 C는 일부러 glancing 각까지 돌린다. 그 각에서는 PML이 흡수하지 못한 파가 셀을 오가며 감쇠 조건이 오래 정체하므로, 85°의 파가 공기층 10 µm를 가로지르는 시간(약 140)에서 상한을 정했다.</li>
    <li><strong>틀리면</strong>: 고정 시간이 짧으면 큰 $\theta$의 run에서 펄스가 monitor에 닿기 전에 끝나 패턴이 바깥쪽에서 꺼진다. 감쇠 조건을 glancing 각에 쓰면 run이 수십 분을 돈다.</li>
  </ul>

  <h3 id="jacobian---">⑦ 후처리 — Jacobian, 정규화, 해석해 비교</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">radial</span> <span class="o">=</span> <span class="n">flux_z</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">POLAR</span><span class="p">)[:,</span> <span class="bp">None</span><span class="p">]</span>                        <span class="c1"># S_r = S_z cos(theta)
</span><span class="n">analytic_A</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">TH</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">PH</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span>              <span class="c1"># x-dipole, up to a constant
</span><span class="n">err</span> <span class="o">=</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">norm</span><span class="p">(</span><span class="n">radial</span><span class="p">),</span> <span class="n">norm</span><span class="p">(</span><span class="n">analytic_A</span><span class="p">))</span>                    <span class="c1"># both normalized to their maximum
</span>
<span class="n">ff</span> <span class="o">=</span> <span class="n">sim_B</span><span class="p">.</span><span class="n">get_farfield</span><span class="p">(</span><span class="n">n2f</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_FF</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">th</span><span class="p">),</span> <span class="n">R_FF</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">th</span><span class="p">)))</span>
<span class="n">S</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">cross</span><span class="p">(</span><span class="n">E</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">H</span><span class="p">)));</span>  <span class="n">pattern_B</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">hypot</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">array_factor</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">K_B</span> <span class="o">*</span> <span class="n">H</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">))</span> <span class="o">**</span> <span class="mi">2</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: z flux에 $\cos\theta$를 곱하고 최대값으로 정규화해 해석 패턴과 L2로 비교한다. 2D는 far field의 Poynting 크기를 각도별로 구한다.</li>
    <li><strong>왜</strong>: 정규화한 모양만 비교한다. 1D run의 절대 flux와 2D near2far의 절대 power는 단위가 달라 같은 축에 둘 수 없다.</li>
    <li><strong>틀리면</strong>: $\cos\theta$로 나누면 L2가 76%로 커진다(§5 그림의 빨간 ×). 계산하지 않은 glancing 표본을 0으로 넣고 L2를 재면 오차가 수십 %가 되는데 그것은 물리가 아니라 빈칸이다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: 이 글의 첫 실행은 <code class="language-plaintext highlighter-rouge">dimensions=1</code>을 명시한 채였고, 그때는 $\theta=0$의 감쇠 조건이 time step 백만을 넘겨도 멈추지 않았으며 flux는 모든 각도에서 같았다. <code class="language-plaintext highlighter-rouge">dimensions</code>를 지우고 <code class="language-plaintext highlighter-rouge">k_point</code>에 z 성분을 넣자 공식 예제의 감쇠 조건이 run당 1초 안에 끝났다. 멈추지 않는 run은 대개 종료 조건이 아니라 설정의 문제다. <code class="language-plaintext highlighter-rouge">until_after_sources</code>에 조건 두 개를 리스트로 주면 둘 다 만족해야 멈추므로 <code class="language-plaintext highlighter-rouge">stop_after_walltime</code>은 상한이 되지 못한다.</p>
  </blockquote>

</details>

<details>
  <summary>원본 결과·검증 표·오류 진단·추가 탐구</summary>

  <h3 id="section-9">원본 §5 · 결과</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/03_vacuum_pattern.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/03_vacuum_pattern.png" alt="파트 A. 위: =0 단면은 ^2, =90° 단면은 상수. 파란 점이 S_z, 빨간 ×가 S_z/(틀린 환산). 오른쪽 막대가 세 환산의 L2. 아래: 계산한 반구의 Meep·해석·차이 지도. 회색 띠는 계산하지 않은 glancing" loading="lazy" /></a>
<figcaption>파트 A. 위: $\phi=0$ 단면은 $\cos^2\theta$, $\phi=90°$ 단면은 상수. 파란 점이 $S_z\cos\theta$, 빨간 ×가 $S_z/\cos\theta$(틀린 환산). 오른쪽 막대가 세 환산의 L2. 아래: 계산한 반구의 Meep·해석·차이 지도. 회색 띠는 계산하지 않은 glancing 영역이다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>환산</th>
        <th>상대 L2 (계산한 240 표본)</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$S_z\cos\theta$</td>
        <td>0.22%</td>
      </tr>
      <tr>
        <td>$S_z$ 그대로</td>
        <td>53%</td>
      </tr>
      <tr>
        <td>$S_z/\cos\theta$</td>
        <td>76%</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/03b_vacuum_pattern_wrong_setup.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/03b_vacuum_pattern_wrong_setup.png" alt="같은 스크립트의 첫 실행. `dimensions=1`을 명시하고 `k_point`에 z 성분이 없었다. Meep 지도(왼쪽 아래)가 에 전혀 의존하지 않고 =0 행만 어둡다. 두 증상이 각각 &quot;횡방향 k가 무시됨&quot;과" loading="lazy" /></a>
<figcaption>같은 스크립트의 첫 실행. <code class="language-plaintext highlighter-rouge">dimensions=1</code>을 명시하고 <code class="language-plaintext highlighter-rouge">k_point</code>에 z 성분이 없었다. Meep 지도(왼쪽 아래)가 $\phi$에 전혀 의존하지 않고 $\theta=0$ 행만 어둡다. 두 증상이 각각 “횡방향 k가 무시됨”과 “k = 0이라 실수 field”의 지문이다. L2 0.35. 그림은 틀렸지만 어디가 틀렸는지를 말해 주기 때문에 남겨 둔다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/04_pec_field.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/04_pec_field.png" alt="파트 B. 쌍극자 + image의 정상상태 Ez. 흰 점선 y=0이 거울면이고 그 위의  E_z는 최대의 0.012배다. 위쪽 절반만 물리적이다. 점선 사각형이 near2far box." loading="lazy" /></a>
<figcaption>파트 B. 쌍극자 + image의 정상상태 Ez. 흰 점선 $y=0$이 거울면이고 그 위의 $\lvert E_z\rvert$는 최대의 0.012배다. 위쪽 절반만 물리적이다. 점선 사각형이 near2far box.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/10/05_pec_pattern.png" data-lightbox=""><img src="/meep-examples/assets/meep/10/05_pec_pattern.png" alt="왼쪽: 거울 위 쌍극자의 패턴. 파란 선이 2D near2far, 검은 점선이 array factor, 초록 점이 1D Bloch(=90°), 빨간 ×가 glancing 각. 가운데: =0 단면은 array factor에 쌍극자의 ^" loading="lazy" /></a>
<figcaption>왼쪽: 거울 위 쌍극자의 패턴. 파란 선이 2D near2far, 검은 점선이 array factor, 초록 점이 1D Bloch($\phi=90°$), 빨간 ×가 glancing 각. 가운데: $\phi=0$ 단면은 array factor에 쌍극자의 $\cos^2\theta$가 곱해진다. 오른쪽: 각도별 오차. 회색 띠가 72° 위다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>방법</th>
        <th>비교 대상</th>
        <th>상대 L2</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>B: 2D near2far (Ez)</td>
        <td>$\sin^2(kh\cos\theta)$, 50각</td>
        <td>0.66% (peak bin 차이 0)</td>
      </tr>
      <tr>
        <td>C: 1D Bloch (Ex, $\phi=90°$), 72° 아래</td>
        <td>$\sin^2(kh\cos\theta)$</td>
        <td>6.8%</td>
      </tr>
      <tr>
        <td>C: 같은 것, 85°까지 포함</td>
        <td>〃</td>
        <td>10.5% (상관 0.981)</td>
      </tr>
      <tr>
        <td>C: 1D Bloch ($\phi=0$), 72° 아래</td>
        <td>$\cos^2\theta\,\sin^2(kh\cos\theta)$</td>
        <td>6.0%</td>
      </tr>
      <tr>
        <td>B vs C, 72° 아래</td>
        <td>서로</td>
        <td>6.4%</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-10">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1D run 묶음 vs 해석 패턴</td>
        <td>2% 안</td>
        <td>0.22%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>환산 인자</td>
        <td>$\cos\theta$ 곱</td>
        <td>곱 0.22%, 나눔 76%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>$\phi=90°$ 단면</td>
        <td>상수</td>
        <td>상수</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>2D PEC vs array factor</td>
        <td>1% 안</td>
        <td>0.66%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>$y=0$의 $\lvert E_z\rvert$</td>
        <td>0</td>
        <td>최대의 0.012배</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>lobe 수</td>
        <td>5개</td>
        <td>5개, 최대 12.9°</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>1D Bloch PEC vs 2D</td>
        <td>2% 안</td>
        <td>6.4%</td>
        <td>❌ (6.4%)</td>
      </tr>
      <tr>
        <td>72° 위의 1D run</td>
        <td>틀어짐</td>
        <td>85°까지 넣으면 L2 10.5%</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>예측 여덟 중 일곱이 맞았고 하나가 틀렸다. 1D Bloch 방법은 거울 위에서도 lobe의 위치와 수를 정확히 재현하지만 진폭이 72° 아래에서도 6% 어긋난다. 원인은 두 가지로 본다. 거울 면이 Yee 격자의 반 칸(10 nm) 안에서 불확실해 $kh$가 0.12 rad 흔들리면 $\theta=0$의 lobe 진폭이 5% 바뀐다. 그리고 5° 간격 표본은 폭이 10° 남짓한 lobe의 봉우리와 골을 비껴 지나므로 정규화의 기준이 되는 최대값 자체가 표본 위치에 좌우된다. 2D near2far는 이 두 문제가 없고 0.66%다. 10_sources의 1D Bloch PEC 노트가 상관 0.947에서 멈춘 것은 같은 한계이고, 이 글은 glancing 각을 빼면 0.98, 넣으면 0.105의 L2로 그 경계를 숫자로 남긴다. 진공에서는 거울이 없으니 격자 반 칸 문제가 없고 0.22%가 나온다.</p>

  <h3 id="section-11">수렴성</h3>

  <table>
    <thead>
      <tr>
        <th>변수</th>
        <th>값</th>
        <th>결과</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>A 각도 격자</td>
        <td>13 × 24 (이 글) vs 30 × 50 (노트 0724)</td>
        <td>L2 0.22% vs 0.22%</td>
        <td>표본 수는 L2를 바꾸지 않는다. 각 표본이 독립된 run이라 격자는 해상도가 아니라 그림의 촘촘함이다. 노트 0722의 1.99%는 고정 시간 종료의 값</td>
      </tr>
      <tr>
        <td>C glancing 포함 여부</td>
        <td>72° 아래 / 85°까지</td>
        <td>6.8% / 10.5%</td>
        <td>노트 0722의 상관 0.947은 glancing을 포함한 값이었다</td>
      </tr>
      <tr>
        <td>B 해상도</td>
        <td>100 (이 글, 노트와 동일)</td>
        <td>0.66%</td>
        <td>노트 0.47%. 해상도 사다리는 직접 해보기</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-12">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: x 쌍극자의 3D 패턴은 72° 아래에서 1D run 묶음으로 0.22% 안에 재현된다. $S_z\cos\theta$가 맞는 환산이다. 거울 위 쌍극자의 패턴은 image 이론의 array factor와 0.66% 안에서 같고, 1D 방법도 72° 아래에서는 같은 답을 준다.</li>
    <li>할 수 없는 것: 72° 위의 방사 세기. 1D 방법은 그 영역을 계산하지 못하고, 이 글의 2D near2far도 그 영역의 수렴성을 따로 보지 않았다. 절대 power와 directivity. 손실 있는 금속 거울. y 편광과 다른 해상도로의 일반화.</li>
  </ul>

  <h3 id="section-13">원본 §6 · 흔한 실수</h3>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>flux가 각도에 무관, 패턴 L2 35%</td>
        <td><code class="language-plaintext highlighter-rouge">dimensions=1</code>을 명시해 횡방향 k가 무시됨</td>
        <td><code class="language-plaintext highlighter-rouge">dimensions</code>를 빼고 <code class="language-plaintext highlighter-rouge">cell_size=(0, 0, sz)</code>로만 1D를 만든다</td>
      </tr>
      <tr>
        <td>$\theta=0$ run만 power가 1/4</td>
        <td>$\mathbf k=0$이라 실수 field로 전환</td>
        <td><code class="language-plaintext highlighter-rouge">k_point</code>에 z 성분 $f\cos\theta$를 넣어 항상 복소 field</td>
      </tr>
      <tr>
        <td>1D run이 끝나지 않음</td>
        <td>위 설정 오류, 또는 glancing 각의 PML 정체</td>
        <td>설정을 고치고, glancing 각은 고정 <code class="language-plaintext highlighter-rouge">until_after_sources</code></td>
      </tr>
      <tr>
        <td>패턴이 $\theta$ 큰 쪽에서 과대</td>
        <td>$S_z/\cos\theta$ 환산</td>
        <td>$S_z\cos\theta$</td>
      </tr>
      <tr>
        <td>반구 L2가 30%대</td>
        <td>계산하지 않은 glancing 표본을 0으로 포함</td>
        <td>계산한 표본만 비교하고 빈칸은 빈칸으로 그린다</td>
      </tr>
      <tr>
        <td>$y=0$이 antinode</td>
        <td>image 부호 또는 <code class="language-plaintext highlighter-rouge">phase=-1</code> 누락</td>
        <td>Ez는 odd, Hz는 even</td>
      </tr>
      <tr>
        <td>lobe 각도가 전부 어긋남</td>
        <td>$k$에 배경 굴절률 누락</td>
        <td>$k=2\pi n/\lambda$, 파트 C의 <code class="language-plaintext highlighter-rouge">k_point</code>에도 n</td>
      </tr>
      <tr>
        <td>near2far 패턴이 뒤틀림</td>
        <td>box 조각의 <code class="language-plaintext highlighter-rouge">weight</code> 부호</td>
        <td>아래·왼쪽 조각 −1</td>
      </tr>
      <tr>
        <td>파트 C에서 거울이 사라짐(L2 43%)</td>
        <td><code class="language-plaintext highlighter-rouge">k_point</code>가 셀 벽을 Bloch 주기로 바꿈</td>
        <td>거울은 <code class="language-plaintext highlighter-rouge">mp.metal</code> 블록으로 geometry에 넣는다</td>
      </tr>
      <tr>
        <td>1D Bloch의 lobe 진폭이 5% 어긋남</td>
        <td>거울 면이 Yee 격자 반 칸(10 nm) 안에서 불확실, $kh$가 0.12 rad 흔들림</td>
        <td>해상도를 올리거나 h를 격자에 맞춘다</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-14">원본 §7 · 직접 해보기</h3>

  <table>
    <thead>
      <tr>
        <th>바꿀 것</th>
        <th>예상 변화</th>
        <th>확인할 수치</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>파트 A를 y 쌍극자로</td>
        <td>패턴이 $\phi$ 방향으로 90° 돈다</td>
        <td>$\phi=0$ 단면이 상수가 되는지</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">GLANCING</code> 0.95 → 0.99</td>
        <td>72~82° 표본이 생기지만 오차가 큼</td>
        <td>그 행의 |Meep − 해석|</td>
      </tr>
      <tr>
        <td>파트 B의 h를 0.3 µm로</td>
        <td>$kh=3.5$, lobe 1~2개</td>
        <td>peak 각도</td>
      </tr>
      <tr>
        <td>파트 B 해상도 50 / 100 / 150</td>
        <td>L2 사다리</td>
        <td>0.66%가 어디서 정체하는지</td>
      </tr>
      <tr>
        <td>파트 B를 Hz 편광으로</td>
        <td>image 부호 +1, <code class="language-plaintext highlighter-rouge">Mirror(Y, phase=+1)</code></td>
        <td>$y=0$이 antinode인지</td>
      </tr>
    </tbody>
  </table>

</details>

<details>
<summary>code/dipole_pattern_3d.py 전체 (클릭하여 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 10 - 3D radiation pattern of a point dipole: a family of 1D Bloch runs, and a PEC mirror.

Post 01 showed a 2D point source radiating equally in all directions. This post asks the 3D question in two ways.
  A. Vacuum Ex dipole, 3D pattern WITHOUT a 3D cell: one 1D simulation per direction (theta, phi), each with a
     transverse Bloch wavevector k = f (sin t cos p, sin t sin p, 0). The z flux of each run, times cos(theta),
     is one angular sample of the 3D pattern. Compared with the analytic dipole pattern 1 - sin^2(t) cos^2(p).
  B. A dipole 1.25 um above a perfect-electric-conductor (PEC) mirror, 2D (Ez): the mirror is replaced by an
     opposite-sign image dipole plus an odd mirror symmetry, and the far field comes from a closed near2far box.
     Compared with the two-element array factor sin^2(k h cos t).
  C. The same mirror problem with the 1D Bloch method of part A (3D Ex dipole, PEC = metallic cell boundary):
     the two methods agree on the pattern away from grazing angles; near grazing the 1D method breaks down.

Run:  python dipole_pattern_3d.py     (~3 min on one core)
Out:  00_source.png, 01_layout.png, 02_layout_1d.png, 03_vacuum_pattern.png, 04_pec_field.png, 05_pec_pattern.png,
      06_anim_pec.gif, 07_anim_1d.gif, result.json   (-&gt; ../assets/10/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">animation</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">_badge</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">HERE</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"10"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">rel_l2</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="nb">float</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="nb">float</span><span class="p">)</span>
    <span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="n">b</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">b</span><span class="p">))</span>


<span class="c1"># =================================================================== A. vacuum dipole via 1D Bloch runs
# ---------------------------------------------------------------- (1) parameters (official dipole_in_vacuum_1D.py, smaller grid)
</span><span class="n">WL_A</span> <span class="o">=</span> <span class="mf">1.0</span>                               <span class="c1"># wavelength [um]; the pattern is scale-free
</span><span class="n">FCEN_A</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">WL_A</span>
<span class="n">FWIDTH_A</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">FCEN_A</span>
<span class="n">RES_A</span> <span class="o">=</span> <span class="mi">50</span>
<span class="n">DPML_A</span><span class="p">,</span> <span class="n">DAIR_A</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">10.0</span>
<span class="n">SZ_A</span> <span class="o">=</span> <span class="n">DPML_A</span> <span class="o">+</span> <span class="n">DAIR_A</span> <span class="o">+</span> <span class="n">DPML_A</span>
<span class="n">Z_SRC_A</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DAIR_A</span>                  <span class="c1"># dipole at the bottom of the air gap (official)
</span><span class="n">Z_MON_A</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DAIR_A</span>                   <span class="c1"># flux point at the top of the air gap
</span><span class="n">GLANCING</span> <span class="o">=</span> <span class="mf">0.95</span>                          <span class="c1"># skip k_perp &gt; 0.95 f: PML cannot absorb nearly-parallel waves (official rule)
</span><span class="n">POLAR</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">90.1</span><span class="p">,</span> <span class="mf">7.5</span><span class="p">))</span>      <span class="c1"># 13 polar angles (0 = +z)
</span><span class="n">AZIM</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">360.0</span><span class="p">,</span> <span class="mf">15.0</span><span class="p">))</span>     <span class="c1"># 24 azimuth angles
</span>

<span class="k">def</span> <span class="nf">bloch_k</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">phi</span><span class="p">,</span> <span class="n">fcen</span><span class="p">,</span> <span class="n">n_index</span><span class="o">=</span><span class="mf">1.0</span><span class="p">):</span>
    <span class="s">"""Full wavevector of the outgoing plane wave, |k| = n f. The z component keeps k != 0 at theta = 0,
    so every run uses complex fields (a k = 0 run would switch to real fields and change the power scale by 4)."""</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">n_index</span> <span class="o">*</span> <span class="n">fcen</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">phi</span><span class="p">),</span> <span class="n">n_index</span> <span class="o">*</span> <span class="n">fcen</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">phi</span><span class="p">),</span> <span class="n">n_index</span> <span class="o">*</span> <span class="n">fcen</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">flux_1d</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">phi</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="p">,</span> <span class="n">n_index</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">sz</span><span class="o">=</span><span class="n">SZ_A</span><span class="p">,</span> <span class="n">z_src</span><span class="o">=</span><span class="n">Z_SRC_A</span><span class="p">,</span> <span class="n">z_mon</span><span class="o">=</span><span class="n">Z_MON_A</span><span class="p">,</span> <span class="n">pml</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">geometry</span><span class="o">=</span><span class="p">(),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">until</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="s">"""One 1D run: Bloch k from (theta, phi), source at z_src, Poynting z-flux at z_mon.
    NOTE: do not pass dimensions=1. The cell size (0, 0, sz) already makes the run 1D, and an explicit dimensions=1
    silently drops the transverse k (the flux then no longer depends on the angle)."""</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES_A</span><span class="p">,</span> <span class="n">k_point</span><span class="o">=</span><span class="n">bloch_k</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">phi</span><span class="p">,</span> <span class="n">fcen</span><span class="p">,</span> <span class="n">n_index</span><span class="p">),</span>
                        <span class="n">default_material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">n_index</span><span class="p">),</span> <span class="n">geometry</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="n">geometry</span><span class="p">),</span>
                        <span class="n">boundary_layers</span><span class="o">=</span><span class="n">pml</span> <span class="k">if</span> <span class="n">pml</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="k">else</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML_A</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">)],</span>
                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">component</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z_src</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())])</span>
    <span class="n">mon</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z_mon</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">until</span> <span class="k">if</span> <span class="n">until</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="k">else</span> <span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="n">component</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z_mon</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">f</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">mon</span><span class="p">)[</span><span class="mi">0</span><span class="p">]);</span> <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">f</span>


<span class="n">t_a</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">flux_z</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">full</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">POLAR</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">AZIM</span><span class="p">)),</span> <span class="n">np</span><span class="p">.</span><span class="n">nan</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">th</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">POLAR</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">th</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">GLANCING</span><span class="p">:</span>
        <span class="k">continue</span>
    <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">ph</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">AZIM</span><span class="p">):</span>
        <span class="n">flux_z</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">flux_1d</span><span class="p">(</span><span class="n">th</span><span class="p">,</span> <span class="n">ph</span><span class="p">,</span> <span class="n">fcen</span><span class="o">=</span><span class="n">FCEN_A</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH_A</span><span class="p">)</span>
<span class="n">n_runs</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="o">~</span><span class="n">np</span><span class="p">.</span><span class="n">isnan</span><span class="p">(</span><span class="n">flux_z</span><span class="p">)))</span>
<span class="n">computed</span> <span class="o">=</span> <span class="o">~</span><span class="n">np</span><span class="p">.</span><span class="n">isnan</span><span class="p">(</span><span class="n">flux_z</span><span class="p">)</span>
<span class="n">cos_t</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">POLAR</span><span class="p">)[:,</span> <span class="bp">None</span><span class="p">]</span>
<span class="n">radial</span> <span class="o">=</span> <span class="n">flux_z</span> <span class="o">*</span> <span class="n">cos_t</span>                                   <span class="c1"># official: radial flux = (kz / f) * flux_z
</span><span class="n">TH</span><span class="p">,</span> <span class="n">PH</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">meshgrid</span><span class="p">(</span><span class="n">POLAR</span><span class="p">,</span> <span class="n">AZIM</span><span class="p">,</span> <span class="n">indexing</span><span class="o">=</span><span class="s">"ij"</span><span class="p">)</span>
<span class="n">analytic_A</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">TH</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">PH</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span>        <span class="c1"># |E|^2 of an x-polarized dipole, up to a constant
</span>

<span class="k">def</span> <span class="nf">norm</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">mask</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">p</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">nanmax</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">mask</span><span class="p">,</span> <span class="n">p</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">nan</span><span class="p">))</span>


<span class="n">err_mul</span> <span class="o">=</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">norm</span><span class="p">(</span><span class="n">radial</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">],</span> <span class="n">norm</span><span class="p">(</span><span class="n">analytic_A</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">])</span>
<span class="n">err_div</span> <span class="o">=</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">norm</span><span class="p">(</span><span class="n">flux_z</span> <span class="o">/</span> <span class="n">cos_t</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">],</span> <span class="n">norm</span><span class="p">(</span><span class="n">analytic_A</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">])</span>
<span class="n">err_raw</span> <span class="o">=</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">norm</span><span class="p">(</span><span class="n">flux_z</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">],</span> <span class="n">norm</span><span class="p">(</span><span class="n">analytic_A</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">])</span>
<span class="n">j0</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j90</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">AZIM</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)))</span>
<span class="n">err_phi0</span> <span class="o">=</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">norm</span><span class="p">(</span><span class="n">radial</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">[:,</span> <span class="n">j0</span><span class="p">],</span> <span class="n">j0</span><span class="p">],</span> <span class="n">norm</span><span class="p">(</span><span class="n">analytic_A</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">computed</span><span class="p">[:,</span> <span class="n">j0</span><span class="p">],</span> <span class="n">j0</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"A: </span><span class="si">{</span><span class="n">n_runs</span><span class="si">}</span><span class="s"> 1D runs (</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">POLAR</span><span class="p">)</span><span class="si">}</span><span class="s">x</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">AZIM</span><span class="p">)</span><span class="si">}</span><span class="s"> grid, </span><span class="si">{</span><span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="o">~</span><span class="n">computed</span><span class="p">))</span><span class="si">}</span><span class="s"> glancing samples skipped) in </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_a</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s; "</span>
      <span class="sa">f</span><span class="s">"rel L2 vs analytic (computed samples): flux_z*cos = </span><span class="si">{</span><span class="n">err_mul</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, flux_z/cos = </span><span class="si">{</span><span class="n">err_div</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, flux_z raw = </span><span class="si">{</span><span class="n">err_raw</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; phi=0 cut </span><span class="si">{</span><span class="n">err_phi0</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># schematic of the 1D cell (plot2D has nothing to draw in 1D)
</span><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">8.6</span><span class="p">,</span> <span class="mf">3.2</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">axhspan</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="n">DPML_A</span> <span class="o">/</span> <span class="n">SZ_A</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"green"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.25</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">axhspan</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">xmin</span><span class="o">=</span><span class="mi">1</span> <span class="o">-</span> <span class="n">DPML_A</span> <span class="o">/</span> <span class="n">SZ_A</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"green"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.25</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="n">Z_SRC_A</span><span class="p">,</span> <span class="n">Z_SRC_A</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">3</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">Z_MON_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"s"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">th_demo</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="mi">45</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">annotate</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="n">Z_SRC_A</span> <span class="o">+</span> <span class="mf">2.2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">th_demo</span><span class="p">),</span> <span class="mf">0.45</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">th_demo</span><span class="p">)),</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="n">Z_SRC_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">arrowstyle</span><span class="o">=</span><span class="s">"-&gt;"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"purple"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.8</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="n">Z_SRC_A</span> <span class="o">+</span> <span class="mf">1.4</span><span class="p">,</span> <span class="mf">0.36</span><span class="p">,</span> <span class="s">"k = f (sin t cos p, sin t sin p, cos t)</span><span class="se">\n</span><span class="s">only the z axis is simulated"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"purple"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="k">for</span> <span class="n">xy</span><span class="p">,</span> <span class="n">step</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">txt</span><span class="p">,</span> <span class="n">txy</span> <span class="ow">in</span> <span class="p">(((</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span> <span class="o">+</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"dimgray"</span><span class="p">,</span> <span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">WL_A</span><span class="si">}</span><span class="s"> um, res=</span><span class="si">{</span><span class="n">RES_A</span><span class="si">}</span><span class="se">\n</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">POLAR</span><span class="p">)</span><span class="si">}</span><span class="s"> polar x </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">AZIM</span><span class="p">)</span><span class="si">}</span><span class="s"> azimuth runs"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span> <span class="o">+</span> <span class="mf">0.6</span><span class="p">,</span> <span class="mf">0.30</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="n">Z_SRC_A</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.42</span><span class="p">),</span> <span class="mi">3</span><span class="p">,</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"Ex dipole (GaussianSource)"</span><span class="p">,</span> <span class="p">(</span><span class="n">Z_SRC_A</span> <span class="o">+</span> <span class="mf">0.25</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.46</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPML_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"green"</span><span class="p">,</span> <span class="s">"PML (both ends)"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.15</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="n">Z_MON_A</span><span class="p">,</span> <span class="mf">0.12</span><span class="p">),</span> <span class="mi">5</span><span class="p">,</span> <span class="s">"blue"</span><span class="p">,</span> <span class="s">"flux point: Poynting z-flux"</span><span class="p">,</span> <span class="p">(</span><span class="n">Z_MON_A</span> <span class="o">-</span> <span class="mf">2.6</span><span class="p">,</span> <span class="mf">0.18</span><span class="p">)),</span>
                                   <span class="p">((</span><span class="n">Z_MON_A</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.12</span><span class="p">),</span> <span class="mi">6</span><span class="p">,</span> <span class="s">"purple"</span><span class="p">,</span> <span class="s">"decay watch point"</span><span class="p">,</span> <span class="p">(</span><span class="n">Z_MON_A</span> <span class="o">-</span> <span class="mf">1.9</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.3</span><span class="p">))):</span>
    <span class="n">_badge</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">xy</span><span class="p">,</span> <span class="n">step</span><span class="p">,</span> <span class="n">color</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="o">*</span><span class="n">txy</span><span class="p">,</span> <span class="n">txt</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_yticks</span><span class="p">([]);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"z [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"part A: one 1D cell per direction; the transverse Bloch wavevector k_point picks the direction (theta, phi)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_layout_1d.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># pattern figure: two polar cuts + hemisphere maps
</span><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">7.6</span><span class="p">))</span>
<span class="n">gs</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_gridspec</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lab</span><span class="p">,</span> <span class="n">an</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(((</span><span class="n">j0</span><span class="p">,</span> <span class="s">"phi = 0 (plane of the dipole axis): cos^2(theta)"</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">POLAR</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">),</span>
                                    <span class="p">(</span><span class="n">j90</span><span class="p">,</span> <span class="s">"phi = 90 deg (plane normal to the dipole): isotropic"</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">ones_like</span><span class="p">(</span><span class="n">POLAR</span><span class="p">)))):</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">col</span><span class="p">],</span> <span class="n">projection</span><span class="o">=</span><span class="s">"polar"</span><span class="p">)</span>
    <span class="n">m</span> <span class="o">=</span> <span class="n">computed</span><span class="p">[:,</span> <span class="n">j</span><span class="p">]</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR</span><span class="p">[</span><span class="n">m</span><span class="p">],</span> <span class="n">norm</span><span class="p">(</span><span class="n">radial</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">m</span><span class="p">,</span> <span class="n">j</span><span class="p">],</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Meep: flux_z cos(theta)"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR</span><span class="p">,</span> <span class="n">an</span><span class="p">,</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"analytic"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR</span><span class="p">[</span><span class="n">m</span><span class="p">],</span> <span class="n">norm</span><span class="p">(</span><span class="n">flux_z</span> <span class="o">/</span> <span class="n">cos_t</span><span class="p">,</span> <span class="n">computed</span><span class="p">)[</span><span class="n">m</span><span class="p">,</span> <span class="n">j</span><span class="p">],</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"flux_z / cos(theta) (wrong)"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_zero_location</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_direction</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamin</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamax</span><span class="p">(</span><span class="mi">90</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_rlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.6</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="n">lab</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span>
<span class="n">ax</span><span class="p">.</span><span class="n">bar</span><span class="p">([</span><span class="s">"flux_z cos"</span><span class="p">,</span> <span class="s">"flux_z raw"</span><span class="p">,</span> <span class="s">"flux_z / cos"</span><span class="p">],</span> <span class="p">[</span><span class="n">err_mul</span><span class="p">,</span> <span class="n">err_raw</span><span class="p">,</span> <span class="n">err_div</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="p">[</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="s">"tab:gray"</span><span class="p">,</span> <span class="s">"tab:red"</span><span class="p">])</span>
<span class="k">for</span> <span class="n">k_</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">([</span><span class="n">err_mul</span><span class="p">,</span> <span class="n">err_raw</span><span class="p">,</span> <span class="n">err_div</span><span class="p">]):</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="n">k_</span><span class="p">,</span> <span class="n">v</span> <span class="o">+</span> <span class="mf">0.01</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">v</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"relative L2 vs analytic (computed samples)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"which conversion of the z flux is the radial flux?"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">Td</span><span class="p">,</span> <span class="n">Pd</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">POLAR</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">AZIM</span><span class="p">)</span>
<span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">ttl</span><span class="p">,</span> <span class="n">cmap</span><span class="p">,</span> <span class="n">vmax</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(((</span><span class="n">norm</span><span class="p">(</span><span class="n">radial</span><span class="p">,</span> <span class="n">computed</span><span class="p">),</span> <span class="s">"Meep: normalized radial flux"</span><span class="p">,</span> <span class="s">"viridis"</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span>
                                                <span class="p">(</span><span class="n">norm</span><span class="p">(</span><span class="n">analytic_A</span><span class="p">,</span> <span class="n">computed</span><span class="p">),</span> <span class="s">"analytic 1 - sin^2(t) cos^2(p)"</span><span class="p">,</span> <span class="s">"viridis"</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span>
                                                <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">norm</span><span class="p">(</span><span class="n">radial</span><span class="p">,</span> <span class="n">computed</span><span class="p">)</span> <span class="o">-</span> <span class="n">norm</span><span class="p">(</span><span class="n">analytic_A</span><span class="p">,</span> <span class="n">computed</span><span class="p">)),</span> <span class="s">"|Meep - analytic|"</span><span class="p">,</span> <span class="s">"magma"</span><span class="p">,</span> <span class="bp">None</span><span class="p">))):</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">col</span><span class="p">])</span>
    <span class="n">pc</span> <span class="o">=</span> <span class="n">ax</span><span class="p">.</span><span class="n">pcolormesh</span><span class="p">(</span><span class="n">Pd</span><span class="p">,</span> <span class="n">Td</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">computed</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">nan</span><span class="p">),</span> <span class="n">cmap</span><span class="o">=</span><span class="n">cmap</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">vmax</span><span class="p">,</span> <span class="n">shading</span><span class="o">=</span><span class="s">"nearest"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">axhspan</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">GLANCING</span><span class="p">)),</span> <span class="mi">90</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lightgray"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">80</span><span class="p">,</span> <span class="s">"not computed (glancing)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"azimuth phi [deg]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"polar theta [deg]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="n">ttl</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">fig</span><span class="p">.</span><span class="n">colorbar</span><span class="p">(</span><span class="n">pc</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="n">ax</span><span class="p">,</span> <span class="n">shrink</span><span class="o">=</span><span class="mf">0.85</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="sa">f</span><span class="s">"3D pattern of an x-dipole from </span><span class="si">{</span><span class="n">n_runs</span><span class="si">}</span><span class="s"> 1D runs: rel L2 </span><span class="si">{</span><span class="n">err_mul</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> on the computed hemisphere"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_vacuum_pattern.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># GIF of one oblique 1D run (theta = 45 deg): Re(Ex) along z vs time
</span><span class="n">th_g</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="mi">45</span><span class="p">)</span>
<span class="n">sim_g</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">SZ_A</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES_A</span><span class="p">,</span> <span class="n">k_point</span><span class="o">=</span><span class="n">bloch_k</span><span class="p">(</span><span class="n">th_g</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="n">FCEN_A</span><span class="p">),</span>
                      <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML_A</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">)],</span>
                      <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_A</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FCEN_A</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">Z_SRC_A</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())])</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">t0g</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FCEN_A</span><span class="p">)</span>
<span class="n">frames_g</span><span class="p">,</span> <span class="n">times_g</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">t0g</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FCEN_A</span><span class="p">))</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">50</span><span class="p">):</span>
    <span class="n">sim_g</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
    <span class="n">frames_g</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">sim_g</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">SZ_A</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">)))</span>
    <span class="n">times_g</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">sim_g</span><span class="p">.</span><span class="n">meep_time</span><span class="p">())</span>
<span class="n">zs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_A</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">frames_g</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
<span class="n">lim_g</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">f</span><span class="p">))</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">frames_g</span><span class="p">)</span>
<span class="n">fig_g</span><span class="p">,</span> <span class="n">ax_g</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">7.6</span><span class="p">,</span> <span class="mf">2.9</span><span class="p">))</span>
<span class="n">ln</span><span class="p">,</span> <span class="o">=</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">zs</span><span class="p">,</span> <span class="n">frames_g</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">);</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="n">lim_g</span><span class="p">,</span> <span class="n">lim_g</span><span class="p">);</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="n">zs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">zs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="n">ax_g</span><span class="p">.</span><span class="n">axvspan</span><span class="p">(</span><span class="n">zs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">zs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">DPML_A</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"green"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.2</span><span class="p">);</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">axvspan</span><span class="p">(</span><span class="n">zs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">DPML_A</span><span class="p">,</span> <span class="n">zs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s">"green"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)</span>
<span class="n">ax_g</span><span class="p">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">Z_SRC_A</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.5</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"source"</span><span class="p">);</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">Z_MON_A</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.5</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"flux point"</span><span class="p">)</span>
<span class="n">ax_g</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"z [um]"</span><span class="p">);</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"Re(Ex)"</span><span class="p">);</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"upper right"</span><span class="p">);</span> <span class="n">ttl_g</span> <span class="o">=</span> <span class="n">ax_g</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig_g</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">_upd</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
    <span class="n">ln</span><span class="p">.</span><span class="n">set_ydata</span><span class="p">(</span><span class="n">frames_g</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="n">ttl_g</span><span class="p">.</span><span class="n">set_text</span><span class="p">(</span><span class="sa">f</span><span class="s">"one 1D run (theta = 45 deg): the pulse moves along z at c cos(theta)   t = </span><span class="si">{</span><span class="n">times_g</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> um/c"</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">ln</span><span class="p">,</span> <span class="n">ttl_g</span>


<span class="n">animation</span><span class="p">.</span><span class="n">FuncAnimation</span><span class="p">(</span><span class="n">fig_g</span><span class="p">,</span> <span class="n">_upd</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">frames_g</span><span class="p">),</span> <span class="n">blit</span><span class="o">=</span><span class="bp">False</span><span class="p">).</span><span class="n">save</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"07_anim_1d.gif"</span><span class="p">),</span> <span class="n">writer</span><span class="o">=</span><span class="n">animation</span><span class="p">.</span><span class="n">PillowWriter</span><span class="p">(</span><span class="n">fps</span><span class="o">=</span><span class="mi">10</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">80</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig_g</span><span class="p">);</span> <span class="n">sim_g</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="c1"># =================================================================== B. dipole above a PEC mirror, 2D near2far with an image dipole
# ---------------------------------------------------------------- (1) parameters (official antenna_pec_ground_plane.py)
</span><span class="n">WL_B</span> <span class="o">=</span> <span class="mf">0.65</span>
<span class="n">FCEN_B</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">WL_B</span>
<span class="n">FWIDTH_B</span> <span class="o">=</span> <span class="mf">0.2</span> <span class="o">*</span> <span class="n">FCEN_B</span>
<span class="n">N_B</span> <span class="o">=</span> <span class="mf">1.2</span>
<span class="n">H</span> <span class="o">=</span> <span class="mf">1.25</span>                                 <span class="c1"># dipole height above the mirror
</span><span class="n">RES_B</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">DPML_B</span><span class="p">,</span> <span class="n">DBULK</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">6.0</span>
<span class="n">S_B</span> <span class="o">=</span> <span class="n">DBULK</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML_B</span>                 <span class="c1"># 7 x 7 cell
</span><span class="n">R_FF</span> <span class="o">=</span> <span class="mi">1000</span> <span class="o">*</span> <span class="n">WL_B</span>
<span class="n">NANG</span> <span class="o">=</span> <span class="mi">50</span>
<span class="n">THETA_B</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="n">NANG</span><span class="p">)</span>          <span class="c1"># angle from the mirror normal (+y)
</span><span class="n">K_B</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">N_B</span> <span class="o">/</span> <span class="n">WL_B</span>
<span class="n">array_factor</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">K_B</span> <span class="o">*</span> <span class="n">H</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">))</span> <span class="o">**</span> <span class="mi">2</span>
<span class="n">array_factor</span> <span class="o">/=</span> <span class="n">array_factor</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span>

<span class="n">sources_B</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH_B</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">H</span><span class="p">)),</span>
             <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">FWIDTH_B</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">H</span><span class="p">),</span> <span class="n">amplitude</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">)]</span>   <span class="c1"># image dipole
</span><span class="n">symB</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">)]</span>                                                                        <span class="c1"># odd in y -&gt; Ez = 0 on y = 0 (PEC)
</span><span class="n">common_B</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">S_B</span><span class="p">,</span> <span class="n">S_B</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES_B</span><span class="p">,</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML_B</span><span class="p">)],</span> <span class="n">default_material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_B</span><span class="p">))</span>
<span class="n">sim_B</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">sources</span><span class="o">=</span><span class="n">sources_B</span><span class="p">,</span> <span class="n">symmetries</span><span class="o">=</span><span class="n">symB</span><span class="p">,</span> <span class="o">**</span><span class="n">common_B</span><span class="p">)</span>
<span class="n">BOX</span> <span class="o">=</span> <span class="mf">2.0</span>                                                                                                                  <span class="c1"># half-size of the near2far box (encloses both dipoles)
</span><span class="n">n2f</span> <span class="o">=</span> <span class="n">sim_B</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">BOX</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">BOX</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">)),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="n">BOX</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mi">1</span><span class="p">))</span>
<span class="n">dft_B</span> <span class="o">=</span> <span class="n">sim_B</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">FCEN_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">DBULK</span><span class="p">,</span> <span class="n">DBULK</span><span class="p">))</span>
<span class="n">annotated_layout</span><span class="p">(</span>
    <span class="n">sim_B</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML_B</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">6.6</span><span class="p">,</span> <span class="mf">6.2</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span>
    <span class="n">title</span><span class="o">=</span><span class="s">"part B: dipole above a PEC mirror = dipole + opposite image, odd mirror symmetry in y"</span><span class="p">,</span>
    <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">WL_B</span><span class="si">}</span><span class="s"> um, n=</span><span class="si">{</span><span class="n">N_B</span><span class="si">}</span><span class="se">\n</span><span class="s">h=</span><span class="si">{</span><span class="n">H</span><span class="si">}</span><span class="s"> um, res=</span><span class="si">{</span><span class="n">RES_B</span><span class="si">}</span><span class="se">\n</span><span class="s">k h = </span><span class="si">{</span><span class="n">K_B</span> <span class="o">*</span> <span class="n">H</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>
    <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">3.4</span><span class="p">,</span> <span class="mf">3.1</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.25</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
    <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"physical Ez dipole at y = +h"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.05</span><span class="p">,</span> <span class="n">H</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="mf">2.4</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"image dipole at y = -h, amplitude -1"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.05</span><span class="p">,</span> <span class="o">-</span><span class="n">H</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.4</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"y = 0: Ez = 0 here (effective PEC)"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">1.2</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">3.4</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.9</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"closed near2far box (4 segments)"</span><span class="p">,</span> <span class="p">(</span><span class="n">BOX</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="mf">1.4</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
<span class="n">source_figure</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">FWIDTH_B</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>
<span class="n">t_b</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">sim_B</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_dft_decayed</span><span class="p">(</span><span class="n">tol</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">))</span>
<span class="n">ez_B</span> <span class="o">=</span> <span class="n">sim_B</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft_B</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">pattern_B</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">NANG</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">th</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">):</span>
    <span class="n">ff</span> <span class="o">=</span> <span class="n">sim_B</span><span class="p">.</span><span class="n">get_farfield</span><span class="p">(</span><span class="n">n2f</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_FF</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">th</span><span class="p">),</span> <span class="n">R_FF</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">th</span><span class="p">)))</span>
    <span class="n">E</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">ff</span><span class="p">[:</span><span class="mi">3</span><span class="p">]);</span> <span class="n">Hf</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">ff</span><span class="p">[</span><span class="mi">3</span><span class="p">:])</span>
    <span class="n">S</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">cross</span><span class="p">(</span><span class="n">E</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">Hf</span><span class="p">)))</span>
    <span class="n">pattern_B</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">hypot</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">sim_B</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
<span class="n">pattern_B</span> <span class="o">/=</span> <span class="n">pattern_B</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span>
<span class="n">err_B</span> <span class="o">=</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">pattern_B</span><span class="p">,</span> <span class="n">array_factor</span><span class="p">)</span>
<span class="n">peak_B</span><span class="p">,</span> <span class="n">peak_an</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">pattern_B</span><span class="p">)),</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">array_factor</span><span class="p">))</span>
<span class="n">node</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez_B</span><span class="p">[:,</span> <span class="n">ez_B</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">//</span> <span class="mi">2</span><span class="p">]))</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez_B</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"B: 2D near2far pattern vs sin^2(k h cos theta): rel L2 </span><span class="si">{</span><span class="n">err_B</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, peak bin Meep </span><span class="si">{</span><span class="n">peak_B</span><span class="si">}</span><span class="s"> vs analytic </span><span class="si">{</span><span class="n">peak_an</span><span class="si">}</span><span class="s"> "</span>
      <span class="sa">f</span><span class="s">"(</span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">[</span><span class="n">peak_B</span><span class="p">])</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg), |Ez| on the y = 0 line / max = </span><span class="si">{</span><span class="n">node</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">e</span><span class="si">}</span><span class="s">; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_b</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="n">ext_B</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DBULK</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DBULK</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DBULK</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DBULK</span><span class="p">]</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">10.5</span><span class="p">,</span> <span class="mf">4.6</span><span class="p">))</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez_B</span><span class="p">)))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ez_B</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">ext_B</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"Re(Ez) at the center frequency"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez_B</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">ext_B</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"|Ez|: the y = 0 line is a node (the mirror)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">:</span>
    <span class="n">a</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.0</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="n">H</span><span class="p">,</span> <span class="o">-</span><span class="n">H</span><span class="p">],</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Rectangle</span><span class="p">((</span><span class="o">-</span><span class="n">BOX</span><span class="p">,</span> <span class="o">-</span><span class="n">BOX</span><span class="p">),</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">BOX</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"cyan"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">));</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"part B: steady-state field of dipole + image. Only the upper half (y &gt; 0) is physical."</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_pec_field.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># GIF: monitor-free run with a short pulse, both dipoles visible, node line marked
</span><span class="n">sim_gB</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">FCEN_B</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">H</span><span class="p">)),</span>
                                <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">FCEN_B</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">H</span><span class="p">),</span> <span class="n">amplitude</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">)],</span>
                       <span class="n">symmetries</span><span class="o">=</span><span class="n">symB</span><span class="p">,</span> <span class="o">**</span><span class="nb">dict</span><span class="p">(</span><span class="n">common_B</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="mi">50</span><span class="p">))</span>
<span class="n">sim_gB</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">vol_gB</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">DBULK</span><span class="p">,</span> <span class="n">DBULK</span><span class="p">))</span>
<span class="n">t0B</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">FCEN_B</span><span class="p">)</span>
<span class="n">frames_B</span><span class="p">,</span> <span class="n">times_B</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_gB</span><span class="p">,</span> <span class="n">vol_gB</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t0B</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">FCEN_B</span><span class="p">),</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t0B</span> <span class="o">+</span> <span class="mf">1.1</span> <span class="o">*</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DBULK</span> <span class="o">*</span> <span class="n">N_B</span> <span class="o">*</span> <span class="mf">1.5</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">animate_fields</span><span class="p">(</span><span class="n">frames_B</span><span class="p">,</span> <span class="n">times_B</span><span class="p">,</span> <span class="n">ext_B</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"06_anim_pec.gif"</span><span class="p">),</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.6</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span>
               <span class="n">lines</span><span class="o">=</span><span class="p">[((</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DBULK</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DBULK</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="s">"k"</span><span class="p">,</span> <span class="s">"mirror plane y = 0 (Ez node)"</span><span class="p">),</span> <span class="p">((</span><span class="o">-</span><span class="n">BOX</span><span class="p">,</span> <span class="n">BOX</span><span class="p">),</span> <span class="p">(</span><span class="n">BOX</span><span class="p">,</span> <span class="n">BOX</span><span class="p">),</span> <span class="s">"blue"</span><span class="p">,</span> <span class="s">"near2far box (top)"</span><span class="p">)],</span>
               <span class="n">points</span><span class="o">=</span><span class="p">[(</span><span class="mi">0</span><span class="p">,</span> <span class="n">H</span><span class="p">,</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"dipole"</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">H</span><span class="p">,</span> <span class="s">"orange"</span><span class="p">,</span> <span class="s">"image dipole (-1)"</span><span class="p">)],</span> <span class="n">title</span><span class="o">=</span><span class="s">"dipole + image"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>
<span class="n">sim_gB</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="c1"># =================================================================== C. the mirror problem with the 1D Bloch method (3D Ex dipole above PEC)
# A k_point makes EVERY cell boundary Bloch-periodic, so the mirror cannot be the cell wall: it is a block of mp.metal
# (perfect electric conductor) at the bottom of the 1D cell. PML only at the top; background n = 1.2.
</span><span class="n">DMETAL</span> <span class="o">=</span> <span class="mf">0.5</span>
<span class="n">SZ_C</span> <span class="o">=</span> <span class="n">DMETAL</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="n">DAIR_A</span> <span class="o">+</span> <span class="n">DPML_A</span>
<span class="n">Z_BOT</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SZ_C</span>
<span class="n">Z_PEC</span> <span class="o">=</span> <span class="n">Z_BOT</span> <span class="o">+</span> <span class="n">DMETAL</span>                               <span class="c1"># mirror surface
</span><span class="n">Z_SRC_C</span> <span class="o">=</span> <span class="n">Z_PEC</span> <span class="o">+</span> <span class="n">H</span>
<span class="n">Z_MON_C</span> <span class="o">=</span> <span class="n">Z_PEC</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="n">DAIR_A</span>
<span class="n">mirror</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">Z_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DMETAL</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DMETAL</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">metal</span><span class="p">)]</span>
<span class="n">POLAR_C</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">90.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">))</span>      <span class="c1"># includes grazing angles on purpose
</span><span class="n">T_C</span> <span class="o">=</span> <span class="mf">150.0</span>                                          <span class="c1"># fixed duration: at 85 deg the wave needs ~140 time units to cross 10 um of n = 1.2
</span><span class="n">flux_C</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">phi_deg</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">90.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">):</span>
    <span class="n">vals</span> <span class="o">=</span> <span class="p">[</span><span class="n">flux_1d</span><span class="p">(</span><span class="n">th</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">phi_deg</span><span class="p">),</span> <span class="n">fcen</span><span class="o">=</span><span class="n">FCEN_B</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.1</span> <span class="o">*</span> <span class="n">FCEN_B</span><span class="p">,</span> <span class="n">n_index</span><span class="o">=</span><span class="n">N_B</span><span class="p">,</span> <span class="n">sz</span><span class="o">=</span><span class="n">SZ_C</span><span class="p">,</span> <span class="n">z_src</span><span class="o">=</span><span class="n">Z_SRC_C</span><span class="p">,</span> <span class="n">z_mon</span><span class="o">=</span><span class="n">Z_MON_C</span><span class="p">,</span>
                    <span class="n">pml</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML_A</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">mirror</span><span class="p">,</span> <span class="n">until</span><span class="o">=</span><span class="n">T_C</span><span class="p">)</span> <span class="k">for</span> <span class="n">th</span> <span class="ow">in</span> <span class="n">POLAR_C</span><span class="p">]</span>
    <span class="n">flux_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">vals</span><span class="p">)</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">)</span>
<span class="n">af_C</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">K_B</span> <span class="o">*</span> <span class="n">H</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">))</span> <span class="o">**</span> <span class="mi">2</span>
<span class="n">an_C</span> <span class="o">=</span> <span class="p">{</span><span class="mf">90.0</span><span class="p">:</span> <span class="n">af_C</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">:</span> <span class="n">af_C</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">}</span>             <span class="c1"># phi=0: times the dipole's own cos^2
</span><span class="n">ok_C</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">GLANCING</span>
<span class="n">res_C</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">phi_deg</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">90.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">):</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">flux_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">]</span> <span class="o">/</span> <span class="n">flux_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">][</span><span class="n">ok_C</span><span class="p">].</span><span class="nb">max</span><span class="p">();</span> <span class="n">a</span> <span class="o">=</span> <span class="n">an_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">]</span> <span class="o">/</span> <span class="n">an_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">][</span><span class="n">ok_C</span><span class="p">].</span><span class="nb">max</span><span class="p">()</span>
    <span class="n">res_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"pattern"</span><span class="p">:</span> <span class="n">p</span><span class="p">,</span> <span class="s">"analytic"</span><span class="p">:</span> <span class="n">a</span><span class="p">,</span> <span class="s">"err_in"</span><span class="p">:</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="n">ok_C</span><span class="p">],</span> <span class="n">a</span><span class="p">[</span><span class="n">ok_C</span><span class="p">]),</span> <span class="s">"err_all"</span><span class="p">:</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">a</span><span class="p">),</span>
                      <span class="s">"corr_all"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">corrcoef</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">a</span><span class="p">)[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])}</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"C [phi = </span><span class="si">{</span><span class="n">phi_deg</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> deg]: 1D Bloch, </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">)</span><span class="si">}</span><span class="s"> angles: rel L2 </span><span class="si">{</span><span class="n">res_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">][</span><span class="s">'err_in'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> below the glancing limit, "</span>
          <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">res_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">][</span><span class="s">'err_all'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> with grazing angles included (correlation </span><span class="si">{</span><span class="n">res_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">][</span><span class="s">'corr_all'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">)"</span><span class="p">)</span>
<span class="n">pB_on_C</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">,</span> <span class="n">THETA_B</span><span class="p">,</span> <span class="n">pattern_B</span><span class="p">)</span>
<span class="n">err_BC</span> <span class="o">=</span> <span class="n">rel_l2</span><span class="p">(</span><span class="n">res_C</span><span class="p">[</span><span class="mf">90.0</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">][</span><span class="n">ok_C</span><span class="p">],</span> <span class="n">pB_on_C</span><span class="p">[</span><span class="n">ok_C</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"B vs C: 2D near2far (Ez) vs 1D Bloch (Ex, phi = 90 deg) on the same angles: rel L2 </span><span class="si">{</span><span class="n">err_BC</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">4.6</span><span class="p">))</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">"polar"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">,</span> <span class="n">pattern_B</span><span class="p">,</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.6</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"B: 2D near2far (Ez dipole)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">,</span> <span class="n">array_factor</span><span class="p">,</span> <span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"analytic sin^2(k h cos t)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">[</span><span class="n">ok_C</span><span class="p">],</span> <span class="n">res_C</span><span class="p">[</span><span class="mf">90.0</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">][</span><span class="n">ok_C</span><span class="p">],</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"C: 1D Bloch (Ex, phi = 90)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">[</span><span class="o">~</span><span class="n">ok_C</span><span class="p">],</span> <span class="n">res_C</span><span class="p">[</span><span class="mf">90.0</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">][</span><span class="o">~</span><span class="n">ok_C</span><span class="p">],</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"C: grazing angles"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_theta_zero_location</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_direction</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamin</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamax</span><span class="p">(</span><span class="mi">90</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_rlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.3</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"dipole </span><span class="si">{</span><span class="n">H</span><span class="si">}</span><span class="s"> um above a PEC, k h = </span><span class="si">{</span><span class="n">K_B</span> <span class="o">*</span> <span class="n">H</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mf">6.5</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">"polar"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">[</span><span class="n">ok_C</span><span class="p">],</span> <span class="n">res_C</span><span class="p">[</span><span class="mf">0.0</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">][</span><span class="n">ok_C</span><span class="p">],</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"C: 1D Bloch, phi = 0"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">[</span><span class="o">~</span><span class="n">ok_C</span><span class="p">],</span> <span class="n">res_C</span><span class="p">[</span><span class="mf">0.0</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">][</span><span class="o">~</span><span class="n">ok_C</span><span class="p">],</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"grazing"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">,</span> <span class="n">res_C</span><span class="p">[</span><span class="mf">0.0</span><span class="p">][</span><span class="s">"analytic"</span><span class="p">],</span> <span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"analytic cos^2(t) sin^2(k h cos t)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_theta_zero_location</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_theta_direction</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamin</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_thetamax</span><span class="p">(</span><span class="mi">90</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_rlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.3</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"phi = 0: array factor times the dipole's cos^2"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mf">6.5</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="k">for</span> <span class="n">phi_deg</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">((</span><span class="mf">90.0</span><span class="p">,</span> <span class="s">"tab:green"</span><span class="p">),</span> <span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="s">"tab:olive"</span><span class="p">)):</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">res_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">][</span><span class="s">"pattern"</span><span class="p">]</span> <span class="o">-</span> <span class="n">res_C</span><span class="p">[</span><span class="n">phi_deg</span><span class="p">][</span><span class="s">"analytic"</span><span class="p">]),</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">c</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"1D Bloch, phi = </span><span class="si">{</span><span class="n">phi_deg</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">pattern_B</span> <span class="o">-</span> <span class="n">array_factor</span><span class="p">),</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.4</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"2D near2far"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">axvspan</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">GLANCING</span><span class="p">)),</span> <span class="mi">90</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lightgray"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">GLANCING</span><span class="p">))</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.02</span><span class="p">,</span> <span class="s">"glancing:</span><span class="se">\n</span><span class="s">PML fails"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"theta from the mirror normal [deg]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"|pattern - analytic| (normalized)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_yscale</span><span class="p">(</span><span class="s">"log"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mf">1e-4</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"where each method fails"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="sa">f</span><span class="s">"B: rel L2 </span><span class="si">{</span><span class="n">err_B</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (near2far) | C: </span><span class="si">{</span><span class="n">res_C</span><span class="p">[</span><span class="mf">90.0</span><span class="p">][</span><span class="s">'err_in'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> below 72 deg, </span><span class="si">{</span><span class="n">res_C</span><span class="p">[</span><span class="mf">90.0</span><span class="p">][</span><span class="s">'err_all'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> with grazing angles"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">(</span><span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.92</span><span class="p">]);</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_pec_pattern.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="k">if</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">():</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"A"</span><span class="p">:</span> <span class="p">{</span><span class="s">"wl"</span><span class="p">:</span> <span class="n">WL_A</span><span class="p">,</span> <span class="s">"res"</span><span class="p">:</span> <span class="n">RES_A</span><span class="p">,</span> <span class="s">"n_polar"</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">POLAR</span><span class="p">),</span> <span class="s">"n_azimuth"</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">AZIM</span><span class="p">),</span> <span class="s">"n_runs"</span><span class="p">:</span> <span class="n">n_runs</span><span class="p">,</span> <span class="s">"n_skipped"</span><span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="o">~</span><span class="n">computed</span><span class="p">)),</span>
                         <span class="s">"glancing_limit_deg"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">GLANCING</span><span class="p">))),</span> <span class="s">"err_mul"</span><span class="p">:</span> <span class="n">err_mul</span><span class="p">,</span> <span class="s">"err_div"</span><span class="p">:</span> <span class="n">err_div</span><span class="p">,</span> <span class="s">"err_raw"</span><span class="p">:</span> <span class="n">err_raw</span><span class="p">,</span> <span class="s">"err_phi0"</span><span class="p">:</span> <span class="n">err_phi0</span><span class="p">},</span>
                   <span class="s">"B"</span><span class="p">:</span> <span class="p">{</span><span class="s">"wl"</span><span class="p">:</span> <span class="n">WL_B</span><span class="p">,</span> <span class="s">"n"</span><span class="p">:</span> <span class="n">N_B</span><span class="p">,</span> <span class="s">"h"</span><span class="p">:</span> <span class="n">H</span><span class="p">,</span> <span class="s">"res"</span><span class="p">:</span> <span class="n">RES_B</span><span class="p">,</span> <span class="s">"kh"</span><span class="p">:</span> <span class="n">K_B</span> <span class="o">*</span> <span class="n">H</span><span class="p">,</span> <span class="s">"box"</span><span class="p">:</span> <span class="n">BOX</span><span class="p">,</span> <span class="s">"err"</span><span class="p">:</span> <span class="n">err_B</span><span class="p">,</span> <span class="s">"peak_bin"</span><span class="p">:</span> <span class="p">[</span><span class="n">peak_B</span><span class="p">,</span> <span class="n">peak_an</span><span class="p">],</span>
                         <span class="s">"peak_deg"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">[</span><span class="n">peak_B</span><span class="p">])),</span> <span class="s">"node_ratio"</span><span class="p">:</span> <span class="n">node</span><span class="p">,</span>
                         <span class="s">"pattern"</span><span class="p">:</span> <span class="n">pattern_B</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"analytic"</span><span class="p">:</span> <span class="n">array_factor</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"theta_deg"</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">THETA_B</span><span class="p">).</span><span class="n">tolist</span><span class="p">()},</span>
                   <span class="s">"C"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">k_</span><span class="p">)):</span> <span class="p">{</span><span class="s">"err_in"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"err_in"</span><span class="p">],</span> <span class="s">"err_all"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"err_all"</span><span class="p">],</span> <span class="s">"corr_all"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"corr_all"</span><span class="p">],</span> <span class="s">"pattern"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"pattern"</span><span class="p">].</span><span class="n">tolist</span><span class="p">()}</span> <span class="k">for</span> <span class="n">k_</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">res_C</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"B_vs_C"</span><span class="p">:</span> <span class="n">err_BC</span><span class="p">,</span> <span class="s">"theta_C_deg"</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">POLAR_C</span><span class="p">).</span><span class="n">tolist</span><span class="p">(),</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">},</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"total </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span></code></pre></figure>

</details>

<details>
  <summary>원본 실행 기록과 재현 환경</summary>

  <p>§4의 발췌 코드와 달리 전체 코드에는 1D 셀 설계도 그리기, 반구 지도, GIF 두 개, result.json 기록이 들어 있다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

  <p><strong>실행 결과 (2026-10-23 실행)</strong>:</p>
  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A: 240 1D runs (13x24 grid, 72 glancing samples skipped) in 201 s; rel L2 vs analytic (computed samples): flux_z*cos = 0.0022, flux_z/cos = 0.7585, flux_z raw = 0.5290; phi=0 cut 0.0012
B: 2D near2far pattern vs sin^2(k h cos theta): rel L2 0.0066, peak bin Meep 7 vs analytic 7 (12.9 deg), |Ez| on the y = 0 line / max = 1.2e-02; 3 s
C [phi = 90 deg]: 1D Bloch, 18 angles: rel L2 0.0675 below the glancing limit, 0.1052 with grazing angles included (correlation 0.9809)
C [phi = 0 deg]: 1D Bloch, 18 angles: rel L2 0.0599 below the glancing limit, 0.0601 with grazing angles included (correlation 0.9965)
B vs C: 2D near2far (Ez) vs 1D Bloch (Ex, phi = 90 deg) on the same angles: rel L2 0.0637
total 258 s
</code></pre></div>  </div>

  <p><strong>재현 환경</strong>: meep 1.33.0 · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep</code> · 실행 <code class="language-plaintext highlighter-rouge">python dipole_pattern_3d.py</code> (약 4.3 min, 단일 코어)</p>

</details>

<h3 id="공식-문서와-다음-글">공식 문서와 다음 글</h3>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/">Near-to-far field spectra 튜토리얼</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/#radiation-pattern-of-an-antenna-above-a-perfect-electric-conductor-ground-plane">antenna above a PEC ground plane</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/dipole_in_vacuum_1D.py">dipole_in_vacuum_1D.py</a></li>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#simulation"><code class="language-plaintext highlighter-rouge">k_point</code>와 Bloch 경계</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#symmetry"><code class="language-plaintext highlighter-rouge">Symmetry</code>와 <code class="language-plaintext highlighter-rouge">phase</code></a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#near2farregion"><code class="language-plaintext highlighter-rouge">Near2FarRegion</code></a></li>
  <li>이전 글: <a href="/meep-examples/bend-inverse/">09 · Waveguide bend inverse design</a> · 시즌 2의 출발점: <a href="/meep-examples/point-line-source/">01 · Point source와 line source</a> · 다음 글: <a href="/meep-examples/cavity-ldos/">11 · 두 거울 사이의 점광원</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="dipole" /><category term="radiation-pattern" /><category term="bloch" /><category term="near2far" /><category term="pec" /><category term="image-dipole" /><summary type="html"><![CDATA[post 01 left the point source radiating equally in all directions, in 2D. This post asks the 3D question twice. First, the 3D pattern of an x-polarized dipole in vacuum without a 3D cell: one 1D simulation per direction, with the direction encoded in a transverse Bloch wavevector. Second, the same dipole above a perfect-electric-conductor mirror, solved in 2D with an opposite-sign image dipole and a closed near2far box, and again with the 1D method.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/10/05_pec_pattern.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/10/05_pec_pattern.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 14 · 박막 속 점광원, 공기로 나오는 몫 — 광추출 효율, LDOS 정규화, kz 적분, CYL 대 3D</title><link href="https://jin-castle.github.io/meep-examples/extraction-efficiency/" rel="alternate" type="text/html" title="Meep Example 14 · 박막 속 점광원, 공기로 나오는 몫 — 광추출 효율, LDOS 정규화, kz 적분, CYL 대 3D" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/extraction-efficiency</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/extraction-efficiency/"><![CDATA[<h2 id="tldr-english">TL;DR (English)</h2>

<p><img src="/meep-examples/assets/meep/14/04_m_series.png" alt="hero" /></p>

<ul>
  <li><strong>What</strong>: post 11 measured how much a dipole emits (LDOS); post 13 split a body of revolution into m runs. An LED asks for the ratio: of everything a dipole in the emitting layer puts out, how much reaches the air. Extraction efficiency = flux through an open surface in air ÷ the source’s own work from <code class="language-plaintext highlighter-rouge">dft_ldos</code>. Three official examples: a dipole in a layer on a mirror (cylindrical vs 3D), the same slab with the dipole off the axis (an m series), and a dipole inside the cleaved facet of a laser stack (a 2D cross-section plus a kz integral).</li>
  <li><strong>Result</strong>: A dipole halfway up the layer sends 0.323 of its power into air (cylindrical, resolution 80); the efficiency swings from 0.52 near the mirror to 0.09 near the top, and at resolution 40 cylindrical and 3D disagree by up to 16 %: a 0.29 µm layer needs resolution 80. 3.5 µm off the axis, the official stop rule (first m below 1 %) halts at m = 32 and reports 0.632; the series rebounds at m ≈ 41, where the slab-guided emission lives, and the sum to m = 60 gives 0.362, matching the on-axis 0.364. The cleaved laser facet needs 76 kz runs and extracts 22.4 %; a single 2D run (kz = 0) would claim 32.9 %.</li>
  <li><strong>Takeaway</strong>: the denominator is not a vacuum constant but the dipole’s own work, and its voxel volume differs between coordinate systems (2πr/res² vs 1/res³ vs 1/res²). Most of the light stays guided in a high-index film. Where you cut a series (m or kz) changes the answer, and the official “first term below 1 %” rule can stop before the guided light arrives.</li>
  <li><strong>Code</strong>: full script at the bottom, ~77 min (mpirun -np 4; B alone 58 min).</li>
</ul>

<h2 id="0-이-글에서-배우는-것">0. 이 글에서 배우는 것</h2>

<ul>
  <li>광추출 효율의 정의: 분자는 공기 쪽 열린 flux 면, 분모는 <code class="language-plaintext highlighter-rouge">dft_ldos</code>의 source 일 $-\mathrm{Re}(FJ^*)\,\Delta V$</li>
  <li>좌표계마다 다른 $\Delta V$: cylindrical $2\pi r/\mathrm{res}^2$, 3D $1/\mathrm{res}^3$, 2D $1/\mathrm{res}^2$</li>
  <li>같은 문제를 cylindrical과 3D로 풀어 맞추는 교차검증. 어디서 어긋나는가</li>
  <li>축에서 떨어진 쌍극자의 m 급수에서 “언제 멈출까”가 결과를 바꾸는 경우</li>
  <li>한 방향으로 균일한 구조(절단면 레이저)의 3D 문제 = 2D 단면 + kz 적분</li>
</ul>

<p><strong>전제 지식</strong>: 11편의 <code class="language-plaintext highlighter-rouge">dft_ldos</code>, 13편의 cylindrical 좌표와 m 급수. <strong>공식 예제</strong>: <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Local_Density_of_States/#extraction-efficiency-of-a-light-emitting-diode-led">LDOS 튜토리얼의 LED 추출 효율</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Cylindrical_Coordinates/#nonaxisymmetric-dipole-sources">nonaxisymmetric dipole sources</a> · 스크립트 <a href="https://github.com/NanoComp/meep/blob/master/python/examples/extraction_eff_ldos.py">extraction_eff_ldos.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/point_dipole_cyl.py">point_dipole_cyl.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/edge_emitter_2D.py">edge_emitter_2D.py</a>. <strong>이전 글</strong>: <a href="/meep-examples/cylindrical-dipole/">13 · 회전 대칭으로 3D를 계산하기</a> · <strong>다음 글</strong>: 15 · 점광원이 수천 개일 때</p>

<h2 id="1-무엇을-알고-싶은가">1. 무엇을 알고 싶은가</h2>

<p>13편 끝 질문이었다. 디스크 안의 쌍극자를 LED의 발광층으로 보면, 쌍극자가 낸 빛 중 몇 %가 공기로 나오는가. 굴절률 2.4인 층에서 공기로 나가려면 임계각 25° 안쪽으로 계면에 닿아야 하고, 나머지는 전반사로 층 안을 따라간다. 이 몫을 재려면 두 숫자가 필요하다. 공기로 나간 power와 쌍극자가 낸 전체 power. 앞의 것은 flux monitor로 잰다. 뒤의 것은 11편처럼 거울과 층이 방출량 자체를 바꾸므로 진공의 상수로 둘 수 없고, 그 구조 속에서 source가 한 일로 재야 한다. 그리고 3D 문제를 싸게 푸는 세 길(cylindrical, 대칭을 쓴 3D, 2D + kz)이 같은 답을 주는지 본다.</p>

<h3 id="어디에-쓰이는가">어디에 쓰이는가</h3>

<p>광추출 효율은 발광 소자의 외부 양자 효율(EQE) = 내부 양자 효율 × 추출 효율에서 뒤쪽 인자다. 소자 설계의 대부분이 이 숫자를 올리는 일이다.</p>

<table>
  <thead>
    <tr>
      <th>응용</th>
      <th>이 글의 어떤 것을 쓰는가</th>
      <th>그 다음에 필요한 것</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>OLED·LED·micro-LED 발광층 설계</td>
      <td>높이(전극과의 거리)에 따른 추출 효율, LDOS 분모</td>
      <td>15편 수천 개의 발광체</td>
    </tr>
    <tr>
      <td>반도체 레이저·SOA의 절단면</td>
      <td>2D 단면 + kz 적분, 편광별 추출</td>
      <td>18편 계면의 각도 응답</td>
    </tr>
    <tr>
      <td>양자점·단일광자원 수집 효율</td>
      <td>축 위/축 밖 쌍극자의 차이, m 급수</td>
      <td>16편 far field로 모으기</td>
    </tr>
    <tr>
      <td>광추출 구조(텍스처, 렌즈, 광결정) 최적화</td>
      <td>분자·분모 정의와 교차검증 절차</td>
      <td>35편 near2far 역설계</td>
    </tr>
  </tbody>
</table>

<h2 id="2-물리-한-페이지">2. 물리 한 페이지</h2>

<p>추출 효율은 두 power의 비다. 분자는 공기 쪽에 둔 열린 flux 면으로 잰다. 분모는 source 점에서 field가 전류에 한 일이고, <code class="language-plaintext highlighter-rouge">dft_ldos</code>가 저장한 $F$(field)와 $J$(전류)로 계산한다. source 하나가 차지하는 부피 $\Delta V$가 좌표계마다 다르다.</p>

\[\eta=\frac{P_{\mathrm{air}}}{P_{\mathrm{total}}},\qquad
P_{\mathrm{total}}=-\mathrm{Re}\{F\,J^*\}\,\Delta V,\qquad
\Delta V=\begin{cases}2\pi r/\mathrm{res}^2 &amp; \text{cylindrical}\\ 1/\mathrm{res}^3 &amp; \text{3D}\\ 1/\mathrm{res}^2 &amp; \text{2D (line current)}\end{cases}\]

<p>축에서 떨어진 쌍극자(cylindrical)와 한 방향으로 균일한 구조의 점광원(2D)은 둘 다 급수로 푼다. 앞은 m에 대해, 뒤는 kz에 대해. 서로 다른 m(또는 kz)은 직교하므로 power는 항별로 더한다. ±m과 ±kz는 같은 power를 주므로 0이 아닌 항은 두 배로 센다.</p>

\[\eta_{\mathrm{off\text{-}axis}}=\frac{\sum_m w_m P^{(m)}_{\mathrm{air}}}{\sum_m w_m P^{(m)}_{\mathrm{total}}},\qquad
\eta_{\mathrm{edge}}=\frac{P_{\mathrm{air}}(0)+2\sum_{k_z&gt;0}P_{\mathrm{air}}(k_z)}{P_{\mathrm{tot}}(0)+2\sum_{k_z&gt;0}P_{\mathrm{tot}}(k_z)},\qquad w_0=1,\ w_{m&gt;0}=2\]

<p>고굴절률 층에 갇힌 빛(guided mode)은 층을 따라 반지름 방향으로 간다. 축에서 r만큼 떨어진 쌍극자가 낸 guided 빛은 방위 차수 $m\approx 2\pi n_{\mathrm{eff}} r/\lambda$ 근처의 항에 실린다. 이 빛이 셀 끝의 옆면 monitor를 지나가면 분자에 들어가므로, 그 m까지 가기 전에 급수를 끊으면 다른 숫자가 나온다.</p>

<table>
  <thead>
    <tr>
      <th>기호</th>
      <th>뜻</th>
      <th>코드 변수</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$\eta$</td>
      <td>추출 효율</td>
      <td><code class="language-plaintext highlighter-rouge">p_air / p_tot</code></td>
    </tr>
    <tr>
      <td>$h$</td>
      <td>거울에서 쌍극자까지 높이 / 층 두께</td>
      <td><code class="language-plaintext highlighter-rouge">HEIGHTS</code></td>
    </tr>
    <tr>
      <td>$F, J$</td>
      <td><code class="language-plaintext highlighter-rouge">dft_ldos</code>가 저장한 source 점의 field와 전류</td>
      <td><code class="language-plaintext highlighter-rouge">sim.ldos_Fdata</code>, <code class="language-plaintext highlighter-rouge">sim.ldos_Jdata</code></td>
    </tr>
    <tr>
      <td>$\Delta V$</td>
      <td>source 한 개의 부피</td>
      <td><code class="language-plaintext highlighter-rouge">2*pi*r/res**2</code>, <code class="language-plaintext highlighter-rouge">1/res**3</code>, <code class="language-plaintext highlighter-rouge">1/res**2</code></td>
    </tr>
    <tr>
      <td>$m$, $k_z$</td>
      <td>급수의 항</td>
      <td><code class="language-plaintext highlighter-rouge">m=</code>, <code class="language-plaintext highlighter-rouge">k_point=(0,0,kz)</code></td>
    </tr>
  </tbody>
</table>

<p><strong>가정과 유효 범위</strong>: 파장 1 µm, 손실 없는 층과 완전도체 거울(A·B), 손실 없는 다층(C). 분자는 열린 면이라 “공기 쪽으로 나간 몫”이지 닫힌 에너지 수지가 아니다. 셀의 가로 크기 L(A: 6 µm, B: 20 µm)이 유한하므로 그 밖으로 가는 빛은 옆면에서 센다.</p>

<h3 id="결과-보기-전에-맞춰보기">결과 보기 전에 맞춰보기</h3>

<table>
  <thead>
    <tr>
      <th>물리량</th>
      <th>내 예측</th>
      <th>근거</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>추출 효율(A, h = 0.5)</td>
      <td>0.3 근처</td>
      <td>노트 0.323(CYL)·0.337(3D)</td>
    </tr>
    <tr>
      <td>높이 의존</td>
      <td>거울에서 멀수록 변한다</td>
      <td>쌍극자와 image의 간섭(10편)</td>
    </tr>
    <tr>
      <td>CYL res 40 vs 80</td>
      <td>1% 안</td>
      <td>파장당 40칸 이상</td>
    </tr>
    <tr>
      <td>3D vs CYL</td>
      <td>2% 안</td>
      <td>노트 max 0.017</td>
    </tr>
    <tr>
      <td>축 위 쌍극자(B)</td>
      <td>0.3 근처</td>
      <td>같은 층, 다른 셀 크기</td>
    </tr>
    <tr>
      <td>B: 공식 종료 규칙</td>
      <td>sum-to-60과 다르다</td>
      <td>노트: 0.63–0.74 vs 0.36</td>
    </tr>
    <tr>
      <td>C: 필요한 kz 수</td>
      <td>70~80</td>
      <td>노트 76</td>
    </tr>
    <tr>
      <td>C: 추출 효율</td>
      <td>22% 근처</td>
      <td>노트 22.4%</td>
    </tr>
  </tbody>
</table>

<p><strong>판정 기준</strong>: 효율이 0 아래나 1 위면 분모의 $\Delta V$나 flux 면의 부호가 틀렸다. CYL과 3D가 2배 다르면 voxel 부피, 5~10%면 해상도나 source 위치를 의심한다.</p>

<h2 id="3-시뮬레이션-설계도">3. 시뮬레이션 설계도</h2>

<p><img src="/meep-examples/assets/meep/14/01_layout.png" alt="layout" />
<em>파트 A의 cylindrical (r, z) 셀(x가 r, y가 z). 회색 층이 n 2.4(두께 0.292 µm), 그 아래 셀 벽이 PML 없는 완전도체 거울이다. 빨간 점이 축에서 1.5 픽셀 떨어진 Er 쌍극자, 파란 선이 분자를 재는 열린 flux 면(위와 옆). 파란 빗금은 대표 DFT 영역. 동그라미 숫자는 §4의 단계 번호다.</em></p>

<p><img src="/meep-examples/assets/meep/14/02_layout_edge.png" alt="layout edge" />
<em>파트 C의 2D 단면. 왼쪽에서부터 기판(n 3.2), 클래딩(1.5), 활성층(2.3), 클래딩이 쌓인 다층이 x = 1.5 µm에서 잘려 있고(절단면), 그 오른쪽은 공기다. 쌍극자는 절단면 0.5 µm 안쪽의 활성층. z 방향으로 구조가 균일하므로 kz마다 2D run 하나를 돌린다.</em></p>

<table>
  <thead>
    <tr>
      <th>파라미터</th>
      <th>값</th>
      <th>왜 이 값인가</th>
      <th>바꾸면</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>A 층</td>
      <td>n 2.4, 두께 0.7λ/n = 0.292 µm, 거울 위</td>
      <td>공식 값</td>
      <td>두께가 바뀌면 guided mode 수가 바뀐다</td>
    </tr>
    <tr>
      <td>A 높이</td>
      <td>0.1~0.9, 9점</td>
      <td>공식 21점의 축소</td>
      <td>—</td>
    </tr>
    <tr>
      <td>A 해상도</td>
      <td>CYL 40·80, 3D 40</td>
      <td>공식 80. 3D는 비용 때문에 40</td>
      <td>3D res 80은 셀 하나 4500만 칸</td>
    </tr>
    <tr>
      <td>A 수집면</td>
      <td>가로 6 µm, 공기층 1 µm</td>
      <td>공식 값</td>
      <td>좁으면 옆으로 나간 빛을 놓친다</td>
    </tr>
    <tr>
      <td>B 셀</td>
      <td>r 20 µm, 층 같음, res 50</td>
      <td>공식 point_dipole_cyl.py</td>
      <td>—</td>
    </tr>
    <tr>
      <td>B 쌍극자</td>
      <td>r = 3.5 µm, m = 0…60</td>
      <td>공식 r 중 하나, $2\pi n r\approx53$을 넘게</td>
      <td>공식은 첫 1% 아래에서 멈춤</td>
    </tr>
    <tr>
      <td>C 다층</td>
      <td>3.2 / 1.5 / 2.3 / 1.5, res 25</td>
      <td>공식 edge_emitter_2D.py</td>
      <td>—</td>
    </tr>
    <tr>
      <td>C kz</td>
      <td>0.02 간격, 전체 power가 최대의 2% 아래일 때까지</td>
      <td>공식 값</td>
      <td>간격이 넓으면 guided 봉우리를 놓친다</td>
    </tr>
  </tbody>
</table>

<p><img src="/meep-examples/assets/meep/14/00_source.png" alt="source" />
<em>source 파형과 스펙트럼(1000 nm, fwidth 0.1 fcen. B는 0.05). 효율은 중심 주파수 하나에서 잰다.</em></p>

<p><strong>강의 노트북과의 차이</strong>: 강의 범위 밖이다. 10_sources의 세 노트는 각각 공식 조건 전체(21 높이 × 2 좌표계 res 80, r 네 개 × m 수백, kz 76점)를 돌렸다. 이 글은 A의 3D를 세 높이·res 40으로 줄이고, B는 r 하나에서 공식 종료 규칙과 m = 60까지 합한 값을 같은 그림에 놓는다.</p>

<h2 id="4-코드-따라가기">4. 코드 따라가기</h2>

<blockquote>
  <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
이번 글의 핵심은 ⑦의 분모다.</p>
</blockquote>

<h3 id="-단위와-파라미터--어떤-숫자를-고정하는가">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WL</span><span class="p">,</span> <span class="n">FREQ</span><span class="p">,</span> <span class="n">N_L</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.4</span>
<span class="n">T_L</span> <span class="o">=</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_L</span>                      <span class="c1"># layer thickness
</span><span class="n">DPML</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">,</span> <span class="n">L</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">6.0</span>             <span class="c1"># PML, air above the layer, lateral size of the collection surface
</span><span class="n">HEIGHTS</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">,</span> <span class="mi">9</span><span class="p">),</span> <span class="mi">3</span><span class="p">)</span>      <span class="c1"># dipole height above the ground plane, fraction of T_L
</span><span class="n">DKZ</span><span class="p">,</span> <span class="n">KZ_TOL</span> <span class="o">=</span> <span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.02</span>                  <span class="c1"># part C: kz step and stop when the total power falls below 2 % of its max
</span></code></pre></div></div>

<ul>
  <li><strong>무엇</strong>: 층과 수집면, 높이 sweep, kz 간격.</li>
  <li><strong>왜</strong>: 층 두께 0.7λ/n은 guided mode가 하나 남짓 들어가는 두께다. 높이를 바꾸면 쌍극자와 거울 image의 간섭이 바뀌어 방출 방향과 양이 둘 다 변한다.</li>
  <li><strong>틀리면</strong>: 수집면 L이 좁으면 옆으로 비스듬히 나간 빛이 PML로 가 버려 분자가 작아진다.</li>
</ul>

<h3 id="-재료와-구조--층-하나와-거울">② 재료와 구조 — 층 하나와 거울</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_L</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">T_L</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">T_L</span><span class="p">))</span>
<span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)]</span>     <span class="c1"># bottom: no PML = ground plane
</span></code></pre></div></div>

<ul>
  <li><strong>무엇</strong>: 셀 바닥에 붙은 무한 층. 바닥 벽에는 PML이 없다.</li>
  <li><strong>왜</strong>: 11·13편과 같은 규칙으로 PML 없는 벽은 완전도체 거울이다. 위쪽과 옆쪽만 연다.</li>
  <li><strong>틀리면</strong>: 공식 docstring은 “metallic ground plane”이라 하지만 코드에 금속 블록은 없다. 거울은 경계 조건이다. 바닥에도 PML을 두면 거울이 사라지고 효율이 달라진다.</li>
</ul>

<h3 id="-source--같은-쌍극자의-세-표현">③ Source — 같은 쌍극자의 세 표현</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">res</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z_src</span><span class="p">))</span>      <span class="c1"># cylindrical, m = -1 (13편: in-plane dipole)
</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z_src</span><span class="p">))</span>              <span class="c1"># 3D with Mirror(X, -1), Mirror(Y)
</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">SRC_C</span><span class="p">)</span>                                 <span class="c1"># 2D + kz: a line current along z with phase exp(i kz z)
</span></code></pre></div></div>

<ul>
  <li><strong>무엇</strong>: A의 수평 쌍극자를 cylindrical에서는 Er(m = −1), 3D에서는 Ex로. C는 절단면 레이저의 z 방향 쌍극자.</li>
  <li><strong>왜</strong>: 2D 셀의 점원은 z로 무한한 선전류다. 그 선전류에 $e^{ik_zz}$ 위상을 주고 kz에 대해 적분하면 점광원이 된다. 10편의 1D Bloch run과 같은 생각을 한 차원 올린 것이다.</li>
  <li><strong>틀리면</strong>: cylindrical에서 r = 0에 Er을 두면 축의 Yee 격자에 Er이 없어 결과가 틀린다(meep #2704). 1.5 픽셀 비킨다.</li>
</ul>

<h3 id="-simulation과-경계--좌표계와-kz">④ Simulation과 경계 — 좌표계와 kz</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(...,</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=-</span><span class="mi">1</span><span class="p">)</span>                                                   <span class="c1"># A, cylindrical
</span><span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(...,</span> <span class="n">symmetries</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)])</span>                          <span class="c1"># A, 3D: 1/4 of the cell
</span><span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(...,</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">kz</span><span class="p">),</span> <span class="n">kz_2d</span><span class="o">=</span><span class="s">"real/imag"</span><span class="p">)</span>                                   <span class="c1"># C: 2D cell, out-of-plane wavevector
</span></code></pre></div></div>

<ul>
  <li><strong>무엇</strong>: 같은 물리를 세 좌표계로. C는 2D 셀에 <code class="language-plaintext highlighter-rouge">k_point</code>의 z 성분과 <code class="language-plaintext highlighter-rouge">kz_2d</code>.</li>
  <li><strong>왜</strong>: <code class="language-plaintext highlighter-rouge">kz_2d="real/imag"</code>는 kz가 있는 2D 계산을 실수 field 두 벌로 푸는 방법이다. 세 표현(real/imag, complex, 3d)이 같다는 것은 10_sources의 kz_2d 노트(18편 예정)에서 확인했다.</li>
  <li><strong>틀리면</strong>: 3D 대칭 위상을 둘 다 +1로 두면 다른 parity의 source를 계산한다(11편).</li>
</ul>

<h3 id="-monitor--분자는-공기-쪽-열린-면">⑤ Monitor — 분자는 공기 쪽 열린 면</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>                   <span class="c1"># top
</span><span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DAIR</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">))</span>         <span class="c1"># side, air only
</span><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="p">...)</span>                                                  <span class="c1"># denominator data
</span></code></pre></div></div>

<ul>
  <li><strong>무엇</strong>: 위와 옆(공기 높이만)의 flux. 3D는 옆면 네 개, 음의 면은 <code class="language-plaintext highlighter-rouge">weight=-1</code>. 동시에 <code class="language-plaintext highlighter-rouge">dft_ldos</code>를 step function으로 넣어 분모 데이터를 모은다.</li>
  <li><strong>왜</strong>: 옆면을 층 높이까지 내리면 층에 갇혀 옆으로 가는 빛까지 “추출”로 센다. 공기 높이만 잡는다.</li>
  <li><strong>틀리면</strong>: B의 cylindrical 셀(r 20 µm)에서는 층에 갇힌 빛이 PML 직전의 옆면을 지나간다. 공식 B 코드는 옆면을 공기층 높이에 두지만, 층의 감쇠 꼬리가 거기에 닿는다. 이것이 §5의 되튐과 관련이 있다.</li>
</ul>

<h3 id="-실행--급수와-종료">⑥ 실행 — 급수와 종료</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">M_MAX</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>                                    <span class="c1"># B: every m up to 60, then decide where to cut afterwards
</span>    <span class="n">rad</span><span class="p">,</span> <span class="n">src</span> <span class="o">=</span> <span class="n">dipole_in_slab</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span>
<span class="n">m_stop</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">m</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">M_MAX</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="n">rel</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mf">1e-2</span><span class="p">)</span>    <span class="c1"># the official rule, applied to the same data
</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>                                                    <span class="c1"># C: kz = 0, 0.02, 0.04, ...
</span>    <span class="p">...</span>
    <span class="k">if</span> <span class="n">dflux</span> <span class="o">&gt;</span> <span class="n">dmax</span><span class="p">:</span> <span class="n">dmax</span> <span class="o">=</span> <span class="n">dflux</span>
    <span class="k">elif</span> <span class="n">dflux</span> <span class="o">/</span> <span class="n">dmax</span> <span class="o">&lt;</span> <span class="n">KZ_TOL</span><span class="p">:</span> <span class="k">break</span>
</code></pre></div></div>

<ul>
  <li><strong>무엇</strong>: B는 공식처럼 도중에 멈추지 않고 m = 60까지 다 돌린 뒤, 같은 데이터에 공식 규칙을 적용해 비교한다. C는 공식 규칙 그대로.</li>
  <li><strong>왜</strong>: 종료 규칙이 맞는지 보려면 규칙 뒤의 항을 실제로 봐야 한다.</li>
  <li><strong>틀리면</strong>: B에서 공식 규칙만 쓰면 m_stop 이후를 볼 수 없어 되튐을 모른다.</li>
</ul>

<h3 id="-후처리--분모와-급수">⑦ 후처리 — 분모와 급수</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p_tot</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_Fdata</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_Jdata</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span> <span class="o">*</span> <span class="n">dV</span>     <span class="c1"># dV: 2*pi*r/res**2 (cyl), 1/res**3 (3D), 1/res**2 (2D)
</span><span class="n">eff</span> <span class="o">=</span> <span class="n">p_air</span> <span class="o">/</span> <span class="n">p_tot</span>
<span class="n">eff_series</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">w</span> <span class="o">*</span> <span class="n">rads</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">w</span> <span class="o">*</span> <span class="n">srcs</span><span class="p">)</span>                    <span class="c1"># w = 1 for m = 0, 2 for m &gt; 0
</span><span class="n">eff_edge</span> <span class="o">=</span> <span class="p">(</span><span class="n">a_kz</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">a_kz</span><span class="p">[</span><span class="mi">1</span><span class="p">:].</span><span class="nb">sum</span><span class="p">())</span> <span class="o">/</span> <span class="p">(</span><span class="n">d_kz</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">d_kz</span><span class="p">[</span><span class="mi">1</span><span class="p">:].</span><span class="nb">sum</span><span class="p">())</span>
</code></pre></div></div>

<ul>
  <li><strong>무엇</strong>: 분모는 source 한 개의 일. 급수는 분자와 분모를 각각 더한 뒤 나눈다.</li>
  <li><strong>왜</strong>: 항마다 효율을 내서 평균하면 안 된다. power가 큰 항이 효율을 정해야 한다.</li>
  <li><strong>틀리면</strong>: $\Delta V$를 빼먹으면 cylindrical과 3D가 수백 배 다르다. cylindrical의 $2\pi r$은 source가 축을 도는 고리라는 뜻이다.</li>
</ul>

<blockquote>
  <p><strong>함정</strong>: 11편의 Purcell 인자는 같은 좌표계 두 run의 비율이라 $\Delta V$가 상쇄됐다. 추출 효율은 flux(물리 단위)와 source 일의 비율이라 $\Delta V$가 상쇄되지 않는다. 좌표계를 바꾸면 이 인자를 같이 바꿔야 한다.</p>
</blockquote>

<h2 id="5-결과">5. 결과</h2>

<p><img src="/meep-examples/assets/meep/14/03_height.png" alt="height" />
<em>파트 A. 왼쪽: 쌍극자 높이에 따른 추출 효율. cylindrical res 80(파랑), res 40(하늘색), 3D res 40(빨간 마름모). 오른쪽: h = 0.5의 log|Er|. 흰 사각형이 층이고, 층을 따라 멀리까지 가는 빛이 갇힌 몫이다.</em></p>

<table>
  <thead>
    <tr>
      <th>h</th>
      <th>CYL res 80</th>
      <th>CYL res 40</th>
      <th>3D res 40</th>
      <th>노트: 3D res 80</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0.1</td>
      <td>0.5230</td>
      <td>0.5494</td>
      <td>0.5475</td>
      <td>—</td>
    </tr>
    <tr>
      <td>0.2</td>
      <td>0.5038</td>
      <td>0.5214</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>0.3</td>
      <td>0.4645</td>
      <td>0.4735</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>0.4</td>
      <td>0.4050</td>
      <td>0.4014</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>0.5</td>
      <td>0.3232</td>
      <td>0.3018</td>
      <td>0.3505</td>
      <td>0.3369</td>
    </tr>
    <tr>
      <td>0.6</td>
      <td>0.2213</td>
      <td>0.1805</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>0.7</td>
      <td>0.1259</td>
      <td>0.0891</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>0.8</td>
      <td>0.0915</td>
      <td>0.1095</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>0.9</td>
      <td>0.1745</td>
      <td>0.2681</td>
      <td>0.2607</td>
      <td>—</td>
    </tr>
  </tbody>
</table>

<p><img src="/meep-examples/assets/meep/14/04_m_series.png" alt="m series" />
<em>파트 B. 왼쪽: r = 3.5 µm 쌍극자의 m 항별 방사 power(그때까지의 최대로 나눔). 빨간 점선이 공식 종료 기준 1%, 회색 점선이 $m=2\pi nr$. 오른쪽: m을 어디서 끊느냐에 따른 효율. 보라 점선은 같은 층에서 축 위 쌍극자의 효율.</em></p>

<table>
  <thead>
    <tr>
      <th>계산</th>
      <th>m 범위</th>
      <th>추출 효율</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>축 위 쌍극자 (r = 0.03 µm, m = 1)</td>
      <td>1 run</td>
      <td>0.3636</td>
    </tr>
    <tr>
      <td>r = 3.5 µm, 공식 규칙(첫 1% 미만)</td>
      <td>0…32</td>
      <td>0.6323</td>
    </tr>
    <tr>
      <td>r = 3.5 µm, m = 60까지</td>
      <td>0…60</td>
      <td>0.3616</td>
    </tr>
    <tr>
      <td>공식 규칙 뒤의 되튐</td>
      <td>m = 41에서 최대의 0.38</td>
      <td>—</td>
    </tr>
    <tr>
      <td>노트(10_sources): 공식 문서 CYL / 3D 기준</td>
      <td>—</td>
      <td>0.320–0.324 / 0.334</td>
    </tr>
  </tbody>
</table>

<p><img src="/meep-examples/assets/meep/14/05_kz.png" alt="kz" />
<em>파트 C. 왼쪽: kz마다의 전체 방출(회색)과 공기로 나간 몫(파랑). 점선은 공기, 클래딩, 활성층의 빛선(light line). 오른쪽: kz를 어디까지 더했느냐에 따른 효율.</em></p>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>값</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>kz 점 수</td>
      <td>76 (0~1.50, 간격 0.02)</td>
    </tr>
    <tr>
      <td>마지막 kz의 전체 power / 최대</td>
      <td>0.0189</td>
    </tr>
    <tr>
      <td>추출 효율 (kz 적분)</td>
      <td>22.375%</td>
    </tr>
    <tr>
      <td>kz = 0 하나만 (2D 선전류)</td>
      <td>32.91%</td>
    </tr>
    <tr>
      <td>노트(10_sources)</td>
      <td>22.375%, 76점</td>
    </tr>
  </tbody>
</table>

<p><img src="/meep-examples/assets/meep/14/07_anim_edge.gif" alt="animation" />
<em>파트 C, kz = 0의 짧은 펄스. 활성층의 쌍극자(빨강)에서 나온 빛 대부분이 다층을 따라 기판 쪽으로 가고, 일부가 절단면을 지나 공기로 나간다.</em></p>

<h3 id="예측과-비교">예측과 비교</h3>

<table>
  <thead>
    <tr>
      <th>물리량</th>
      <th>내 예측 (§2)</th>
      <th>시뮬레이션</th>
      <th>판정</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>추출 효율(A, h = 0.5)</td>
      <td>0.3 근처</td>
      <td>0.323 (CYL res 80)</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>높이 의존</td>
      <td>거울에서 멀수록 변한다</td>
      <td>0.52 → 0.09(h 0.8) → 0.17</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>CYL res 40 vs 80</td>
      <td>1% 안</td>
      <td>h ≤ 0.4에서 2~5%, h ≥ 0.6에서 18~54%</td>
      <td>❌</td>
    </tr>
    <tr>
      <td>3D vs CYL</td>
      <td>2% 안</td>
      <td>res 40: h 0.1 0.4%, h 0.5 16%, h 0.9 2.7%</td>
      <td>❌</td>
    </tr>
    <tr>
      <td>축 위 쌍극자(B)</td>
      <td>0.3 근처</td>
      <td>0.364</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>B: 공식 종료 규칙</td>
      <td>sum-to-60과 다르다</td>
      <td>0.632 vs 0.362</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>C: 필요한 kz 수</td>
      <td>70~80</td>
      <td>76</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>C: 추출 효율</td>
      <td>22% 근처</td>
      <td>22.375%</td>
      <td>✅</td>
    </tr>
  </tbody>
</table>

<p>여덟 예측 중 여섯이 맞았고, 틀린 두 개가 모두 해상도 문제였다. 층 두께 0.292 µm는 res 40에서 11.7칸이다. 쌍극자 높이를 층 두께의 비율로 주면 격자에 맞춰 반올림되고, 위쪽 공기 계면 근처(h ≥ 0.6)에서는 field가 급하게 변해 한두 칸의 차이가 효율을 크게 바꾼다. res 40에서 CYL과 3D가 h = 0.5에서 16% 다른 것도 같은 원인으로 본다. 노트의 res 80 값은 CYL 0.323, 3D 0.337로 차이가 1.4%까지 줄었다. 이 층에는 res 80이 필요하다. B는 노트와 소수 넷째 자리까지 같다. 공식 규칙은 m = 32에서 멈춰 0.632를 내지만, 그 뒤 m = 41 근처에서 항이 다시 커진다. 이 항들은 source의 일(분모)이 매우 크고 공기로 나간 몫(분자)은 작다. 층에 갇혀 반지름 방향으로 가는 빛은 쌍극자에서 r만큼 떨어진 곳에서 둘레 $2\pi r$에 $n_{\mathrm{eff}}$배의 파장이 들어가는 m, 즉 $m\approx2\pi n_{\mathrm{eff}}r$ 근처에 실린다. 이 m을 빼면 분모의 대부분이 빠지므로 효율이 두 배로 나온다. m = 60까지 더한 0.362는 축 위 쌍극자의 0.364와 0.5% 안에서 같다. 무한한 층에서는 쌍극자의 가로 위치가 효율을 바꾸지 않아야 하므로 이 일치가 급수를 맞게 끊었다는 검산이다. C에서 kz = 0 하나(2D 선전류)는 32.9%를 주지만 적분하면 22.4%다. kz가 공기의 빛선 k₀를 넘으면 공기로는 빛이 못 나가고(파랑이 0) 다층 안의 guided 방출만 남는다(회색 봉우리). 2D 계산 하나로 3D 소자의 추출 효율을 말하면 이 몫이 빠진다.</p>

<h3 id="수렴성">수렴성</h3>

<table>
  <thead>
    <tr>
      <th>변수</th>
      <th>값</th>
      <th>결과</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>A 해상도</td>
      <td>CYL 40 / 80 (노트 80)</td>
      <td>h 0.5: 0.302 / 0.323</td>
      <td>층이 12칸뿐인 res 40은 부족</td>
    </tr>
    <tr>
      <td>A 좌표계</td>
      <td>CYL 40 vs 3D 40; 노트 CYL 80 vs 3D 80</td>
      <td>16% / 1.4% (h 0.5)</td>
      <td>해상도를 올리면 두 좌표계가 만난다</td>
    </tr>
    <tr>
      <td>B m 범위</td>
      <td>0…32 / 0…60</td>
      <td>0.632 / 0.362</td>
      <td>마지막 항 2e-8</td>
    </tr>
    <tr>
      <td>C kz 범위</td>
      <td>0 / 0…1.50</td>
      <td>32.9% / 22.4%</td>
      <td>tail 0.019</td>
    </tr>
  </tbody>
</table>

<h3 id="주장할-수-있는-것--없는-것">주장할 수 있는 것 / 없는 것</h3>

<ul>
  <li>할 수 있는 것: 이 층(n 2.4, 0.7λ/n, 거울 위)에서 수평 쌍극자의 추출 효율은 높이에 따라 0.52에서 0.09까지 변하고, h = 0.5에서 res 80의 cylindrical 값은 0.323이다. 축에서 3.5 µm 떨어진 쌍극자도 m을 guided 빛 너머(60)까지 더하면 축 위와 같은 0.36이 된다. 절단면 레이저(z 쌍극자, 0.5 µm)의 추출 효율은 kz 적분으로 22.4%다.</li>
  <li>할 수 없는 것: res 40의 높이 곡선(특히 h ≥ 0.6). 3D 값의 수렴(이 글은 res 40만 돌렸다). B의 0.36이 A의 0.32와 다른 이유(셀 크기 20 vs 6 µm, 해상도 50 vs 80, 대역폭이 다르다)를 하나로 정하는 것. 열린 면이라 갇힌 빛이 흡수 없이 어디로 가는지의 에너지 수지.</li>
</ul>

<h2 id="6-흔한-실수">6. 흔한 실수</h2>

<table>
  <thead>
    <tr>
      <th>증상</th>
      <th>원인</th>
      <th>고치는 법</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>효율이 1보다 큼 또는 수백 배 다름</td>
      <td>분모의 $\Delta V$ 누락, 좌표계에 맞지 않는 $\Delta V$</td>
      <td>cyl $2\pi r/\mathrm{res}^2$, 3D $1/\mathrm{res}^3$, 2D $1/\mathrm{res}^2$</td>
    </tr>
    <tr>
      <td>분모를 진공 source power로 둠</td>
      <td>거울·층이 방출량을 바꾼다는 것을 잊음</td>
      <td>같은 run의 <code class="language-plaintext highlighter-rouge">dft_ldos</code>로 잰다</td>
    </tr>
    <tr>
      <td>효율이 너무 큼</td>
      <td>옆면 monitor를 층 높이까지 내림</td>
      <td>옆면은 공기 높이만</td>
    </tr>
    <tr>
      <td>CYL이 축 근처에서 틀림</td>
      <td>Er을 r = 0에 둠</td>
      <td>1.5 픽셀 offset</td>
    </tr>
    <tr>
      <td>m 급수 효율이 크게 다름</td>
      <td>첫 1% 교차에서 멈춤</td>
      <td>guided 빛의 $m\approx2\pi nr$ 너머까지 보고 정한다</td>
    </tr>
    <tr>
      <td>kz 적분이 작게 나옴</td>
      <td>kz &gt; 0 항을 두 배로 세지 않음</td>
      <td>±kz 대칭, $w=2$</td>
    </tr>
    <tr>
      <td>3D가 CYL과 2배 다름</td>
      <td>3D 대칭 위상 틀림</td>
      <td>Ex는 Mirror(X, −1)</td>
    </tr>
  </tbody>
</table>

<h2 id="7-직접-해보기">7. 직접 해보기</h2>

<table>
  <thead>
    <tr>
      <th>바꿀 것</th>
      <th>예상 변화</th>
      <th>확인할 수치</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>A의 층 두께 0.7λ/n → 0.4λ/n</td>
      <td>guided mode가 줄어 효율이 오른다</td>
      <td>η(h = 0.5)</td>
    </tr>
    <tr>
      <td>A를 수직 쌍극자(Ez, m = 0)로</td>
      <td>위로 덜 나가 효율이 크게 준다</td>
      <td>η</td>
    </tr>
    <tr>
      <td>B의 r = 6.7, 9.5 µm</td>
      <td>되튐이 더 큰 m으로 간다</td>
      <td>m_stop, 되튐 위치</td>
    </tr>
    <tr>
      <td>C를 x·y 편광으로</td>
      <td>편광마다 다른 효율</td>
      <td>η</td>
    </tr>
    <tr>
      <td>11개 쌍극자 디스크(disc_extraction_efficiency.py)</td>
      <td>노트: 0.932, m 93개 run</td>
      <td>η, 마지막 m의 몫</td>
    </tr>
  </tbody>
</table>

<h2 id="8-전체-코드">8. 전체 코드</h2>

<details>
<summary>code/extraction_efficiency.py 전체 (클릭하여 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 14 - A point source in a thin film: the share that escapes into air (light-extraction efficiency).

Post 11 measured how much a dipole emits (LDOS); post 13 split a body of revolution into m runs. An LED asks
the ratio of the two: of all the power a dipole in the emitting layer puts out, how much reaches the air?
    extraction efficiency = P_air (flux through an open surface in air) / P_total (source work from dft_ldos)
  A. Official extraction_eff_ldos.py: a dipole in a dielectric layer (n = 2.4, t = 0.7 wl / n) on a ground
     plane, efficiency vs dipole height, in cylindrical coordinates (Er, m = -1) at resolution 40 and 80 and in
     3D (Ex) at resolution 40. The denominator needs the voxel volume of each coordinate system.
  B. Official point_dipole_cyl.py: the same slab, a dipole 3.5 um off the axis = an m series. The official stop
     rule (first m whose radiated flux &lt; 1 % of the running max) is compared with summing far beyond it: the
     slab-guided light reaches the side monitor through high m and the series rebounds.
  C. Official edge_emitter_2D.py: a z-dipole 0.5 um inside the cleaved facet of a multilayer laser stack.
     The 3D problem is a 2D cross-section plus an integral over the out-of-plane wavevector kz.
MPI-safe: collective calls on every rank, figures on the master only.

Run:  mpirun -np 4 python extraction_efficiency.py      (~40 min)
Out:  00_source.png, 01_layout.png, 02_layout_edge.png, 03_height.png, 04_m_series.png, 05_kz.png,
      06_field.png, 07_anim_edge.gif, result.json   (-&gt; ../assets/14/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">math</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">HERE</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"14"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">MASTER</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">()</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">say</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">orient_rz</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">nr</span><span class="p">):</span>
    <span class="n">arr</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">arr</span><span class="p">.</span><span class="n">ndim</span> <span class="o">==</span> <span class="mi">2</span> <span class="ow">and</span> <span class="nb">abs</span><span class="p">(</span><span class="n">arr</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">nr</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">abs</span><span class="p">(</span><span class="n">arr</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">nr</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">arr</span><span class="p">.</span><span class="n">T</span>
    <span class="k">return</span> <span class="n">arr</span>


<span class="k">def</span> <span class="nf">source_work</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">dV</span><span class="p">):</span>
    <span class="s">"""Total power emitted by the point source: -Re(F J*) dV from the dft_ldos data."""</span>
    <span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="o">-</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_Fdata</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">conj</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">ldos_Jdata</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span> <span class="o">*</span> <span class="n">dV</span><span class="p">)</span>


<span class="c1"># ================================================================ A. dipole in a layer on a ground plane: CYL vs 3D
</span><span class="n">WL</span><span class="p">,</span> <span class="n">FREQ</span><span class="p">,</span> <span class="n">N_L</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.4</span>
<span class="n">T_L</span> <span class="o">=</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">WL</span> <span class="o">/</span> <span class="n">N_L</span>                      <span class="c1"># layer thickness
</span><span class="n">DPML</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">,</span> <span class="n">L</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">6.0</span>             <span class="c1"># PML, air above the layer, lateral size of the collection surface
</span><span class="n">TOL</span> <span class="o">=</span> <span class="mf">1e-8</span>
<span class="n">HEIGHTS</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">,</span> <span class="mi">9</span><span class="p">),</span> <span class="mi">3</span><span class="p">)</span>      <span class="c1"># dipole height above the ground plane, fraction of T_L
</span><span class="n">H3D</span> <span class="o">=</span> <span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">layer</span><span class="p">(</span><span class="n">sz</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_L</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">T_L</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">T_L</span><span class="p">))]</span>


<span class="k">def</span> <span class="nf">eff_cyl</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">res</span><span class="p">,</span> <span class="n">want</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="n">sr</span><span class="p">,</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">L</span> <span class="o">+</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">T_L</span> <span class="o">+</span> <span class="n">DAIR</span> <span class="o">+</span> <span class="n">DPML</span>
    <span class="n">src_pt</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">1.5</span> <span class="o">/</span> <span class="n">res</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="n">h</span> <span class="o">*</span> <span class="n">T_L</span><span class="p">)</span>          <span class="c1"># Er at r = 0 is undefined on the Yee grid (meep #2704)
</span>    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">),</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span>
                        <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)],</span>   <span class="c1"># bottom: no PML = ground plane
</span>                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.1</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">src_pt</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">layer</span><span class="p">(</span><span class="n">sz</span><span class="p">))</span>
    <span class="n">flux</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DAIR</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">)))</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">],</span> <span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">))</span> <span class="k">if</span> <span class="n">want</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="k">if</span> <span class="n">want</span><span class="p">:</span>
        <span class="n">annotated_layout</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mf">3.6</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">,</span>
                         <span class="n">title</span><span class="o">=</span><span class="s">"part A, cylindrical (r, z) cell: dipole in a layer (n = 2.4) on a ground plane; x = r, y = z"</span><span class="p">,</span>
                         <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">WL</span><span class="si">}</span><span class="s"> um, res=</span><span class="si">{</span><span class="n">res</span><span class="si">}</span><span class="se">\n</span><span class="s">t = 0.7 wl/n = </span><span class="si">{</span><span class="n">T_L</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> um"</span><span class="p">,</span> <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">3.6</span><span class="p">,</span> <span class="mf">0.33</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">6.05</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.6</span><span class="p">),</span>
                         <span class="n">decay_point</span><span class="o">=</span><span class="p">(</span><span class="n">src_pt</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">.</span><span class="n">z</span><span class="p">),</span> <span class="n">decay_text_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">1.8</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.45</span><span class="p">),</span>
                         <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"layer n = 2.4 (bottom edge: PEC ground plane, no PML)"</span><span class="p">,</span> <span class="p">(</span><span class="mf">2.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.75</span><span class="p">),</span> <span class="p">(</span><span class="mf">1.8</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"Er dipole at r = 1.5 px, height h"</span><span class="p">,</span> <span class="p">(</span><span class="n">src_pt</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">.</span><span class="n">z</span><span class="p">),</span> <span class="p">(</span><span class="mf">1.8</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"numerator: flux through top + outer r (air only)"</span><span class="p">,</span> <span class="p">(</span><span class="mf">4.0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="p">(</span><span class="mf">3.6</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">,</span> <span class="n">TOL</span><span class="p">))</span>
    <span class="n">p_air</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">flux</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">p_tot</span> <span class="o">=</span> <span class="n">source_work</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">src_pt</span><span class="p">.</span><span class="n">x</span> <span class="o">/</span> <span class="n">res</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>         <span class="c1"># CYL voxel: 2 pi r dr dz
</span>    <span class="n">er</span> <span class="o">=</span> <span class="n">orient_rz</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="nb">round</span><span class="p">(</span><span class="n">L</span> <span class="o">*</span> <span class="n">res</span><span class="p">)))</span> <span class="k">if</span> <span class="n">want</span> <span class="k">else</span> <span class="bp">None</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">p_air</span> <span class="o">/</span> <span class="n">p_tot</span><span class="p">,</span> <span class="n">er</span><span class="p">,</span> <span class="n">sz</span>


<span class="k">def</span> <span class="nf">eff_3d</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">res</span><span class="p">):</span>
    <span class="n">sxy</span><span class="p">,</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">L</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">T_L</span> <span class="o">+</span> <span class="n">DAIR</span> <span class="o">+</span> <span class="n">DPML</span>
    <span class="n">src_pt</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="n">h</span> <span class="o">*</span> <span class="n">T_L</span><span class="p">)</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sxy</span><span class="p">,</span> <span class="n">sxy</span><span class="p">,</span> <span class="n">sz</span><span class="p">),</span> <span class="n">symmetries</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span>
                        <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)],</span>
                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.1</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">src_pt</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">layer</span><span class="p">(</span><span class="n">sz</span><span class="p">))</span>
    <span class="n">zc</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DAIR</span>
    <span class="n">flux</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">zc</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">)),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">zc</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="n">zc</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">)),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">L</span><span class="p">,</span> <span class="n">zc</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">DAIR</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ex</span><span class="p">,</span> <span class="n">src_pt</span><span class="p">,</span> <span class="n">TOL</span><span class="p">))</span>
    <span class="n">p_air</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">flux</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">p_tot</span> <span class="o">=</span> <span class="n">source_work</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">res</span> <span class="o">**</span> <span class="mi">3</span><span class="p">)</span>                                <span class="c1"># 3D voxel
</span>    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">p_air</span> <span class="o">/</span> <span class="n">p_tot</span>


<span class="n">t_a</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">effA</span> <span class="o">=</span> <span class="p">{</span><span class="s">"cyl40"</span><span class="p">:</span> <span class="p">[],</span> <span class="s">"cyl80"</span><span class="p">:</span> <span class="p">[]}</span>
<span class="n">er_map</span><span class="p">,</span> <span class="n">sz_A</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="bp">None</span>
<span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="n">HEIGHTS</span><span class="p">:</span>
    <span class="n">effA</span><span class="p">[</span><span class="s">"cyl40"</span><span class="p">].</span><span class="n">append</span><span class="p">(</span><span class="n">eff_cyl</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="mi">40</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">e80</span><span class="p">,</span> <span class="n">er</span><span class="p">,</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">eff_cyl</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="mi">80</span><span class="p">,</span> <span class="n">want</span><span class="o">=</span><span class="p">(</span><span class="n">h</span> <span class="o">==</span> <span class="mf">0.5</span><span class="p">))</span>
    <span class="n">effA</span><span class="p">[</span><span class="s">"cyl80"</span><span class="p">].</span><span class="n">append</span><span class="p">(</span><span class="n">e80</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">er</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">er_map</span><span class="p">,</span> <span class="n">sz_A</span> <span class="o">=</span> <span class="n">er</span><span class="p">,</span> <span class="n">sz</span>
<span class="n">say</span><span class="p">(</span><span class="s">"A (cyl): "</span> <span class="o">+</span> <span class="s">"; "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"h </span><span class="si">{</span><span class="n">h</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">: res40 </span><span class="si">{</span><span class="n">a</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, res80 </span><span class="si">{</span><span class="n">b</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">h</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">HEIGHTS</span><span class="p">,</span> <span class="n">effA</span><span class="p">[</span><span class="s">"cyl40"</span><span class="p">],</span> <span class="n">effA</span><span class="p">[</span><span class="s">"cyl80"</span><span class="p">]))</span> <span class="o">+</span> <span class="sa">f</span><span class="s">"; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_a</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>
<span class="n">t_a3</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">eff3</span> <span class="o">=</span> <span class="p">{</span><span class="n">h</span><span class="p">:</span> <span class="n">eff_3d</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span> <span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="n">H3D</span><span class="p">}</span>
<span class="n">say</span><span class="p">(</span><span class="s">"A (3D, res 40): "</span> <span class="o">+</span> <span class="s">"; "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"h </span><span class="si">{</span><span class="n">h</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">v</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (cyl40 </span><span class="si">{</span><span class="n">effA</span><span class="p">[</span><span class="s">'cyl40'</span><span class="p">][</span><span class="nb">list</span><span class="p">(</span><span class="n">HEIGHTS</span><span class="p">).</span><span class="n">index</span><span class="p">(</span><span class="n">h</span><span class="p">)]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, cyl80 </span><span class="si">{</span><span class="n">effA</span><span class="p">[</span><span class="s">'cyl80'</span><span class="p">][</span><span class="nb">list</span><span class="p">(</span><span class="n">HEIGHTS</span><span class="p">).</span><span class="n">index</span><span class="p">(</span><span class="n">h</span><span class="p">)]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">)"</span> <span class="k">for</span> <span class="n">h</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">eff3</span><span class="p">.</span><span class="n">items</span><span class="p">())</span> <span class="o">+</span> <span class="sa">f</span><span class="s">"; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_a3</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
    <span class="n">source_figure</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>

<span class="c1"># ================================================================ B. off-axis dipole in the slab: the m series and when to stop
</span><span class="n">t_b</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">RES_B</span><span class="p">,</span> <span class="n">R_CELL</span><span class="p">,</span> <span class="n">PML_B</span><span class="p">,</span> <span class="n">PAD_B</span> <span class="o">=</span> <span class="mi">50</span><span class="p">,</span> <span class="mf">20.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span>
<span class="n">M_MAX</span> <span class="o">=</span> <span class="mi">60</span>
<span class="n">R_SRC</span> <span class="o">=</span> <span class="mf">3.5</span>


<span class="k">def</span> <span class="nf">dipole_in_slab</span><span class="p">(</span><span class="n">rpos</span><span class="p">,</span> <span class="n">m</span><span class="p">):</span>
    <span class="n">sr</span><span class="p">,</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">R_CELL</span> <span class="o">+</span> <span class="n">PML_B</span><span class="p">,</span> <span class="n">T_L</span> <span class="o">+</span> <span class="n">PAD_B</span> <span class="o">+</span> <span class="n">PML_B</span>
    <span class="n">src_pt</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">rpos</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">T_L</span><span class="p">)</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_B</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">),</span> <span class="n">dimensions</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">CYLINDRICAL</span><span class="p">,</span> <span class="n">m</span><span class="o">=</span><span class="n">m</span><span class="p">,</span> <span class="n">force_complex_fields</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
                        <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">PML_B</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">R</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">PML_B</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">side</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">High</span><span class="p">)],</span>
                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.05</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Er</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">src_pt</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">layer</span><span class="p">(</span><span class="n">sz</span><span class="p">))</span>
    <span class="n">flux</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">R_CELL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">PML_B</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_CELL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_CELL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz</span> <span class="o">-</span> <span class="n">PML_B</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">PAD_B</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">PAD_B</span><span class="p">)))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_dft_decayed</span><span class="p">(</span><span class="n">tol</span><span class="o">=</span><span class="mf">1e-4</span><span class="p">))</span>
    <span class="n">rad</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">flux</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">src</span> <span class="o">=</span> <span class="n">source_work</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">rpos</span> <span class="o">/</span> <span class="n">RES_B</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">rad</span><span class="p">,</span> <span class="n">src</span>


<span class="n">r_ax</span> <span class="o">=</span> <span class="mf">1.5</span> <span class="o">/</span> <span class="n">RES_B</span>
<span class="n">rad_ax</span><span class="p">,</span> <span class="n">src_ax</span> <span class="o">=</span> <span class="n">dipole_in_slab</span><span class="p">(</span><span class="n">r_ax</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">eff_axis</span> <span class="o">=</span> <span class="n">rad_ax</span> <span class="o">/</span> <span class="n">src_ax</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"B: dipole on the axis (m = 1, r = </span><span class="si">{</span><span class="n">r_ax</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">): extraction </span><span class="si">{</span><span class="n">eff_axis</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">rads</span><span class="p">,</span> <span class="n">srcs</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">M_MAX</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
    <span class="n">rad</span><span class="p">,</span> <span class="n">src</span> <span class="o">=</span> <span class="n">dipole_in_slab</span><span class="p">(</span><span class="n">R_SRC</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span>
    <span class="n">rads</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">rad</span><span class="p">);</span> <span class="n">srcs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">src</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">m</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"B: r </span><span class="si">{</span><span class="n">R_SRC</span><span class="si">}</span><span class="s">, m = </span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">: radiated </span><span class="si">{</span><span class="n">rad</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s">, source </span><span class="si">{</span><span class="n">src</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s">; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_b</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>
<span class="n">rads</span><span class="p">,</span> <span class="n">srcs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">rads</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">srcs</span><span class="p">)</span>
<span class="n">w</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="n">M_MAX</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>                                  <span class="c1"># +-m give the same power: count m &gt; 0 twice
</span><span class="n">running_max</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">maximum</span><span class="p">.</span><span class="n">accumulate</span><span class="p">(</span><span class="n">rads</span><span class="p">)</span>
<span class="n">rel</span> <span class="o">=</span> <span class="n">rads</span> <span class="o">/</span> <span class="n">running_max</span>
<span class="n">m_stop</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="n">m</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">M_MAX</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="n">rel</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mf">1e-2</span><span class="p">))</span>             <span class="c1"># official rule: first m &gt; 0 below 1 % of the running max
</span><span class="n">eff_series</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">w</span> <span class="o">*</span> <span class="n">rads</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">w</span> <span class="o">*</span> <span class="n">srcs</span><span class="p">)</span>
<span class="n">eff_official</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">eff_series</span><span class="p">[</span><span class="n">m_stop</span><span class="p">]);</span> <span class="n">eff_full</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">eff_series</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="n">rebound</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">rel</span><span class="p">[</span><span class="n">m_stop</span><span class="p">:].</span><span class="nb">max</span><span class="p">())</span>
<span class="n">m_rebound</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">m_stop</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">rel</span><span class="p">[</span><span class="n">m_stop</span><span class="p">:]))</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"B: official stop at m = </span><span class="si">{</span><span class="n">m_stop</span><span class="si">}</span><span class="s"> (radiated/max </span><span class="si">{</span><span class="n">rel</span><span class="p">[</span><span class="n">m_stop</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">e</span><span class="si">}</span><span class="s">) -&gt; efficiency </span><span class="si">{</span><span class="n">eff_official</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; after the stop the series rebounds to "</span>
    <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">rebound</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> of the max at m = </span><span class="si">{</span><span class="n">m_rebound</span><span class="si">}</span><span class="s">; summed to m = </span><span class="si">{</span><span class="n">M_MAX</span><span class="si">}</span><span class="s">: efficiency </span><span class="si">{</span><span class="n">eff_full</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (last term </span><span class="si">{</span><span class="n">rel</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">e</span><span class="si">}</span><span class="s">); </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_b</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="c1"># ================================================================ C. cleaved-facet edge emitter: 2D cross-section + kz integral
</span><span class="n">t_c</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">RES_C</span><span class="p">,</span> <span class="n">CLAD</span><span class="p">,</span> <span class="n">ACT</span><span class="p">,</span> <span class="n">SUB</span><span class="p">,</span> <span class="n">PML_C</span><span class="p">,</span> <span class="n">AIR_C</span><span class="p">,</span> <span class="n">SIDE</span> <span class="o">=</span> <span class="mi">25</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">3.0</span>
<span class="n">N_SUB</span><span class="p">,</span> <span class="n">N_CLAD</span><span class="p">,</span> <span class="n">N_ACT</span> <span class="o">=</span> <span class="mf">3.2</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">,</span> <span class="mf">2.3</span>
<span class="n">DKZ</span><span class="p">,</span> <span class="n">KZ_TOL</span><span class="p">,</span> <span class="n">POS_C</span> <span class="o">=</span> <span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.5</span>
<span class="n">CX</span> <span class="o">=</span> <span class="n">PML_C</span> <span class="o">+</span> <span class="n">SIDE</span> <span class="o">+</span> <span class="n">AIR_C</span> <span class="o">+</span> <span class="n">PML_C</span>
<span class="n">CY</span> <span class="o">=</span> <span class="n">PML_C</span> <span class="o">+</span> <span class="n">SUB</span> <span class="o">+</span> <span class="n">CLAD</span> <span class="o">+</span> <span class="n">ACT</span> <span class="o">+</span> <span class="n">CLAD</span> <span class="o">+</span> <span class="n">AIR_C</span> <span class="o">+</span> <span class="n">PML_C</span>
<span class="n">SRC_C</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CX</span> <span class="o">+</span> <span class="n">PML_C</span> <span class="o">+</span> <span class="n">SIDE</span> <span class="o">-</span> <span class="n">POS_C</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CY</span> <span class="o">+</span> <span class="n">PML_C</span> <span class="o">+</span> <span class="n">SUB</span> <span class="o">+</span> <span class="n">CLAD</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">ACT</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">stack</span><span class="p">():</span>
    <span class="n">x0</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CX</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">PML_C</span> <span class="o">+</span> <span class="n">SIDE</span><span class="p">);</span> <span class="n">wx</span> <span class="o">=</span> <span class="n">PML_C</span> <span class="o">+</span> <span class="n">SIDE</span><span class="p">;</span> <span class="n">y</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CY</span>
    <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">th</span><span class="p">,</span> <span class="n">n</span> <span class="ow">in</span> <span class="p">((</span><span class="n">PML_C</span> <span class="o">+</span> <span class="n">SUB</span><span class="p">,</span> <span class="n">N_SUB</span><span class="p">),</span> <span class="p">(</span><span class="n">CLAD</span><span class="p">,</span> <span class="n">N_CLAD</span><span class="p">),</span> <span class="p">(</span><span class="n">ACT</span><span class="p">,</span> <span class="n">N_ACT</span><span class="p">),</span> <span class="p">(</span><span class="n">CLAD</span><span class="p">,</span> <span class="n">N_CLAD</span><span class="p">)):</span>
        <span class="n">out</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">n</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">x0</span><span class="p">,</span> <span class="n">y</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">th</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">wx</span><span class="p">,</span> <span class="n">th</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">)));</span> <span class="n">y</span> <span class="o">+=</span> <span class="n">th</span>
    <span class="k">return</span> <span class="n">out</span>


<span class="k">def</span> <span class="nf">edge_sim</span><span class="p">(</span><span class="n">kz</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.1</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">,</span> <span class="n">monitors</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES_C</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">CX</span><span class="p">,</span> <span class="n">CY</span><span class="p">),</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">kz</span><span class="p">),</span> <span class="n">kz_2d</span><span class="o">=</span><span class="s">"real/imag"</span><span class="p">,</span>
                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">SRC_C</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">stack</span><span class="p">(),</span>
                        <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">PML_C</span><span class="p">)])</span>
    <span class="n">flux</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="k">if</span> <span class="n">monitors</span><span class="p">:</span>
        <span class="n">flux</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
                            <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">CY</span> <span class="o">-</span> <span class="n">PML_C</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">CX</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">PML_C</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>                 <span class="c1"># top
</span>                            <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CX</span> <span class="o">-</span> <span class="n">PML_C</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">CY</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">PML_C</span><span class="p">)),</span>                 <span class="c1"># right (in front of the facet)
</span>                            <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CX</span> <span class="o">-</span> <span class="n">PML_C</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">AIR_C</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CY</span> <span class="o">+</span> <span class="n">PML_C</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">AIR_C</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">weight</span><span class="o">=-</span><span class="mf">1.0</span><span class="p">))</span>   <span class="c1"># bottom of the air gap
</span>    <span class="k">return</span> <span class="n">sim</span><span class="p">,</span> <span class="n">flux</span>


<span class="n">kzs</span><span class="p">,</span> <span class="n">d_kz</span><span class="p">,</span> <span class="n">a_kz</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="n">nkz</span><span class="p">,</span> <span class="n">dmax</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.0</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="n">kz</span> <span class="o">=</span> <span class="n">nkz</span> <span class="o">*</span> <span class="n">DKZ</span>
    <span class="n">sim</span><span class="p">,</span> <span class="n">flux</span> <span class="o">=</span> <span class="n">edge_sim</span><span class="p">(</span><span class="n">kz</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">nkz</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">annotated_layout</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_layout_edge.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">PML_C</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">6.4</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">,</span>
                         <span class="n">title</span><span class="o">=</span><span class="s">"part C: cleaved facet of a laser stack (2D x-y); the stack is uniform along z"</span><span class="p">,</span>
                         <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"res=</span><span class="si">{</span><span class="n">RES_C</span><span class="si">}</span><span class="s">, kz step </span><span class="si">{</span><span class="n">DKZ</span><span class="si">}</span><span class="se">\n</span><span class="s">sub 3.2 / clad 1.5 / act 2.3"</span><span class="p">,</span> <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">2.4</span><span class="p">,</span> <span class="mf">2.25</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">2.4</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.2</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
                         <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"Ez dipole 0.5 um inside the facet"</span><span class="p">,</span> <span class="p">(</span><span class="n">SRC_C</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">SRC_C</span><span class="p">.</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">2.4</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"active layer n = 2.3 between claddings"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">1.5</span><span class="p">,</span> <span class="n">SRC_C</span><span class="p">.</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">2.4</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"air flux: top + front + under the gap"</span><span class="p">,</span> <span class="p">(</span><span class="mf">1.9</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.3</span><span class="p">,</span> <span class="mf">1.9</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">dft_ldos</span><span class="p">(</span><span class="n">FREQ</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_C</span><span class="p">,</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">dflux</span> <span class="o">=</span> <span class="n">source_work</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">RES_C</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>            <span class="c1"># 2D: a line current, pixel area
</span>    <span class="n">aflux</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">flux</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">kzs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">kz</span><span class="p">);</span> <span class="n">d_kz</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">dflux</span><span class="p">);</span> <span class="n">a_kz</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">aflux</span><span class="p">)</span>
    <span class="n">nkz</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">if</span> <span class="n">dflux</span> <span class="o">&gt;</span> <span class="n">dmax</span><span class="p">:</span>
        <span class="n">dmax</span> <span class="o">=</span> <span class="n">dflux</span>
    <span class="k">elif</span> <span class="n">dflux</span> <span class="o">/</span> <span class="n">dmax</span> <span class="o">&lt;</span> <span class="n">KZ_TOL</span><span class="p">:</span>
        <span class="k">break</span>
<span class="n">kzs</span><span class="p">,</span> <span class="n">d_kz</span><span class="p">,</span> <span class="n">a_kz</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">,</span> <span class="p">(</span><span class="n">kzs</span><span class="p">,</span> <span class="n">d_kz</span><span class="p">,</span> <span class="n">a_kz</span><span class="p">))</span>
<span class="n">eff_edge</span> <span class="o">=</span> <span class="nb">float</span><span class="p">((</span><span class="n">a_kz</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">a_kz</span><span class="p">[</span><span class="mi">1</span><span class="p">:].</span><span class="nb">sum</span><span class="p">())</span> <span class="o">/</span> <span class="p">(</span><span class="n">d_kz</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">d_kz</span><span class="p">[</span><span class="mi">1</span><span class="p">:].</span><span class="nb">sum</span><span class="p">()))</span>
<span class="n">eff_kz0</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">a_kz</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">d_kz</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">kz_cut</span> <span class="o">=</span> <span class="n">N_ACT</span> <span class="o">*</span> <span class="n">FREQ</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"C: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">kzs</span><span class="p">)</span><span class="si">}</span><span class="s"> kz points up to </span><span class="si">{</span><span class="n">kzs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> (tail </span><span class="si">{</span><span class="n">d_kz</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="n">dmax</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">); extraction </span><span class="si">{</span><span class="mi">100</span> <span class="o">*</span> <span class="n">eff_edge</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> % (kz = 0 alone: </span><span class="si">{</span><span class="mi">100</span> <span class="o">*</span> <span class="n">eff_kz0</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> %); </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_c</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="c1"># GIF: kz = 0, short pulse, monitor-free
</span><span class="n">sim_g</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">edge_sim</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">,</span> <span class="n">monitors</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">vol</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">CX</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">PML_C</span><span class="p">,</span> <span class="n">CY</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">PML_C</span><span class="p">))</span>
<span class="n">eps_g</span> <span class="o">=</span> <span class="n">sim_g</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">vol</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">t0</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">)</span>
<span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_g</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t0</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">(</span><span class="mf">0.4</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">),</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t0</span> <span class="o">+</span> <span class="mf">9.0</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="c1"># ================================================================ figures
</span><span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mf">4.3</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"width_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">1.4</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">HEIGHTS</span><span class="p">,</span> <span class="n">effA</span><span class="p">[</span><span class="s">"cyl80"</span><span class="p">],</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"cylindrical, res 80 (official)"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">HEIGHTS</span><span class="p">,</span> <span class="n">effA</span><span class="p">[</span><span class="s">"cyl40"</span><span class="p">],</span> <span class="s">"s--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:cyan"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"cylindrical, res 40"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">H3D</span><span class="p">),</span> <span class="p">[</span><span class="n">eff3</span><span class="p">[</span><span class="n">h</span><span class="p">]</span> <span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="n">H3D</span><span class="p">],</span> <span class="s">"D"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"3D Cartesian, res 40"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"dipole height above the ground plane / layer thickness"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"extraction efficiency into air"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"dipole in a 0.29 um layer (n = 2.4) on a mirror"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ext</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz_A</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz_A</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">]</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">log10</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">er_map</span><span class="p">)</span> <span class="o">+</span> <span class="mf">1e-12</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">ext</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"auto"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Rectangle</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sz_A</span><span class="p">),</span> <span class="n">L</span><span class="p">,</span> <span class="n">T_L</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"r [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"z [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"log10 |Er|, h = 0.5 (res 80): much of the light stays in the layer"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_height.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

    <span class="n">ms</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="n">M_MAX</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mf">4.3</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">semilogy</span><span class="p">(</span><span class="n">ms</span><span class="p">,</span> <span class="n">rel</span><span class="p">,</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"radiated(m) / running max"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mf">1e-2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"official stop: 1 %"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="n">m_stop</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">m_stop</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">2e-1</span><span class="p">,</span> <span class="sa">f</span><span class="s">"stop at m = </span><span class="si">{</span><span class="n">m_stop</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">m_rebound</span><span class="p">,</span> <span class="n">rebound</span><span class="p">,</span> <span class="s">"*"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:orange"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"rebound </span><span class="si">{</span><span class="n">rebound</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> at m = </span><span class="si">{</span><span class="n">m_rebound</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">N_L</span> <span class="o">*</span> <span class="n">R_SRC</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"-."</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">N_L</span> <span class="o">*</span> <span class="n">R_SRC</span> <span class="o">-</span> <span class="mi">14</span><span class="p">,</span> <span class="mf">2e-4</span><span class="p">,</span> <span class="s">"m = 2 pi n r (guided in the slab)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"azimuthal order m"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"radiated power of the m term (relative)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"dipole at r = </span><span class="si">{</span><span class="n">R_SRC</span><span class="si">}</span><span class="s"> um in the slab"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">"both"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">ms</span><span class="p">,</span> <span class="n">eff_series</span><span class="p">,</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="n">m_stop</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="n">eff_axis</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:purple"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"dipole on the axis: </span><span class="si">{</span><span class="n">eff_axis</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">m_stop</span><span class="p">,</span> <span class="n">eff_official</span><span class="p">,</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"official stop: </span><span class="si">{</span><span class="n">eff_official</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">M_MAX</span><span class="p">,</span> <span class="n">eff_full</span><span class="p">,</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"summed to m = </span><span class="si">{</span><span class="n">M_MAX</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">eff_full</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"m included up to"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"extraction efficiency"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"the efficiency depends on where the series is cut"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_m_series.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mf">4.3</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">kzs</span><span class="p">,</span> <span class="n">d_kz</span> <span class="o">/</span> <span class="n">d_kz</span><span class="p">.</span><span class="nb">max</span><span class="p">(),</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"total (dft_ldos)"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">kzs</span><span class="p">,</span> <span class="n">a_kz</span> <span class="o">/</span> <span class="n">d_kz</span><span class="p">.</span><span class="nb">max</span><span class="p">(),</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"into air"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">kc</span><span class="p">,</span> <span class="n">lab</span> <span class="ow">in</span> <span class="p">((</span><span class="n">FREQ</span><span class="p">,</span> <span class="s">"kz = k0 (air light line)"</span><span class="p">),</span> <span class="p">(</span><span class="n">N_CLAD</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">,</span> <span class="s">"1.5 k0"</span><span class="p">),</span> <span class="p">(</span><span class="n">N_ACT</span> <span class="o">*</span> <span class="n">FREQ</span><span class="p">,</span> <span class="s">"2.3 k0"</span><span class="p">)):</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="n">kc</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">kc</span> <span class="o">+</span> <span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">,</span> <span class="n">lab</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">rotation</span><span class="o">=</span><span class="mi">90</span><span class="p">,</span> <span class="n">va</span><span class="o">=</span><span class="s">"top"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"kz [2 pi / um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"power per kz (relative)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">kzs</span><span class="p">)</span><span class="si">}</span><span class="s"> 2D runs, one per kz"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">cum</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">kzs</span><span class="p">))</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">a_kz</span><span class="p">))</span> <span class="o">/</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">kzs</span><span class="p">))</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">d_kz</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">kzs</span><span class="p">,</span> <span class="mi">100</span> <span class="o">*</span> <span class="n">cum</span><span class="p">,</span> <span class="s">"-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mi">100</span> <span class="o">*</span> <span class="n">eff_edge</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mi">100</span> <span class="o">*</span> <span class="n">eff_kz0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:orange"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"kz = 0 alone (2D line source): </span><span class="si">{</span><span class="mi">100</span> <span class="o">*</span> <span class="n">eff_kz0</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> %"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"kz included up to"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"extraction efficiency [%]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"kz integral: </span><span class="si">{</span><span class="mi">100</span> <span class="o">*</span> <span class="n">eff_edge</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> % into air"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_kz.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

    <span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="p">[</span><span class="o">-</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CX</span> <span class="o">-</span> <span class="n">PML_C</span><span class="p">),</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">CX</span> <span class="o">-</span> <span class="n">PML_C</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">CY</span> <span class="o">-</span> <span class="n">PML_C</span><span class="p">),</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">CY</span> <span class="o">-</span> <span class="n">PML_C</span><span class="p">],</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"07_anim_edge.gif"</span><span class="p">),</span>
                   <span class="n">eps</span><span class="o">=</span><span class="n">eps_g</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.6</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span> <span class="n">clip_percentile</span><span class="o">=</span><span class="mf">99.0</span><span class="p">,</span> <span class="n">points</span><span class="o">=</span><span class="p">[(</span><span class="n">SRC_C</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">SRC_C</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"dipole"</span><span class="p">)],</span>
                   <span class="n">title</span><span class="o">=</span><span class="s">"edge emitter, kz = 0"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f_</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"A"</span><span class="p">:</span> <span class="p">{</span><span class="s">"heights"</span><span class="p">:</span> <span class="n">HEIGHTS</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"cyl40"</span><span class="p">:</span> <span class="n">effA</span><span class="p">[</span><span class="s">"cyl40"</span><span class="p">],</span> <span class="s">"cyl80"</span><span class="p">:</span> <span class="n">effA</span><span class="p">[</span><span class="s">"cyl80"</span><span class="p">],</span> <span class="s">"3d40"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="n">k</span><span class="p">):</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">eff3</span><span class="p">.</span><span class="n">items</span><span class="p">()}},</span>
                   <span class="s">"B"</span><span class="p">:</span> <span class="p">{</span><span class="s">"r"</span><span class="p">:</span> <span class="n">R_SRC</span><span class="p">,</span> <span class="s">"eff_axis"</span><span class="p">:</span> <span class="n">eff_axis</span><span class="p">,</span> <span class="s">"m_stop"</span><span class="p">:</span> <span class="n">m_stop</span><span class="p">,</span> <span class="s">"eff_official"</span><span class="p">:</span> <span class="n">eff_official</span><span class="p">,</span> <span class="s">"eff_full"</span><span class="p">:</span> <span class="n">eff_full</span><span class="p">,</span> <span class="s">"rebound"</span><span class="p">:</span> <span class="n">rebound</span><span class="p">,</span>
                         <span class="s">"m_rebound"</span><span class="p">:</span> <span class="n">m_rebound</span><span class="p">,</span> <span class="s">"rel"</span><span class="p">:</span> <span class="n">rel</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"eff_series"</span><span class="p">:</span> <span class="n">eff_series</span><span class="p">.</span><span class="n">tolist</span><span class="p">()},</span>
                   <span class="s">"C"</span><span class="p">:</span> <span class="p">{</span><span class="s">"n_kz"</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">kzs</span><span class="p">),</span> <span class="s">"kz_max"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">kzs</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]),</span> <span class="s">"tail"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">d_kz</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="n">dmax</span><span class="p">),</span> <span class="s">"eff"</span><span class="p">:</span> <span class="n">eff_edge</span><span class="p">,</span> <span class="s">"eff_kz0"</span><span class="p">:</span> <span class="n">eff_kz0</span><span class="p">},</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"np"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">count_processors</span><span class="p">(),</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">},</span> <span class="n">f_</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"total </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s on </span><span class="si">{</span><span class="n">mp</span><span class="p">.</span><span class="n">count_processors</span><span class="p">()</span><span class="si">}</span><span class="s"> process(es)"</span><span class="p">)</span></code></pre></figure>

</details>

<p>§4의 발췌 코드와 달리 전체 코드에는 높이 sweep, m 급수와 종료 규칙 비교, kz 적분, GIF, result.json 기록이 들어 있다. MPI로 돌릴 수 있게 collective 호출은 모든 rank에서, 그림 저장은 master에서만 한다. 설계도 두 장은 시간 진행 없이 같은 셀을 만드는 <code class="language-plaintext highlighter-rouge">code/extraction_layouts.py</code>로 그렸다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

<p><strong>실행 결과 (2026-10-23 실행, mpirun -np 4)</strong>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A (cyl): h 0.1: res40 0.5494, res80 0.5230; h 0.2: res40 0.5214, res80 0.5038; h 0.3: res40 0.4735, res80 0.4645; h 0.4: res40 0.4014, res80 0.4050; h 0.5: res40 0.3018, res80 0.3232; h 0.6: res40 0.1805, res80 0.2213; h 0.7: res40 0.0891, res80 0.1259; h 0.8: res40 0.1095, res80 0.0915; h 0.9: res40 0.2681, res80 0.1745; 253 s
A (3D, res 40): h 0.1: 0.5475 (cyl40 0.5494, cyl80 0.5230); h 0.5: 0.3505 (cyl40 0.3018, cyl80 0.3232); h 0.9: 0.2607 (cyl40 0.2681, cyl80 0.1745); 476 s
B: dipole on the axis (m = 1, r = 0.03): extraction 0.3636
B: r 3.5, m = 0: radiated 8.3457e+03, source 9.8732e+03
B: r 3.5, m = 20: radiated 1.8285e+03, source 5.9457e+03
B: r 3.5, m = 40: radiated 4.1701e+03, source 3.9968e+04
B: r 3.5, m = 60: radiated 2.4012e-04, source 3.0755e-02
B: official stop at m = 32 (radiated/max 5.48e-03) -&gt; efficiency 0.6323; after the stop the series rebounds to 0.382 of the max at m = 41; summed to m = 60: efficiency 0.3616 (last term 2.0e-08); 3502 s
C: 76 kz points up to 1.50 (tail 0.0189); extraction 22.375 % (kz = 0 alone: 32.91 %); 359 s
total 4604 s on 4 process(es)
</code></pre></div></div>

<p><strong>재현 환경</strong>: meep 1.33.0 (MPI) · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep=*=mpi_mpich_*</code> · 실행 <code class="language-plaintext highlighter-rouge">mpirun -np 4 python extraction_efficiency.py</code> (약 77 min (mpirun -np 4; B alone 58 min))</p>

<h2 id="확인-질문">확인 질문</h2>

<ol>
  <li>11편의 Purcell 인자에서는 $\Delta V$가 필요 없었는데 추출 효율에서는 왜 필요한가.</li>
  <li>축에서 3.5 µm 떨어진 쌍극자의 m 급수가 m 30 근처에서 작아졌다가 다시 커지는 이유를 층에 갇힌 빛과 $m\approx2\pi n r$로 설명해 보라.</li>
  <li>실제 OLED의 발광층에는 위치와 방향이 제각각인 분자가 수천 개 있고, 서로 위상이 맞지 않는다. 이 글처럼 쌍극자 하나씩 돌려 power를 더하면 run이 몇 개 필요한가. 그것을 몇 번의 run으로 줄이는 방법이 있는가. (15편)</li>
</ol>

<h2 id="9-더-읽기">9. 더 읽기</h2>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Local_Density_of_States/#extraction-efficiency-of-a-light-emitting-diode-led">LDOS 튜토리얼: LED 추출 효율</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Cylindrical_Coordinates/#nonaxisymmetric-dipole-sources">nonaxisymmetric dipole sources</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#ldos-spectra"><code class="language-plaintext highlighter-rouge">dft_ldos</code></a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#the-simulation-class">kz_2d</a></li>
  <li>스크립트: <a href="https://github.com/NanoComp/meep/blob/master/python/examples/extraction_eff_ldos.py">extraction_eff_ldos.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/point_dipole_cyl.py">point_dipole_cyl.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/edge_emitter_2D.py">edge_emitter_2D.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/disc_extraction_efficiency.py">disc_extraction_efficiency.py</a></li>
  <li>이전 글: <a href="/meep-examples/cylindrical-dipole/">13 · 회전 대칭으로 3D를 계산하기</a> · LDOS: <a href="/meep-examples/cavity-ldos/">11 · 두 거울 사이의 점광원</a> · 다음 글: 15 · 점광원이 수천 개일 때</li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="extraction-efficiency" /><category term="led" /><category term="oled" /><category term="ldos" /><category term="cylindrical" /><category term="kz" /><category term="edge-emitter" /><summary type="html"><![CDATA[post 11 measured how much a dipole emits (LDOS); post 13 split a body of revolution into m runs. An LED asks for the ratio: of everything a dipole in the emitting layer puts out, how much reaches the air. Extraction efficiency = flux through an open surface in air ÷ the source's own work from `dft_ldos`. Three official examples: a dipole in a layer on a mirror (cylindrical vs 3D), the same slab with the dipole off the axis (an m series), and a dipole inside the cleaved facet of a laser stack (a 2D cross-section plus a kz integral).]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/14/04_m_series.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/14/04_m_series.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 07 · Metalens의 meta-atom과 phase library — 폭 하나로 위상을 돌리고, 4단계로 빛을 꺾고, 어디서 설계가 틀어지는가</title><link href="https://jin-castle.github.io/meep-examples/meta-atom/" rel="alternate" type="text/html" title="Meep Example 07 · Metalens의 meta-atom과 phase library — 폭 하나로 위상을 돌리고, 4단계로 빛을 꺾고, 어디서 설계가 틀어지는가" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/meta-atom</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/meta-atom/"><![CDATA[<details>
  <summary>English summary</summary>

  <ul>
    <li><strong>What</strong>: a silicon bar in a 0.45 µm unit cell is a meta-atom. Sweep its width, record the complex transmission t(w), and you have a phase library. Pick four widths that step the phase by 90°, tile them into a 1.8 µm supercell, and the structure should deflect 1550 nm light to +59.4°.</li>
    <li><strong>Result</strong>: the library covers 1.10 × 2π with |t| between 0.69 and 1.01. The 4-level supercell sends 51 % of the power into the +1 order, 16 % into −1 and 3 % straight through; that is 63 % of the 4-level blazed bound 0.81. A 40-atom array peaks at 58.5°.</li>
    <li><strong>Takeaway</strong>: the library assumes every neighbour is identical. In the real supercell they are not, so the local-phase approximation leaks power into the wrong orders. That gap is what inverse design (post 08) closes.</li>
    <li><strong>Code</strong>: full script at the bottom, ~35 s on one core.</li>
  </ul>

</details>

<h2 id="observe">1. 관찰 · 빛의 경로를 먼저 보기</h2>

<p>폭이 다른 네 Si 막대를 반복해 배치했습니다. 빛은 아래에서 위로 들어오고, 막대를 지난 파면은 오른쪽으로 기웁니다. <strong>오른쪽으로 나가는 +1차에 모든 빛이 모였는지</strong> 왼쪽 차수별 효율 막대그래프로 확인해 보세요.</p>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/07/04_supercell.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/04_supercell.png" alt="네 Si 막대 supercell의 차수별 효율과 실제 Re(Ez), 진폭 필드. +1차가 가장 크지만 다른 차수도 남아 있다." loading="lazy" />
  </a>
  <figcaption>목표 +1차 효율은 약 0.514이고 −1차와 0차에도 빛이 남습니다. 그림의 0.811 점선은 균일 진폭을 가정한 이상적 4단계 위상 모델의 기준입니다.</figcaption>
</figure>

<figure class="lesson-figure lesson-animation">
  <a href="/meep-examples/assets/meep/07/06_anim_array.gif" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/06_anim_array.gif" alt="12개 Si 막대를 지난 펄스의 파면이 오른쪽으로 기울어 전파하는 시간 전개" loading="lazy" data-animation-src="/meep-examples/assets/meep/07/06_anim_array.gif" data-static-src="/meep-examples/assets/meep/07/04_supercell.png" />
  </a>
  <button class="animation-toggle" type="button" hidden="">애니메이션 정지</button>
  <figcaption>12-atom 배열에 짧은 펄스(fwidth 0.4 fcen)가 아래에서 올라온다. 막대를 지난 파면이 오른쪽으로 기운 채 나간다. 방향은 위상 기울기가, 폭은 개구가 정한다.</figcaption>
</figure>

<h2 id="predict">2. 예측 · 결과를 읽기 전에</h2>

<p>단위 셀의 위상이 2π 전체를 덮으면, 네 막대를 조합한 배열도 반드시 목표 차수로 100% 보낼까요?</p>

<fieldset class="prediction">
  <legend>먼저 하나를 골라보세요.</legend>
  <label><input type="radio" name="prediction-07" value="0" /> 원하는 위상을 모두 고를 수 있으므로 100%가 된다</label>
  <label><input type="radio" name="prediction-07" value="1" /> 진폭 차이와 이웃의 변화 때문에 효율이 줄 수 있다</label>
</fieldset>

<details>
  <summary>예측의 근거 확인하기</summary>

  <p>두 번째입니다. 위상을 네 단계로 근사하는 것만으로도 이상적 모델의 효율은 약 0.811입니다. 실제 막대의 진폭은 같지 않고, 단위 셀에서 가정했던 동일한 이웃도 실제 배열에서는 달라집니다. 따라서 2π 커버는 필요한 설계 조건이지 100% 효율 보장이 아닙니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기 · 관찰을 설명하는 방법</h2>

<!-- concept-illustration:part-07:start -->

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/07/00_concept.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/00_concept.png" alt="같은 높이의 Si 막대 폭을 바꿔 목표 상대위상을 선택하고 네 막대를 주기적으로 배열해 위쪽 오른쪽 +1차로 빛을 보내는 개념이다." loading="lazy" />
  </a>
  <figcaption>Si(n = 3.45) 막대가 SiO₂(n = 1.45) 기판 위에 놓이고 빛은 기판 안에서 +y 방향으로 입사합니다. 막대 높이는 0.9 µm이며 폭 75·100·175·225 nm를 선택해 네 단계의 상대위상을 근사합니다. 네 구간의 주기 1.8 µm를 x 방향으로 반복하며 목표 +1차는 +y 법선에서 오른쪽으로 약 59.4°입니다. 0·90·180·270°는 정확한 측정값이 아닌 목표 상대위상입니다. 입체 음영은 구조 이해를 위한 표현이고, 실제 2D 막대는 z 방향으로 무한합니다.</figcaption>
</figure>

<!-- concept-illustration:part-07:end -->

<h3 id="폭을-위상으로-바꾸는-표가-phase-library다">폭을 위상으로 바꾸는 표가 phase library다</h3>

<p>주기 0.45 µm의 단위 셀은 1550 nm에서 0차만 전파합니다. 한 주기 위의 복소 DFT 필드를 평균하고 막대 없는 셀로 나누면 복소 투과계수 t(w)를 얻습니다. 그 크기는 진폭, 위각은 위상입니다. 폭을 바꾸며 두 값을 기록한 표가 library입니다.</p>

\[t(w)=\frac{\langle E_z\rangle(w)}{\langle E_z\rangle(0)}\]

<p>위상은 <code class="language-plaintext highlighter-rouge">np.unwrap</code>으로 이어 읽지만, 표본 사이의 실제 변화가 너무 크면 제대로 복원할 수 없습니다. 진폭이 크게 떨어지는 폭도 함께 확인해야 합니다. 여기의 t는 <strong>막대 없는 기준 셀 대비 필드 비율</strong>이므로 그 크기 자체를 입사 power 대비 효율로 읽지 않습니다.</p>

<h3 id="네-개의-폭으로-기울어진-파면을-만든다">네 개의 폭으로 기울어진 파면을 만든다</h3>

<p>네 구획의 목표 상대위상은 0°, 90°, 180°, 270°입니다. 시작 위상 φ₀를 함께 이동해도 위상 기울기는 같으므로 목표 각도는 유지됩니다. 이 자유도로 진폭이 너무 작은 폭을 피합니다.</p>

\[\Lambda=4\times0.45=1.8\;\mu\mathrm{m},\qquad \sin\theta_{+1}=1.55/1.8\]

<p>목표 각도는 +y 법선에서 오른쪽으로 59.4°입니다. 실제 선택 폭은 75, 100, 175, 225 nm입니다. 각 막대를 고를 때의 library는 <strong>같은 폭의 이웃이 무한히 반복되는 조건</strong>이며, 서로 다른 폭을 이웃으로 놓는 순간 그 근사가 검증 대상이 됩니다.</p>

<aside class="lesson-note">
  <p><strong>개념도의 네 위상은 목표값입니다.</strong> 정확한 측정 위상과 혼동하지 마세요. 이 계산은 2D Ez, 수직 입사, 손실 없는 Si(3.45)·SiO₂(1.45)입니다. z 방향으로 무한한 막대의 결과를 실제 3D metalens 성능으로 바로 읽을 수 없습니다.</p>
</aside>

<details>
  <summary>기호·설계 가정과 예측표 자세히 보기</summary>

  <p>주기 Λ_a = 0.45 µm(파장의 0.29배)의 unit cell에 든 Si 막대는 회절하지 않는다. 0차만 전파하므로 unit cell 전체가 복소 투과계수 t(w) 하나로 요약된다. 막대가 넓을수록 유효 굴절률이 커져 위상이 더 쌓인다. 높이 H = 0.9 µm, Δn ≈ 2.45로 어림 Δn·H/λ = 1.4바퀴이니 한 바퀴는 넘길 수 있다.</p>

  <p>+1차로 꺾으려면 투과 위상이 x에 비례해 φ(x) = 2πx/Λ여야 한다. Λ = 4Λ_a = 1.8 µm로 두고 네 구획에 0°, 90°, 180°, 270°를 주면 계단식 근사가 된다. N단계로 이산화한 blazed 격자의 +1차 효율 상한은 sinc²(1/N)이고 N = 4면 0.81이다. 그 위에 두 가지 손실이 더 얹힌다. |t|가 균일하지 않은 것, 그리고 library가 “이웃이 모두 나와 같다”는 주기 가정에서 나온 값이라 폭이 다른 이웃 옆에서는 틀린다는 것.</p>

\[t(w)=\frac{\langle E_z\rangle_{\text{period}}(w)}{\langle E_z\rangle_{\text{period}}(0)},\qquad
\phi_{\text{target}}(x)=\frac{2\pi x}{\Lambda},\qquad
\sin\theta_{+1}=\frac{\lambda}{\Lambda}=\frac{1.55}{1.8}\Rightarrow 59.4^\circ,\qquad
\eta_{+1}\le\mathrm{sinc}^2\!\Big(\frac1N\Big)=0.811\]

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Λ_a, Λ</td>
        <td>atom 주기 0.45, supercell 주기 1.8 µm</td>
        <td><code class="language-plaintext highlighter-rouge">LA</code>, <code class="language-plaintext highlighter-rouge">LAMBDA</code></td>
      </tr>
      <tr>
        <td>w, H</td>
        <td>막대 폭(설계 변수), 높이 0.9 µm</td>
        <td><code class="language-plaintext highlighter-rouge">widths</code>, <code class="language-plaintext highlighter-rouge">H</code></td>
      </tr>
      <tr>
        <td>t(w)</td>
        <td>빈 셀로 정규화한 0차 복소 투과</td>
        <td><code class="language-plaintext highlighter-rouge">t_atom(w) / t_atom(0)</code></td>
      </tr>
      <tr>
        <td>φ₀</td>
        <td>네 목표 위상의 시작점(전역 위상)</td>
        <td><code class="language-plaintext highlighter-rouge">phi0</code></td>
      </tr>
      <tr>
        <td>w_lib</td>
        <td>선택된 네 폭(픽셀 정렬)</td>
        <td><code class="language-plaintext highlighter-rouge">w_lib</code></td>
      </tr>
      <tr>
        <td>η_m</td>
        <td>m차 효율 (입사 flux 대비)</td>
        <td><code class="language-plaintext highlighter-rouge">orders[m]["eff"]</code></td>
      </tr>
      <tr>
        <td>θ_d</td>
        <td>설계 편향각 59.44°</td>
        <td><code class="language-plaintext highlighter-rouge">THETA_D</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 2D, Ez 편광, 수직 입사, 손실 없는 Si(3.45)·SiO₂(1.45). library는 res 40에서 만들고 res 60과 비교한다. far field는 2D 선 초점의 각도 분포다.</p>

  <h3 id="section">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
        <th> </th>
        <th> </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>위상 span (H 0.9, Si)</td>
        <td>1바퀴 이상</td>
        <td>Δn·H/λ = 1.4의 70~80% (06편 경험)</td>
        <td> </td>
        <td> </td>
      </tr>
      <tr>
        <td>위상의 단조성</td>
        <td>w에 대해 단조 증가</td>
        <td>넓을수록 유효 굴절률 증가</td>
        <td> </td>
        <td> </td>
      </tr>
      <tr>
        <td>|t|</td>
        <td>넓은 w에서 떨어짐</td>
        <td>막대 공명·반사</td>
        <td> </td>
        <td> </td>
      </tr>
      <tr>
        <td>+1차 효율</td>
        <td>0.81 미만, 0.5~0.7</td>
        <td>4단계 상한 ×</td>
        <td>t</td>
        <td>불균일 × 이웃 결합</td>
      </tr>
      <tr>
        <td>−1차와 0차</td>
        <td>0은 아님, 합쳐 0.1~0.2</td>
        <td>계단 근사의 누설</td>
        <td> </td>
        <td> </td>
      </tr>
      <tr>
        <td>40-atom 빔 방향</td>
        <td>59° 근처, 10-atom은 더 벗어남</td>
        <td>개구가 짧으면 빔폭이 커지고 피크가 밀린다</td>
        <td> </td>
        <td> </td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: 차수 합이 총 투과 flux와 1%p 이상 다르면 분해 오류. 위상 unwrap에서 인접 차가 π를 넘으면 표본 부족.</p>

</details>

<h2 id="run">4. 직접 실행 · 변수 하나만 바꾸기</h2>

<h3 id="한-번만-바꿔보기-설계-해상도">한 번만 바꿔보기: 설계 해상도</h3>

<ol>
  <li><code class="language-plaintext highlighter-rouge">meta_atom.py</code>와 <code class="language-plaintext highlighter-rouge">blogfig.py</code>가 있는 <code class="language-plaintext highlighter-rouge">code/</code> 폴더에서 <code class="language-plaintext highlighter-rouge">python meta_atom.py</code>를 실행합니다. 기준 <code class="language-plaintext highlighter-rouge">result.json</code>의 선택 폭 네 개와 +1차 효율을 보관합니다.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">RES = 40</code>을 <code class="language-plaintext highlighter-rouge">RES = 60</code>으로만</strong> 바꾸고 다시 실행합니다. 폭 표본 17개 전체와 다른 구조·파라미터는 유지합니다.</li>
  <li>새 library에서 고른 폭과 supercell의 +1차 효율을 원본과 비교합니다. 두 경우 모두 차수 합이 총 투과 flux와 맞는지도 확인합니다.</li>
</ol>

<p>원본에는 해상도 60의 library 비교가 있지만, 그 library로 <strong>다시 설계한 배열의 효율은 기록되어 있지 않습니다</strong>. 그 값을 새 실험에서 구합니다. 일부 폭만 재계산하면 unwrap의 branch가 달라질 수 있으므로 표본 전체를 사용합니다.</p>

<details>
  <summary>계산 배치·광원·파라미터 보기</summary>

  <figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/07/01_layout.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/01_layout.png" alt="Si 막대 네 개와 SiO2 기판, 광원, mode monitor 및 y 방향 PML 배치" loading="lazy" />
  </a>
  <figcaption>supercell(실험 C). 아래 검은 띠 = SiO₂ 기판(아래 PML 관통), 검은 막대 넷 = 설계된 Si meta-atom, 빨간 가로선 = 기판 안의 평면파 source, 파란 가로선 = 차수를 재는 mode monitor, 녹색 빗금 = y 방향 PML. x는 주기 경계. 보라 × = 종료 감시점. 동그라미 숫자는 §4의 단계 번호다. unit cell(실험 A)은 이 셀의 1/4 폭에 막대 하나다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Λ_a</td>
        <td>0.45 µm</td>
        <td>res 40에서 정확히 18 px. 픽셀 정수가 아니면 Meep이 셀을 반올림해 실제 주기와 k_x = m/Λ가 어긋난다</td>
        <td>θ_d가 따라 바뀐다</td>
      </tr>
      <tr>
        <td>Λ = 4Λ_a, θ_d</td>
        <td>1.8 µm, 59.44°</td>
        <td>θ_d를 먼저 정하지 않고 주기를 픽셀 정수로 고정한 뒤 각도가 따라오게</td>
        <td>—</td>
      </tr>
      <tr>
        <td>H</td>
        <td>0.9 µm</td>
        <td>2π를 넘기는 최소 높이 근처</td>
        <td>낮추면 span &lt; 2π</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">widths</code></td>
        <td>0.04–0.42, 17점</td>
        <td>unwrap 조건(인접 차 &lt; π)을 만족하는 밀도</td>
        <td>성기면 unwrap이 2π 틀린다</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">RES</code></td>
        <td>40 (수렴성 60)</td>
        <td>폭 0.075 µm 막대가 3 px</td>
        <td>60에서 위상이 최대 0.82 rad 바뀐다(§5)</td>
      </tr>
      <tr>
        <td>종료</td>
        <td>monitor 점 Ez 1e-7 감쇠</td>
        <td>좁은 대역(fwidth 0.1 fcen) 펄스 꼬리</td>
        <td>고정 시간이면 폭마다 다르게 틀린다</td>
      </tr>
      <tr>
        <td>far field</td>
        <td>R = 200 µm, 341각, source는 배열 폭만</td>
        <td>배열 옆 빈 구간의 빛이 0° 인공물이 되지 않게</td>
        <td>셀 전체 폭 source면 0°가 과대</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/07/00_source.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/00_source.png" alt="메타원자 실험의 가우시안 광원 시간 파형과 좁은 대역 스펙트럼" loading="lazy" />
  </a>
  <figcaption>source 파형과 스펙트럼. fwidth 0.1 fcen, width 15.5, t0 = 77.5.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 없다. 파라미터·절차·수치 모두 강의 week 8과 같다(위상 span 1.101 × 2π, 설계 폭 네 개, +1차 0.514). 이 글은 거기에 10_sources의 공식 metasurface_lens 재현에서 얻은 두 가지 주의(wrapped phase를 그대로 불연속으로 읽지 말 것, 목표 위상을 library와 같은 2π branch에 둘 것)를 §4·§6에 덧붙였다.</p>

</details>

<details>
  <summary>코드 단계별 설명 보기</summary>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
전파 방향이 +y라서 06편과 x·y가 바뀐다. 실험 A(library)는 unit cell, C(supercell)는 네 배 넓은 셀, D(far field)는 PML 전면의 유한 셀이다.</p>
  </blockquote>

  <h3 id="section-1">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">wl</span> <span class="o">=</span> <span class="mf">1.55</span><span class="p">;</span> <span class="n">fcen</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">wl</span><span class="p">;</span> <span class="n">fwidth</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">Si</span><span class="p">,</span> <span class="n">SiO2</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">3.45</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">1.45</span><span class="p">)</span>
<span class="n">N_SEC</span> <span class="o">=</span> <span class="mi">4</span>                       <span class="c1"># phase levels per supercell period
</span><span class="n">LA</span> <span class="o">=</span> <span class="mf">0.45</span>                       <span class="c1"># atom period [um]: 18 px at resolution 40
</span><span class="n">LAMBDA</span> <span class="o">=</span> <span class="n">N_SEC</span> <span class="o">*</span> <span class="n">LA</span>             <span class="c1"># supercell period 1.80 um
</span><span class="n">THETA_D</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">wl</span> <span class="o">/</span> <span class="n">LAMBDA</span><span class="p">))</span>   <span class="c1"># 59.44 deg
</span><span class="n">H</span> <span class="o">=</span> <span class="mf">0.9</span>                         <span class="c1"># bar height [um]
</span><span class="n">RES</span> <span class="o">=</span> <span class="mi">40</span>
<span class="n">DPML</span><span class="p">,</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">DAIR</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span>
<span class="n">SY</span> <span class="o">=</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="n">DAIR</span> <span class="o">+</span> <span class="n">DPML</span>
<span class="n">Y_BOT</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SY</span><span class="p">;</span> <span class="n">Y_DEV</span> <span class="o">=</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">;</span> <span class="n">SRC_Y</span> <span class="o">=</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.3</span><span class="p">;</span> <span class="n">MON_Y</span> <span class="o">=</span> <span class="o">-</span><span class="n">Y_BOT</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.3</span>
<span class="n">BLAZED_BOUND</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">))</span> <span class="o">**</span> <span class="mi">2</span>   <span class="c1"># 0.8106
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: atom 주기를 픽셀 정수로 먼저 고정하고, supercell 주기와 편향각을 거기서 유도한다. blazed 상한도 여기서 계산해 둔다.</li>
    <li><strong>왜</strong>: θ_d = 60°로 잡으면 Λ = 1.7898 µm로 픽셀 정수가 아니다. Meep이 셀을 반올림하면 “주기”와 차수 계산 k_x = m/Λ가 어긋난다. 숫자를 먼저 고정하고 각도가 따라오게 하면 이 문제가 없다.</li>
    <li><strong>틀리면</strong>: 셀 반올림 경고가 뜨고 ±1차의 각도·효율이 미세하게 틀린다. 06편에서 1.2 µm 주기가 res 22에서 반올림된 것도 같은 문제였다.</li>
  </ul>

  <h3 id="section-2">② 재료와 구조 — 무엇이 어디에 있는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">geometry_bars</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">period</span><span class="p">):</span>
    <span class="n">g</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">)]</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">widths</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">w</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">widths</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">w</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">period</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">period</span> <span class="o">/</span> <span class="n">n</span>
            <span class="n">g</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xj</span><span class="p">,</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">H</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">g</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 기판 위에 구획마다 Si 막대 하나. <code class="language-plaintext highlighter-rouge">widths=[w]</code>면 unit cell, <code class="language-plaintext highlighter-rouge">widths=w_lib</code>면 4구획 supercell이다.</li>
    <li><strong>왜</strong>: library와 supercell이 같은 함수로 만들어져야 “library 값을 그대로 썼는데 왜 다른가”를 물을 수 있다. w = 0은 막대 없는 reference다.</li>
    <li><strong>틀리면</strong>: 막대 중심을 구획 중심에 두지 않으면 위상 기울기에 오프셋이 생겨 0차가 커진다.</li>
  </ul>

  <h3 id="source----">③ Source — 빛을 어떻게 넣는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">plane_wave</span><span class="p">(</span><span class="n">period</span><span class="p">,</span> <span class="n">fw</span><span class="o">=</span><span class="n">fwidth</span><span class="p">,</span> <span class="n">integrated</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw</span><span class="p">,</span> <span class="n">is_integrated</span><span class="o">=</span><span class="n">integrated</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                      <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SRC_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">period</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 기판 안에서 셀 폭 전체의 가로선. +y로 가는 평면파.</li>
    <li><strong>왜</strong>: 주기 셀에서는 셀 폭 = 주기라 그 자체로 평면파다. 유한 배열(D)에서만 <code class="language-plaintext highlighter-rouge">is_integrated=True</code>와 “배열 폭만큼”의 선원을 쓴다.</li>
    <li><strong>틀리면</strong>: 유한 배열에서 셀 전체 폭으로 쏘면 배열 옆 빈 기판을 그대로 통과한 빛이 0° 피크로 크게 섞인다.</li>
  </ul>

  <h3 id="simulation-----pml">④ Simulation과 경계 — 계산 상자와 PML</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">periodic_sim</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">period</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">period</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">geometry</span><span class="o">=</span><span class="n">geometry_bars</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">period</span><span class="p">),</span>
                         <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span>
                         <span class="n">sources</span><span class="o">=</span><span class="n">plane_wave</span><span class="p">(</span><span class="n">period</span><span class="p">))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: PML은 y에만, x는 <code class="language-plaintext highlighter-rouge">k_point=0</code>의 주기 경계. 06편과 축만 다르다.</li>
    <li><strong>왜</strong>: unit cell의 t(w)는 “무한 주기 배열 안의 막대”의 값이다. 이 가정이 뒤에서 깨지는 지점을 보게 된다.</li>
    <li><strong>틀리면</strong>: unit cell에 PML을 x에도 두면 고립된 막대 하나의 산란을 계산하게 되고 t(w)의 의미가 달라진다.</li>
  </ul>

  <h3 id="monitor---">⑤ Monitor — 무엇을 재는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># A. unit cell: DFT of Ez on a line across one period; its mean is the zeroth Fourier coefficient
</span><span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LA</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="c1"># C. supercell: a mode monitor across the period, decomposed order by order
</span><span class="n">mon</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
<span class="n">a_m</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mon</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">DiffractedPlanewave</span><span class="p">((</span><span class="n">m</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: unit cell에서는 한 주기 위의 복소 DFT를 평균해 t를 얻고, supercell에서는 06편처럼 차수별 진폭을 얻는다.</li>
    <li><strong>왜</strong>: 주기 함수의 한 주기 평균은 0차 Fourier 계수다. subwavelength 셀에서는 0차만 전파하므로 평균 하나가 투과 전부다. <code class="language-plaintext highlighter-rouge">get_array</code>가 아니라 <code class="language-plaintext highlighter-rouge">get_dft_array</code>인 이유는 마지막 시각의 snapshot이 아니라 정상상태 복소 진폭이 필요하기 때문이다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">get_array</code>로 재면 펄스가 지나간 뒤의 잔재를 평균하게 된다. monitor를 막대 바로 위에 두면 소멸파가 섞인다(여기서는 0.7 µm 위).</li>
  </ul>

  <h3 id="section-3">⑥ 실행과 종료 조건 — 언제 멈추는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="mf">1e-7</span><span class="p">))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: monitor 점의 Ez가 10⁻⁷로 줄 때까지. 34번의 library run 모두 같은 조건.</li>
    <li><strong>왜</strong>: 복소 위상은 진폭보다 꼬리에 민감하다. 임계값을 보통(10⁻⁶)보다 낮게 둔다.</li>
    <li><strong>틀리면</strong>: 폭마다 종료 시각이 달라져도 상관없지만, 고정 시간으로 끊으면 어떤 폭에서는 꼬리가 남아 위상이 틀어진다.</li>
  </ul>

  <h3 id="section-4">⑦ 후처리 — 숫자로 바꾸기</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">t_ref</span> <span class="o">=</span> <span class="n">t_atom</span><span class="p">(</span><span class="mf">0.0</span><span class="p">)</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">t_atom</span><span class="p">(</span><span class="n">w</span><span class="p">)</span> <span class="o">/</span> <span class="n">t_ref</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">widths</span><span class="p">])</span>
<span class="n">phase</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">t</span><span class="p">));</span> <span class="n">phase</span> <span class="o">-=</span> <span class="n">phase</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>          <span class="c1"># library: |t|, relative phase
</span>
<span class="c1"># design: for each trial phi0, four targets phi0 + k*pi/2 -&gt; widths by inverse interpolation; keep the phi0 with the largest min|t|
</span><span class="n">targets</span> <span class="o">=</span> <span class="n">phi0</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="n">N_SEC</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">)</span>
<span class="n">ws</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">targets</span><span class="p">,</span> <span class="n">ph_dense</span><span class="p">,</span> <span class="n">w_dense</span><span class="p">)</span>
<span class="n">w_lib</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">ws</span> <span class="o">*</span> <span class="n">RES</span><span class="p">)</span> <span class="o">/</span> <span class="n">RES</span>                            <span class="c1"># snap to the pixel grid
</span>
<span class="n">eff_m</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">a_m</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">P_in</span>                               <span class="c1"># supercell: efficiency per order, P_in from an all-SiO2 run
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 빈 셀로 나눈 t의 위상을 unwrap해 library를 만들고, 목표 위상에서 폭을 역으로 읽으며, 전역 위상 φ₀를 골라 min|t|를 키운다. 폭은 픽셀에 맞춘다.</li>
    <li><strong>왜</strong>: <code class="language-plaintext highlighter-rouge">np.angle</code>은 (−π, π]의 wrapped 값이다. 10_sources의 phase map 노트가 경고하듯, 거기서 보이는 급변은 물리적 불연속이 아니라 branch cut일 수 있다. unwrap은 인접 표본의 차가 π보다 작을 때만 옳으므로 폭을 촘촘히 잡았다. library의 위상은 상대값이라 상수를 더해도 되고, 그 자유도가 |t| 균일성을 사는 데 쓰인다.</li>
    <li><strong>틀리면</strong>: 목표 위상을 library와 다른 2π branch에 두고 clip하면 네 폭이 모두 library 최솟값으로 몰린다(10_sources 실패 사례). 픽셀 정렬을 빼면 supercell 막대 폭이 library와 다른 값으로 반올림된다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: 성긴 폭 부분집합만 다시 돌려 수렴성을 보면 unwrap이 어긋나 2π만큼 틀린다. 수렴성 비교는 같은 폭 격자 전체로 library를 다시 만든 뒤 한다(§5).</p>
  </blockquote>

</details>

<h2 id="interpret">5. 해석 · 측정값과 한계를 함께 읽기</h2>

<h3 id="위상-한-바퀴와-효율-100는-다르다">위상 한 바퀴와 효율 100%는 다르다</h3>

<p>원본 library는 위상 <strong>1.101 × 2π</strong>를 덮고, 진폭 범위는 0.689–1.011입니다. 선택 폭의 진폭은 1.001, 0.959, 0.885, 0.885로 균일하지 않습니다.</p>

<table>
  <thead>
    <tr>
      <th>실제 supercell의 차수</th>
      <th>각도</th>
      <th>입사 flux 대비 효율</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>−1</td>
      <td>−59.4°</td>
      <td>0.1576</td>
    </tr>
    <tr>
      <td>0</td>
      <td>0°</td>
      <td>0.0325</td>
    </tr>
    <tr>
      <td>+1</td>
      <td>+59.4°</td>
      <td>0.5144</td>
    </tr>
  </tbody>
</table>

<p>합 0.7045는 전체 투과 flux와 일치합니다. 목표 차수의 0.5144는 이상적 4단계 모델 0.8106의 63.5%입니다. 이 차이를 진폭 불균일과 이웃 결합으로 <strong>각각 얼마씩 나눌지는 이 실험만으로 알 수 없습니다</strong>.</p>

<p>유한 배열에서는 개구도 중요합니다. 10개 막대(4.5 µm)의 피크는 49.5°, 40개(18 µm)는 58.5°입니다. 넓은 배열의 빔이 더 좁아지면서 목표 59.4°에 가까워집니다.</p>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/07/02_library.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/02_library.png" alt="막대 폭에 따른 투과 진폭, 상대 위상 및 해상도 40과 60의 위상 차" loading="lazy" />
  </a>
  <figcaption>왼쪽 &#124;t&#124;, 가운데 위상(w = 0.04 기준, 2π 단위), 오른쪽 해상도 40 → 60의 위상 차. 위상은 단조 증가하며 1.10바퀴를 돈다. &#124;t&#124;는 w ≈ 0.13과 0.3 근처에서 0.7까지 떨어진다. 해상도 차는 w = 0.087에서 0.49 rad, 0.42에서 0.39 rad로, 설계 간격 π/2의 10%(초록 띠)를 여러 점에서 넘는다.</figcaption>
</figure>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/07/03_design.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/03_design.png" alt="네 목표 위상에서 선택한 막대 폭, 각 폭의 투과 진폭과 supercell 구조" loading="lazy" />
  </a>
  <figcaption>왼쪽: 네 목표 위상(φ₀ + 0°, 90°, 180°, 270°)에서 읽은 폭. 가운데: 그 폭의 &#124;t&#124;. 오른쪽: 만들어지는 supercell 한 주기.</figcaption>
</figure>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/07/05_farfield.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/07/05_farfield.png" alt="10개와 40개 막대 배열의 원거리 각도 분포와 설계각 59.4도 비교" loading="lazy" />
  </a>
  <figcaption>library 폭을 반복한 10-atom(4.5 µm)과 40-atom(18 µm) 배열의 far field. 회색 점선이 설계각 59.4°.</figcaption>
</figure>

<aside class="lesson-note">
  <p><strong>해상도 40의 설계가 수렴한 것은 아닙니다.</strong> 40→60에서 위상 범위는 1.101→1.163 × 2π, 최대 위상 차는 약 0.82 rad, 진폭 차는 0.071입니다. 가장 좁은 선택 막대는 3 px에 불과합니다. 효율 0.5144는 해상도 40으로 설계·검증한 값이며, 둘째 자리의 신뢰도나 3D·편광·파장 의존성을 보장하지 않습니다.</p>
</aside>

<details>
  <summary>전체 측정표·예측 비교·수렴성 기록 보기</summary>

  <h3 id="a-phase-library">A. Phase library</h3>

  <table>
    <thead>
      <tr>
        <th>양</th>
        <th>res 40</th>
        <th>res 60</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>위상 span / 2π</td>
        <td>1.101</td>
        <td>1.163</td>
      </tr>
      <tr>
        <td>|t| 범위</td>
        <td>0.689–1.011</td>
        <td>0.690–1.015</td>
      </tr>
      <tr>
        <td>max |Δφ| (60 − 40)</td>
        <td>—</td>
        <td>0.82 rad (2π의 13%)</td>
      </tr>
    </tbody>
  </table>

  <h3 id="b-4-">B. 4단계 설계</h3>

  <table>
    <thead>
      <tr>
        <th>구획</th>
        <th>목표 위상</th>
        <th>w (µm, 픽셀 정렬)</th>
        <th>|t|</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0</td>
        <td>0.797 rad</td>
        <td>0.075</td>
        <td>1.001</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2.368</td>
        <td>0.100</td>
        <td>0.959</td>
      </tr>
      <tr>
        <td>2</td>
        <td>3.938</td>
        <td>0.175</td>
        <td>0.885</td>
      </tr>
      <tr>
        <td>3</td>
        <td>5.509</td>
        <td>0.225</td>
        <td>0.885</td>
      </tr>
    </tbody>
  </table>

  <p>φ₀ = 0.797 rad가 min|t| = 0.885를 준다. 네 폭 중 셋이 0.1 µm 아래이거나 근처라 res 40에서 3~4 px다.</p>

  <h3 id="c-supercell---">C. Supercell: 빛은 어디로 가는가</h3>

  <table>
    <thead>
      <tr>
        <th>차수</th>
        <th>각도</th>
        <th>효율</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>−1</td>
        <td>−59.4°</td>
        <td>0.158</td>
      </tr>
      <tr>
        <td>0</td>
        <td>0°</td>
        <td>0.033</td>
      </tr>
      <tr>
        <td>+1</td>
        <td>+59.4°</td>
        <td>0.514</td>
      </tr>
      <tr>
        <td>합</td>
        <td> </td>
        <td>0.705 = 총 투과 flux 0.705</td>
      </tr>
    </tbody>
  </table>

  <p>+1차 0.514는 상한 0.811의 63.5%다. 나머지는 −1차(0.158)와 0차(0.033), 그리고 반사(1 − 0.705 = 0.295)로 갔다.</p>

  <h3 id="d---far-field">D. 유한 배열의 far field</h3>

  <table>
    <thead>
      <tr>
        <th>배열</th>
        <th>개구</th>
        <th>주 lobe</th>
        <th>어림 빔폭 λ/(D cos θ)</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>10 atom</td>
        <td>4.5 µm</td>
        <td>+49.5°</td>
        <td>38.8°</td>
      </tr>
      <tr>
        <td>40 atom</td>
        <td>18 µm</td>
        <td>+58.5°</td>
        <td>9.7°</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-5">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>위상 span</td>
        <td>1바퀴 이상</td>
        <td>1.10 × 2π</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>단조성</td>
        <td>단조 증가</td>
        <td>17점 모두 증가</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>|t|</td>
        <td>넓은 w에서 하락</td>
        <td>0.13·0.30 근처 0.69~0.71</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>+1차 효율</td>
        <td>0.5~0.7</td>
        <td>0.514</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>−1 + 0차</td>
        <td>0.1~0.2</td>
        <td>0.191</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>빔 방향</td>
        <td>40 atom ≈ 59°, 10 atom은 벗어남</td>
        <td>58.5°, 49.5°</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>예측은 맞았지만 상한 대비 63.5%의 손실을 어디에 돌릴지는 숫자가 말해 준다. |t|의 불균일은 0.885² ≈ 0.78 정도의 몫이다. 그 밖의 손실이 “이웃이 같다”는 주기 가정에서 온다. library의 각 폭은 좌우에 같은 폭의 막대가 있을 때의 값인데, supercell에서는 0.075 옆에 0.100, 0.175 옆에 0.225가 있다. 폭이 가장 급히 바뀌는 구획 3 → 0 경계(0.225 → 0.075)에서 위상 오차가 가장 크다. 08편의 inverse design은 이 간극을 네 폭이 아니라 픽셀 단위 자유도로 메운다.</p>

  <h3 id="section-6">수렴성</h3>

  <table>
    <thead>
      <tr>
        <th>양</th>
        <th>res 40</th>
        <th>res 60</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>위상 span / 2π</td>
        <td>1.101</td>
        <td>1.163</td>
        <td>6%</td>
      </tr>
      <tr>
        <td>max |Δφ|</td>
        <td>—</td>
        <td>0.82 rad</td>
        <td>w = 0.087, 0.42에서 최대</td>
      </tr>
      <tr>
        <td>max Δ|t|</td>
        <td>—</td>
        <td>0.071</td>
        <td> </td>
      </tr>
    </tbody>
  </table>

  <p>위상이 해상도에 13%(2π 기준)까지 움직인다. 설계 간격 π/2의 절반이다. 가장 좁은 막대(3 px)가 원인이고, 설계에 쓸 폭 구간의 오차를 따로 봐야 한다. 이 글의 supercell 수치(0.514)는 res 40 library로 설계하고 res 40으로 검증한 값이라 자기일관적이지만, res 60으로 다시 설계하면 폭과 효율이 달라질 것이다.</p>

  <h3 id="section-7">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: Si 막대(H 0.9, 주기 0.45)의 library는 1550 nm에서 2π를 덮는다. 4단계 설계 supercell은 +1차에 51%를 보내고, 유한 배열은 설계각 근처로 빔을 만든다. 차수 합과 총 flux가 일치해 분해는 옳다.</li>
    <li>할 수 없는 것: 효율 0.514의 둘째 자리. res 60으로 library를 다시 만들면 폭이 바뀐다. 3D·편광·파장 의존성. “국소 위상 근사 때문”이라는 손실 배분의 정량적 분해(두 손실을 따로 끄는 실험은 하지 않았다).</li>
  </ul>

</details>

<details>
  <summary>증상별 점검표 보기</summary>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>위상 곡선에 2π 점프</td>
        <td>unwrap 실패(표본 성김) 또는 부분집합 재계산</td>
        <td>폭 간격을 줄이고 전체 격자로 다시 만들기</td>
      </tr>
      <tr>
        <td>네 폭이 모두 같은 값으로 몰림</td>
        <td>목표 위상이 library와 다른 2π branch에서 clip</td>
        <td><code class="language-plaintext highlighter-rouge">target_on_map = (target − φ_min) mod 2π + φ_min</code></td>
      </tr>
      <tr>
        <td>셀 반올림 경고, 각도가 미세하게 틀림</td>
        <td>주기가 픽셀 정수가 아님</td>
        <td>주기를 먼저 픽셀 정수로, 각도는 따라오게</td>
      </tr>
      <tr>
        <td>far field 0°에 큰 피크</td>
        <td>유한 배열 source가 셀 전체 폭</td>
        <td>배열 폭만큼만, <code class="language-plaintext highlighter-rouge">is_integrated=True</code></td>
      </tr>
      <tr>
        <td>차수 합 ≠ 총 flux</td>
        <td>소멸 차수 포함 또는 monitor가 막대에 근접</td>
        <td>|k_x| &lt; k₀인 차수만, monitor를 띄우기</td>
      </tr>
      <tr>
        <td>t(w)가 실행마다 다름</td>
        <td><code class="language-plaintext highlighter-rouge">get_array</code> snapshot 사용</td>
        <td><code class="language-plaintext highlighter-rouge">add_dft_fields</code> + <code class="language-plaintext highlighter-rouge">get_dft_array</code></td>
      </tr>
    </tbody>
  </table>

</details>

<h2 id="check">6. 확인 · 두 질문에 답해보기</h2>

<h3 id="1-전역-위상-φ를-바꾸면-폭-네-개가-달라져도-목표-각도는-왜-같을까요">1. 전역 위상 φ₀를 바꾸면 폭 네 개가 달라져도 목표 각도는 왜 같을까요?</h3>

<details>
  <summary>설명 확인하기</summary>

  <p>모든 목표 위상에 같은 상수를 더해도 위치에 따른 위상 기울기는 같습니다. 방향은 기울기가 정합니다. 다만 선택 폭과 진폭, 실제 이웃 결합이 달라져 실제 효율은 달라질 수 있습니다.</p>

</details>

<h3 id="2-library의-2π-커버와-차수-합--flux가-모두-맞으면-소자-설계가-끝난-것일까요">2. library의 2π 커버와 차수 합 = flux가 모두 맞으면 소자 설계가 끝난 것일까요?</h3>

<details>
  <summary>설명 확인하기</summary>

  <p>아닙니다. 전자는 목표 위상을 고를 수 있는지, 후자는 차수 분해가 전체 투과와 맞는지를 확인합니다. 실제 목표 차수 효율, 해상도 수렴성, 유한 개구와 적용할 3D 조건은 별도로 검증해야 합니다.</p>

</details>

<h2 id="reference">7. 참고 · 전체 코드와 원본 기록</h2>

<p>아래 전체 프로그램은 원본 그대로입니다. 실행 환경과 결과 기록을 함께 확인하세요.</p>

<details>
<summary>meta_atom.py (클릭해서 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 07 - Meta-atoms and a phase library.

Local view of a periodic structure: each Si bar (width w, height H) in a subwavelength unit cell
transmits a plane wave with its own complex coefficient t(w). Collect t(w) -&gt; phase library, pick
4 widths that step the phase by 90 deg, tile them into a supercell that should deflect light to +1,
and check how far the real device falls short of the 4-level blazed bound. Then a finite array and
its far field, and a GIF of the tilted wavefront.

  A. phase library: |t(w)|, arg t(w) at resolution 40 and 60 (reference = empty unit cell)
  B. 4-level design: phase targets phi0 + k*pi/2 -&gt; widths; phi0 chosen to maximise min |t|
  C. supercell (period 4*La): orders by DiffractedPlanewave, sum = total flux, vs sinc^2(1/4) = 0.8106
  D. finite arrays (10 and 40 atoms): near2far pattern, main lobe vs the design angle
  E. GIF: 12-atom array, the wavefront leaves tilted

Run:  python meta_atom.py             (~4 min on one core)
Out:  00_source.png, 01_layout.png, 02_library.png, 03_design.png, 04_supercell.png,
      05_farfield.png, 06_anim_array.gif, result.json   (-&gt; ../assets/07/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)),</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"07"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>

<span class="c1"># ---------------------------------------------------------------- (1) units &amp; parameters
</span><span class="n">wl</span> <span class="o">=</span> <span class="mf">1.55</span>
<span class="n">fcen</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">wl</span>
<span class="n">fwidth</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">Si</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">3.45</span><span class="p">)</span>
<span class="n">SiO2</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">1.45</span><span class="p">)</span>
<span class="n">N_SEC</span> <span class="o">=</span> <span class="mi">4</span>                       <span class="c1"># phase levels per supercell period
</span><span class="n">LA</span> <span class="o">=</span> <span class="mf">0.45</span>                       <span class="c1"># atom period [um]: 18 px at resolution 40 (integer pixels matter: see post)
</span><span class="n">LAMBDA</span> <span class="o">=</span> <span class="n">N_SEC</span> <span class="o">*</span> <span class="n">LA</span>             <span class="c1"># supercell period 1.80 um
</span><span class="n">THETA_D</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">wl</span> <span class="o">/</span> <span class="n">LAMBDA</span><span class="p">)))</span>   <span class="c1"># +1 order angle: 59.44 deg
</span><span class="n">H</span> <span class="o">=</span> <span class="mf">0.9</span>                         <span class="c1"># bar height [um]
</span><span class="n">RES</span> <span class="o">=</span> <span class="mi">40</span>
<span class="n">DPML</span><span class="p">,</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">DAIR</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span>
<span class="n">SY</span> <span class="o">=</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="n">DAIR</span> <span class="o">+</span> <span class="n">DPML</span>
<span class="n">Y_BOT</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SY</span>
<span class="n">Y_DEV</span> <span class="o">=</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span>     <span class="c1"># substrate top = bar bottom
</span><span class="n">SRC_Y</span> <span class="o">=</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.3</span>      <span class="c1"># source inside the substrate
</span><span class="n">MON_Y</span> <span class="o">=</span> <span class="o">-</span><span class="n">Y_BOT</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.3</span>     <span class="c1"># monitor in the air above the bars
</span><span class="n">BLAZED_BOUND</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">))</span> <span class="o">**</span> <span class="mi">2</span>   <span class="c1"># 4-level phase quantisation limit
</span>

<span class="c1"># ---------------------------------------------------------------- (2) geometry: substrate + Si bars
</span><span class="k">def</span> <span class="nf">geometry_bars</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">period</span><span class="p">):</span>
    <span class="s">"""SiO2 substrate through the bottom PML plus one Si bar per section (bar j centred in section j)."""</span>
    <span class="n">g</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">)]</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">widths</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">w</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">widths</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">w</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">period</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">period</span> <span class="o">/</span> <span class="n">n</span>
            <span class="n">g</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xj</span><span class="p">,</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">H</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">g</span>


<span class="c1"># ---------------------------------------------------------------- (3) source: plane wave in the substrate, travelling +y
</span><span class="k">def</span> <span class="nf">plane_wave</span><span class="p">(</span><span class="n">period</span><span class="p">,</span> <span class="n">fw</span><span class="o">=</span><span class="n">fwidth</span><span class="p">,</span> <span class="n">integrated</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw</span><span class="p">,</span> <span class="n">is_integrated</span><span class="o">=</span><span class="n">integrated</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                      <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SRC_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">period</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>


<span class="c1"># ---------------------------------------------------------------- (4) periodic cell: PML in y only, Bloch-periodic in x (k = 0)
</span><span class="k">def</span> <span class="nf">periodic_sim</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">period</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">period</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">geometry</span><span class="o">=</span><span class="n">geometry_bars</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">period</span><span class="p">),</span>
                         <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span>
                         <span class="n">sources</span><span class="o">=</span><span class="n">plane_wave</span><span class="p">(</span><span class="n">period</span><span class="p">))</span>


<span class="c1"># ================================================================ A. phase library
</span><span class="k">def</span> <span class="nf">t_atom</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">):</span>
    <span class="s">"""Zeroth-order complex transmission of one unit cell: the DFT of Ez on the monitor line averaged
    over one period (the average over a period IS the zeroth Fourier coefficient). w = 0 -&gt; reference."""</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">periodic_sim</span><span class="p">([</span><span class="n">w</span><span class="p">],</span> <span class="n">LA</span><span class="p">,</span> <span class="n">resolution</span><span class="p">)</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LA</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>   <span class="c1"># (5)
</span>    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="mf">1e-7</span><span class="p">))</span>      <span class="c1"># (6)
</span>    <span class="n">t</span> <span class="o">=</span> <span class="nb">complex</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>                                                 <span class="c1"># (7)
</span>    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">t</span>


<span class="k">def</span> <span class="nf">build_library</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">):</span>
    <span class="n">t_ref</span> <span class="o">=</span> <span class="n">t_atom</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">resolution</span><span class="p">)</span>
    <span class="n">t</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">t_atom</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">resolution</span><span class="p">)</span> <span class="o">/</span> <span class="n">t_ref</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">widths</span><span class="p">])</span>
    <span class="n">phase</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">t</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">t</span><span class="p">),</span> <span class="n">phase</span> <span class="o">-</span> <span class="n">phase</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>


<span class="n">source_figure</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>
<span class="n">widths</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.04</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">,</span> <span class="mi">17</span><span class="p">)</span>
<span class="n">amp40</span><span class="p">,</span> <span class="n">ph40</span> <span class="o">=</span> <span class="n">build_library</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">RES</span><span class="p">)</span>
<span class="n">amp60</span><span class="p">,</span> <span class="n">ph60</span> <span class="o">=</span> <span class="n">build_library</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span>
<span class="n">span40</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">ph40</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span> <span class="o">-</span> <span class="n">ph40</span><span class="p">.</span><span class="nb">min</span><span class="p">())</span>
<span class="n">dphi</span> <span class="o">=</span> <span class="n">ph60</span> <span class="o">-</span> <span class="n">ph40</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"A. library H=</span><span class="si">{</span><span class="n">H</span><span class="si">}</span><span class="s">: phase span = </span><span class="si">{</span><span class="n">span40</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> rad = </span><span class="si">{</span><span class="n">span40</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> x 2pi; |t| in [</span><span class="si">{</span><span class="n">amp40</span><span class="p">.</span><span class="nb">min</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">, </span><span class="si">{</span><span class="n">amp40</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">]; "</span>
      <span class="sa">f</span><span class="s">"monotonic: </span><span class="si">{</span><span class="nb">bool</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">all</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">ph40</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">))</span><span class="si">}</span><span class="s">; res 60 vs 40: max|dphi| = </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">dphi</span><span class="p">))</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> rad, max d|t| = </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">amp60</span> <span class="o">-</span> <span class="n">amp40</span><span class="p">))</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mf">3.8</span><span class="p">))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">amp40</span><span class="p">,</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"resolution 40"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">amp60</span><span class="p">,</span> <span class="s">"s--"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"resolution 60"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.15</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"bar width w [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"|t|"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"transmission amplitude"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">ph40</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"resolution 40"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">ph60</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="s">"s--"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"resolution 60"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="mf">0.05</span><span class="p">,</span> <span class="mf">1.02</span><span class="p">,</span> <span class="s">"2 pi"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"bar width w [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"phase / 2 pi  (relative to w = 0.04)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"transmission phase: span </span><span class="si">{</span><span class="n">span40</span><span class="o">/</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> x 2pi"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">widths</span><span class="p">,</span> <span class="n">dphi</span><span class="p">,</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">axhspan</span><span class="p">(</span><span class="o">-</span><span class="mf">0.1</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">,</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.15</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"bar width w [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"phase(60) - phase(40) [rad]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"resolution error; green = 10 % of the pi/2 design step"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="sa">f</span><span class="s">"meta-atom phase library: Si bar, H = </span><span class="si">{</span><span class="n">H</span><span class="si">}</span><span class="s"> um, period </span><span class="si">{</span><span class="n">LA</span><span class="si">}</span><span class="s"> um, lambda = 1550 nm"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_library.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ================================================================ B. 4-level design from the library
</span><span class="n">w_dense</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">widths</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">widths</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="mi">2001</span><span class="p">)</span>
<span class="n">ph_dense</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">w_dense</span><span class="p">,</span> <span class="n">widths</span><span class="p">,</span> <span class="n">ph40</span><span class="p">)</span>
<span class="n">amp_dense</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">w_dense</span><span class="p">,</span> <span class="n">widths</span><span class="p">,</span> <span class="n">amp40</span><span class="p">)</span>
<span class="n">best</span> <span class="o">=</span> <span class="bp">None</span>
<span class="k">for</span> <span class="n">phi0</span> <span class="ow">in</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">span40</span> <span class="o">-</span> <span class="mf">1.5</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="mi">400</span><span class="p">):</span>
    <span class="n">targets</span> <span class="o">=</span> <span class="n">phi0</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="n">N_SEC</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">targets</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span> <span class="o">&gt;</span> <span class="n">span40</span><span class="p">:</span>
        <span class="k">continue</span>
    <span class="n">ws</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">targets</span><span class="p">,</span> <span class="n">ph_dense</span><span class="p">,</span> <span class="n">w_dense</span><span class="p">)</span>           <span class="c1"># phase -&gt; width (library is monotonic)
</span>    <span class="n">amps</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">interp</span><span class="p">(</span><span class="n">ws</span><span class="p">,</span> <span class="n">w_dense</span><span class="p">,</span> <span class="n">amp_dense</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">best</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span> <span class="n">amps</span><span class="p">.</span><span class="nb">min</span><span class="p">()</span> <span class="o">&gt;</span> <span class="n">best</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
        <span class="n">best</span> <span class="o">=</span> <span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">amps</span><span class="p">.</span><span class="nb">min</span><span class="p">()),</span> <span class="nb">float</span><span class="p">(</span><span class="n">phi0</span><span class="p">),</span> <span class="n">ws</span><span class="p">,</span> <span class="n">amps</span><span class="p">,</span> <span class="n">targets</span><span class="p">)</span>
<span class="n">min_amp</span><span class="p">,</span> <span class="n">phi0</span><span class="p">,</span> <span class="n">w_sel</span><span class="p">,</span> <span class="n">a_sel</span><span class="p">,</span> <span class="n">targets</span> <span class="o">=</span> <span class="n">best</span>
<span class="n">w_lib</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">w_sel</span> <span class="o">*</span> <span class="n">RES</span><span class="p">)</span> <span class="o">/</span> <span class="n">RES</span>                       <span class="c1"># snap to the pixel grid
</span><span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"B. design: phi0 = </span><span class="si">{</span><span class="n">phi0</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> rad, widths = </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">w_lib</span><span class="p">,</span> <span class="mi">3</span><span class="p">).</span><span class="n">tolist</span><span class="p">()</span><span class="si">}</span><span class="s"> um, |t| = </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">a_sel</span><span class="p">,</span> <span class="mi">3</span><span class="p">).</span><span class="n">tolist</span><span class="p">()</span><span class="si">}</span><span class="s">, min |t| = </span><span class="si">{</span><span class="n">min_amp</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mf">3.8</span><span class="p">))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">w_dense</span><span class="p">,</span> <span class="n">ph_dense</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_SEC</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="n">targets</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">([</span><span class="n">w_sel</span><span class="p">[</span><span class="n">j</span><span class="p">]],</span> <span class="p">[</span><span class="n">targets</span><span class="p">[</span><span class="n">j</span><span class="p">]],</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">annotate</span><span class="p">(</span><span class="sa">f</span><span class="s">"section </span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">targets</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">-</span> <span class="n">targets</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">,</span> <span class="p">(</span><span class="n">w_sel</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">targets</span><span class="p">[</span><span class="n">j</span><span class="p">]),</span> <span class="n">textcoords</span><span class="o">=</span><span class="s">"offset points"</span><span class="p">,</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="o">-</span><span class="mi">11</span><span class="p">),</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"bar width w [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"phase [rad]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"solve phase -&gt; width for 4 targets"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">w_dense</span><span class="p">,</span> <span class="n">amp_dense</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">w_sel</span><span class="p">,</span> <span class="n">a_sel</span><span class="p">,</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="n">min_amp</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"min |t| = </span><span class="si">{</span><span class="n">min_amp</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.15</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"bar width w [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"|t|"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"the price: |t| is not uniform"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_SEC</span><span class="p">):</span>
    <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">LA</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Rectangle</span><span class="p">((</span><span class="n">xj</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">LA</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">LA</span><span class="p">,</span> <span class="n">H</span><span class="p">,</span> <span class="n">facecolor</span><span class="o">=</span><span class="s">"none"</span><span class="p">,</span> <span class="n">edgecolor</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">add_patch</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">Rectangle</span><span class="p">((</span><span class="n">xj</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">w_lib</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="mi">0</span><span class="p">),</span> <span class="n">w_lib</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">H</span><span class="p">,</span> <span class="n">facecolor</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.75</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">xj</span><span class="p">,</span> <span class="n">H</span> <span class="o">*</span> <span class="mf">1.08</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">targets</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">-</span> <span class="n">targets</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> deg</span><span class="se">\n</span><span class="s">w = </span><span class="si">{</span><span class="n">w_lib</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mf">7.5</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_xlim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.55</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="mf">0.55</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.1</span> <span class="o">*</span> <span class="n">H</span><span class="p">,</span> <span class="mf">1.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_aspect</span><span class="p">(</span><span class="s">"equal"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"one supercell period (1.8 um)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"4-level phase design: four widths that step the phase by 90 deg"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_design.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ================================================================ C. supercell: where does the light go?
</span><span class="n">stop_sc</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="mf">1e-7</span><span class="p">)</span>
<span class="n">mon_region</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">default_material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">,</span>     <span class="c1"># reference: all substrate
</span>                    <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">sources</span><span class="o">=</span><span class="n">plane_wave</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">))</span>
<span class="n">fl</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mon_region</span><span class="p">)</span>
<span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_sc</span><span class="p">)</span>
<span class="n">P_in</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">fl</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="n">sim</span> <span class="o">=</span> <span class="n">periodic_sim</span><span class="p">(</span><span class="n">w_lib</span><span class="p">,</span> <span class="n">LAMBDA</span><span class="p">)</span>
<span class="n">mon</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mon_region</span><span class="p">)</span>
<span class="n">annotated_layout</span><span class="p">(</span>
    <span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.2</span><span class="p">,</span> <span class="mf">7.0</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span>
    <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s">"supercell: 4 Si bars on SiO2, period </span><span class="si">{</span><span class="n">LAMBDA</span><span class="si">}</span><span class="s"> um, periodic in x, PML in y"</span><span class="p">,</span>
    <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">wl</span><span class="si">}</span><span class="s"> res=</span><span class="si">{</span><span class="n">RES</span><span class="si">}</span><span class="se">\n</span><span class="s">La=</span><span class="si">{</span><span class="n">LA</span><span class="si">}</span><span class="s"> H=</span><span class="si">{</span><span class="n">H</span><span class="si">}</span><span class="se">\n</span><span class="s">w=</span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="nb">round</span><span class="p">(</span><span class="n">w_lib</span><span class="p">,</span><span class="mi">3</span><span class="p">).</span><span class="n">tolist</span><span class="p">()</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>
    <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="mf">2.35</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">decay_text_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">1.75</span><span class="p">),</span>
    <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"4 Si bars (geometry)"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">LA</span><span class="p">,</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="mf">1.25</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"plane wave in SiO2"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">SRC_Y</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="n">SRC_Y</span> <span class="o">-</span> <span class="mf">0.35</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"mode monitor: orders"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="n">MON_Y</span> <span class="o">+</span> <span class="mf">0.35</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
<span class="n">dft_sc</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">SY</span><span class="p">))</span>
<span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_sc</span><span class="p">)</span>
<span class="n">T_total</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">mon</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">P_in</span><span class="p">)</span>
<span class="n">field_sc</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft_sc</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">eps_sc</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_epsilon</span><span class="p">()</span>
<span class="n">orders</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">):</span>
    <span class="n">kx</span> <span class="o">=</span> <span class="n">m</span> <span class="o">/</span> <span class="n">LAMBDA</span>
    <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">kx</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">fcen</span><span class="p">:</span>
        <span class="k">continue</span>                                                                    <span class="c1"># evanescent
</span>    <span class="n">a</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mon</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">DiffractedPlanewave</span><span class="p">((</span><span class="n">m</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
    <span class="n">orders</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"angle_deg"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">kx</span> <span class="o">/</span> <span class="n">fcen</span><span class="p">))),</span> <span class="s">"eff"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">P_in</span><span class="p">)}</span>
<span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
<span class="n">sum_orders</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">v</span><span class="p">[</span><span class="s">"eff"</span><span class="p">]</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">orders</span><span class="p">.</span><span class="n">values</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="s">"C. supercell orders: "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"m=</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">v</span><span class="p">[</span><span class="s">'eff'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="n">v</span><span class="p">[</span><span class="s">'angle_deg'</span><span class="p">]</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg)"</span> <span class="k">for</span> <span class="n">m</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">orders</span><span class="p">.</span><span class="n">items</span><span class="p">()))</span> <span class="o">+</span>
      <span class="sa">f</span><span class="s">"; sum = </span><span class="si">{</span><span class="n">sum_orders</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, T_total = </span><span class="si">{</span><span class="n">T_total</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; +1 efficiency </span><span class="si">{</span><span class="n">orders</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="s">'eff'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> = </span><span class="si">{</span><span class="n">orders</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="s">'eff'</span><span class="p">]</span> <span class="o">/</span> <span class="n">BLAZED_BOUND</span> <span class="o">*</span> <span class="mi">100</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> % of the 4-level bound </span><span class="si">{</span><span class="n">BLAZED_BOUND</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">ext_sc</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="n">Y_BOT</span><span class="p">,</span> <span class="o">-</span><span class="n">Y_BOT</span><span class="p">]</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">4.6</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"width_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">1.4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
<span class="n">ms</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">orders</span><span class="p">)</span>
<span class="n">bars</span> <span class="o">=</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">([</span><span class="sa">f</span><span class="s">"m = </span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="se">\n</span><span class="si">{</span><span class="n">orders</span><span class="p">[</span><span class="n">m</span><span class="p">][</span><span class="s">'angle_deg'</span><span class="p">]</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">ms</span><span class="p">],</span> <span class="p">[</span><span class="n">orders</span><span class="p">[</span><span class="n">m</span><span class="p">][</span><span class="s">"eff"</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">ms</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="p">[</span><span class="s">"tab:blue"</span> <span class="k">if</span> <span class="n">m</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="s">"tab:gray"</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">ms</span><span class="p">])</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="n">BLAZED_BOUND</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"4-level blazed bound </span><span class="si">{</span><span class="n">BLAZED_BOUND</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">b</span><span class="p">,</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">bars</span><span class="p">,</span> <span class="n">ms</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">get_x</span><span class="p">()</span> <span class="o">+</span> <span class="n">b</span><span class="p">.</span><span class="n">get_width</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">orders</span><span class="p">[</span><span class="n">m</span><span class="p">][</span><span class="s">"eff"</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.01</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">orders</span><span class="p">[</span><span class="n">m</span><span class="p">][</span><span class="s">'eff'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"efficiency (fraction of incident power)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"orders: sum </span><span class="si">{</span><span class="n">sum_orders</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> = total flux </span><span class="si">{</span><span class="n">T_total</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">xs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">ext_sc</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">ext_sc</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">eps_sc</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="n">ys</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">ext_sc</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">ext_sc</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">eps_sc</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">field_sc</span><span class="p">))))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">field_sc</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">ext_sc</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"Re(Ez): the wavefront tilts"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_sc</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">ext_sc</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"|Ez|"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
    <span class="n">a</span><span class="p">.</span><span class="n">contour</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">,</span> <span class="n">eps_sc</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="p">[</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">],</span> <span class="n">colors</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.6</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="n">MON_Y</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="sa">f</span><span class="s">"library supercell, design angle </span><span class="si">{</span><span class="n">THETA_D</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_supercell.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>


<span class="c1"># ================================================================ D. finite arrays: far field
</span><span class="k">def</span> <span class="nf">finite_array</span><span class="p">(</span><span class="n">n_atom</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">pad</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">R_ff</span><span class="o">=</span><span class="mf">200.0</span><span class="p">,</span> <span class="n">angles</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mi">85</span><span class="p">,</span> <span class="mi">85</span><span class="p">,</span> <span class="mi">341</span><span class="p">)):</span>
    <span class="n">aperture</span> <span class="o">=</span> <span class="n">n_atom</span> <span class="o">*</span> <span class="n">LA</span>
    <span class="n">sx</span> <span class="o">=</span> <span class="n">aperture</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">pad</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span>
    <span class="n">n2f_y</span> <span class="o">=</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DAIR</span>
    <span class="n">geom</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">)]</span>
    <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n_atom</span><span class="p">):</span>
        <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">aperture</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">LA</span>
        <span class="n">geom</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xj</span><span class="p">,</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w_lib</span><span class="p">[</span><span class="n">j</span> <span class="o">%</span> <span class="n">N_SEC</span><span class="p">],</span> <span class="n">H</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">))</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">geom</span><span class="p">,</span>
                        <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">,</span> <span class="n">is_integrated</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                                           <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SRC_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">aperture</span><span class="p">,</span> <span class="mi">0</span><span class="p">))])</span>   <span class="c1"># source only under the array
</span>    <span class="n">n2f</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_near2far</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Near2FarRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">n2f_y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">n2f_y</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">I</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="nb">abs</span><span class="p">(</span><span class="n">sim</span><span class="p">.</span><span class="n">get_farfield</span><span class="p">(</span><span class="n">n2f</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R_ff</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">)),</span> <span class="n">R_ff</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">))))[</span><span class="mi">2</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">angles</span><span class="p">])</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">aperture</span><span class="p">,</span> <span class="n">angles</span><span class="p">,</span> <span class="n">I</span> <span class="o">/</span> <span class="n">I</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span>


<span class="n">ff</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mf">4.2</span><span class="p">))</span>
<span class="k">for</span> <span class="n">n_atom</span><span class="p">,</span> <span class="n">color</span> <span class="ow">in</span> <span class="p">((</span><span class="mi">10</span><span class="p">,</span> <span class="s">"tab:orange"</span><span class="p">),</span> <span class="p">(</span><span class="mi">40</span><span class="p">,</span> <span class="s">"tab:blue"</span><span class="p">)):</span>
    <span class="n">aperture</span><span class="p">,</span> <span class="n">angles</span><span class="p">,</span> <span class="n">pattern</span> <span class="o">=</span> <span class="n">finite_array</span><span class="p">(</span><span class="n">n_atom</span><span class="p">)</span>
    <span class="n">peak</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">angles</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">pattern</span><span class="p">)])</span>
    <span class="n">bw</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">wl</span> <span class="o">/</span> <span class="p">(</span><span class="n">aperture</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">THETA_D</span><span class="p">)))))</span>
    <span class="n">ff</span><span class="p">[</span><span class="n">n_atom</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"aperture_um"</span><span class="p">:</span> <span class="n">aperture</span><span class="p">,</span> <span class="s">"peak_deg"</span><span class="p">:</span> <span class="n">peak</span><span class="p">,</span> <span class="s">"beamwidth_est_deg"</span><span class="p">:</span> <span class="n">bw</span><span class="p">}</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">angles</span><span class="p">,</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">n_atom</span><span class="si">}</span><span class="s"> atoms (D = </span><span class="si">{</span><span class="n">aperture</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> um): peak </span><span class="si">{</span><span class="n">peak</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg, est. width </span><span class="si">{</span><span class="n">bw</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"D. </span><span class="si">{</span><span class="n">n_atom</span><span class="si">}</span><span class="s"> atoms: aperture </span><span class="si">{</span><span class="n">aperture</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> um, main lobe </span><span class="si">{</span><span class="n">peak</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg (design </span><span class="si">{</span><span class="n">THETA_D</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">), est. beam width </span><span class="si">{</span><span class="n">bw</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">THETA_D</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="n">THETA_D</span><span class="p">,</span> <span class="mf">1.03</span><span class="p">,</span> <span class="sa">f</span><span class="s">" design </span><span class="si">{</span><span class="n">THETA_D</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"angle from the normal [deg]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"normalized |Ez|^2 (far field)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.12</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"far field of finite arrays built from the library"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_farfield.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ================================================================ E. GIF: 12-atom array, short pulse
</span><span class="n">n_anim</span> <span class="o">=</span> <span class="mi">12</span>
<span class="n">fw_anim</span> <span class="o">=</span> <span class="mf">0.4</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">aperture</span> <span class="o">=</span> <span class="n">n_anim</span> <span class="o">*</span> <span class="n">LA</span>
<span class="n">sx_a</span> <span class="o">=</span> <span class="n">aperture</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="mf">1.0</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span>
<span class="n">sy_a</span> <span class="o">=</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="mf">2.5</span> <span class="o">+</span> <span class="n">DPML</span>
<span class="n">yb</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sy_a</span>
<span class="n">ydev</span> <span class="o">=</span> <span class="n">yb</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span>
<span class="n">geom</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">yb</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">)]</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n_anim</span><span class="p">):</span>
    <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">aperture</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">LA</span>
    <span class="n">geom</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xj</span><span class="p">,</span> <span class="n">ydev</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w_lib</span><span class="p">[</span><span class="n">j</span> <span class="o">%</span> <span class="n">N_SEC</span><span class="p">],</span> <span class="n">H</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">Si</span><span class="p">))</span>
<span class="n">sim_a</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx_a</span><span class="p">,</span> <span class="n">sy_a</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">geom</span><span class="p">,</span>
                      <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw_anim</span><span class="p">,</span> <span class="n">is_integrated</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                                         <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">yb</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.3</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">aperture</span><span class="p">,</span> <span class="mi">0</span><span class="p">))])</span>
<span class="n">sim_a</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">vol_a</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx_a</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">sy_a</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">))</span>
<span class="n">eps_a</span> <span class="o">=</span> <span class="n">sim_a</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">vol_a</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">ext_a</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="p">(</span><span class="n">sx_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sx_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="n">sy_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sy_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">]</span>
<span class="n">t_src</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="n">fw_anim</span>
<span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_a</span><span class="p">,</span> <span class="n">vol_a</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t_src</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">fw_anim</span><span class="p">,</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t_src</span> <span class="o">+</span> <span class="mf">1.2</span> <span class="o">*</span> <span class="n">sy_a</span> <span class="o">*</span> <span class="mf">1.45</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="n">ext_a</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"06_anim_array.gif"</span><span class="p">),</span> <span class="n">eps</span><span class="o">=</span><span class="n">eps_a</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">6.0</span><span class="p">,</span> <span class="mf">5.2</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span>
               <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">n_anim</span><span class="si">}</span><span class="s">-atom array: wavefront leaves tilted toward +</span><span class="si">{</span><span class="n">THETA_D</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>

<span class="k">if</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">():</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"params"</span><span class="p">:</span> <span class="p">{</span><span class="s">"wl"</span><span class="p">:</span> <span class="n">wl</span><span class="p">,</span> <span class="s">"La"</span><span class="p">:</span> <span class="n">LA</span><span class="p">,</span> <span class="s">"Lambda"</span><span class="p">:</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="s">"H"</span><span class="p">:</span> <span class="n">H</span><span class="p">,</span> <span class="s">"theta_d_deg"</span><span class="p">:</span> <span class="n">THETA_D</span><span class="p">,</span> <span class="s">"n_si"</span><span class="p">:</span> <span class="mf">3.45</span><span class="p">,</span> <span class="s">"n_sio2"</span><span class="p">:</span> <span class="mf">1.45</span><span class="p">},</span>
                   <span class="s">"library"</span><span class="p">:</span> <span class="p">{</span><span class="s">"widths"</span><span class="p">:</span> <span class="n">widths</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"amp40"</span><span class="p">:</span> <span class="n">amp40</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"phase40"</span><span class="p">:</span> <span class="n">ph40</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"amp60"</span><span class="p">:</span> <span class="n">amp60</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span>
                               <span class="s">"phase60"</span><span class="p">:</span> <span class="n">ph60</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"span40_over_2pi"</span><span class="p">:</span> <span class="n">span40</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="s">"max_dphi_60_40"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">dphi</span><span class="p">)))},</span>
                   <span class="s">"design"</span><span class="p">:</span> <span class="p">{</span><span class="s">"phi0"</span><span class="p">:</span> <span class="n">phi0</span><span class="p">,</span> <span class="s">"targets"</span><span class="p">:</span> <span class="n">targets</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"widths"</span><span class="p">:</span> <span class="n">w_lib</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"amps"</span><span class="p">:</span> <span class="n">a_sel</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"min_amp"</span><span class="p">:</span> <span class="n">min_amp</span><span class="p">},</span>
                   <span class="s">"supercell"</span><span class="p">:</span> <span class="p">{</span><span class="s">"orders"</span><span class="p">:</span> <span class="n">orders</span><span class="p">,</span> <span class="s">"sum_orders"</span><span class="p">:</span> <span class="n">sum_orders</span><span class="p">,</span> <span class="s">"T_total"</span><span class="p">:</span> <span class="n">T_total</span><span class="p">,</span> <span class="s">"blazed_bound"</span><span class="p">:</span> <span class="n">BLAZED_BOUND</span><span class="p">,</span>
                                 <span class="s">"plus1_over_bound"</span><span class="p">:</span> <span class="n">orders</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="s">"eff"</span><span class="p">]</span> <span class="o">/</span> <span class="n">BLAZED_BOUND</span><span class="p">},</span>
                   <span class="s">"farfield"</span><span class="p">:</span> <span class="n">ff</span><span class="p">,</span> <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">},</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span></code></pre></figure>

</details>

<details>
  <summary>원본 실행 로그·재현 환경 보기</summary>

  <p>§4의 발췌 코드와 달리 전체 코드에는 far field·그림 저장·GIF 녹화·result.json 기록이 들어 있다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

  <p><strong>실행 결과 (2026-10-23 실행)</strong>:</p>
  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A. library H=0.9: phase span = 6.920 rad = 1.101 x 2pi; |t| in [0.689, 1.011]; monotonic: True; res 60 vs 40: max|dphi| = 0.817 rad, max d|t| = 0.071
B. design: phi0 = 0.797 rad, widths = [0.075, 0.1, 0.175, 0.225] um, |t| = [1.001, 0.959, 0.885, 0.885], min |t| = 0.885
C. supercell orders: m=-1: 0.1576 (-59.4 deg), m=0: 0.0325 (+0.0 deg), m=1: 0.5144 (+59.4 deg); sum = 0.7045, T_total = 0.7045; +1 efficiency 0.5144 = 63.5 % of the 4-level bound 0.8106
D. 10 atoms: aperture 4.50 um, main lobe +49.5 deg (design +59.44), est. beam width 38.8 deg
D. 40 atoms: aperture 18.00 um, main lobe +58.5 deg (design +59.44), est. beam width 9.7 deg
</code></pre></div>  </div>

  <p><strong>재현 환경</strong>: meep 1.33.0 · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep</code> · 실행 <code class="language-plaintext highlighter-rouge">python meta_atom.py</code> (약 35 s, 단일 코어)</p>

</details>

<details>
  <summary>응용과 다음 학습 주제 보기</summary>

  <h3 id="section-8">어디에 쓰이는가</h3>

  <p>meta-atom과 phase library는 metalens, 빔 조향기, 편광 분리기의 설계 흐름이다. 단위 셀 하나를 재고 배치해 소자를 만든다.</p>

  <table>
    <thead>
      <tr>
        <th>응용</th>
        <th>이 글의 어떤 것을 쓰는가</th>
        <th>그 다음에 필요한 것</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>metalens(스마트폰 카메라 두께, AR 디스플레이, 내시경)</td>
        <td>phase library → 위치별 위상 → 초점</td>
        <td>35편 near2far 역설계</td>
      </tr>
      <tr>
        <td>beam deflector(LiDAR, 광 스위치)</td>
        <td>4단계 blazed 설계, supercell 효율</td>
        <td>08편 metagrating 역설계</td>
      </tr>
      <tr>
        <td>편광·색 분리 메타표면</td>
        <td>같은 library 방법에 편광 축과 파장을 더한다</td>
        <td>21편 비등방 재료</td>
      </tr>
      <tr>
        <td>단위 셀 → 배치 → 검증의 설계 흐름</td>
        <td>이 글 전체</td>
        <td>—</td>
      </tr>
    </tbody>
  </table>

</details>

<ul>
  <li><a href="https://github.com/NanoComp/meep/blob/master/python/examples/metasurface_lens.py">공식 예제 metasurface_lens.py</a> (duty cycle → 위상 lookup으로 렌즈 설계) · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating_phasemap.py">공식 binary_grating_phasemap.py</a></li>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Near_to_Far_Field_Spectra/">Near-to-Far Field 튜토리얼</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#near-to-far-field-spectra"><code class="language-plaintext highlighter-rouge">add_near2far</code> / <code class="language-plaintext highlighter-rouge">get_farfield</code> 레퍼런스</a></li>
  <li>이전 글: <a href="/meep-examples/binary-grating/">06 · Binary grating과 diffraction order</a> · 다음 글: <a href="/meep-examples/metagrating-inverse/">08 · Metagrating inverse design</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="metasurface" /><category term="meta-atom" /><category term="phase-library" /><category term="blazed-grating" /><category term="near2far" /><summary type="html"><![CDATA[a silicon bar in a 0.45 µm unit cell is a meta-atom. Sweep its width, record the complex transmission t(w), and you have a phase library. Pick four widths that step the phase by 90°, tile them into a 1.8 µm supercell, and the structure should deflect 1550 nm light to +59.4°.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/07/04_supercell.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/07/04_supercell.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 08 · Metagrating inverse design — forward, adjoint, gradient, 검증의 4단계 계약</title><link href="https://jin-castle.github.io/meep-examples/metagrating-inverse/" rel="alternate" type="text/html" title="Meep Example 08 · Metagrating inverse design — forward, adjoint, gradient, 검증의 4단계 계약" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/metagrating-inverse</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/metagrating-inverse/"><![CDATA[<h2 id="observe">1. 먼저 보기: 같은 격자로 더 많은 빛을 보낼 수 있을까?</h2>

<p>07편에서 고른 네 개의 Si 막대는 서로 다른 이웃과 만나면 library에서 예상한 응답과 달라집니다. 이번에는 한 주기 전체를 <strong>73개 밀도 변수</strong>로 열어, 오른쪽 위 +1차로 나가는 빛을 늘려 봅니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/06_verify.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/06_verify.png" alt="새 시뮬레이션에서 비교한 원래 격자와 갱신 격자의 차수별 효율 및 전기장" /></a>
<figcaption>실제 별도 검증 결과입니다. +1차 효율은 0.4959에서 0.6228로 증가하고, 0차는 0.0666에서 0.0169로 줄었습니다. 그림을 누르면 원본을 확대할 수 있습니다.</figcaption>
</figure>

<p class="lesson-note"><strong>개선과 수렴은 다릅니다.</strong> 이 결과는 MMA 5회 평가 중 가장 좋았던 3회차입니다. 73개 중 27개가 회색조이며, 최소 선폭·이진화 제약과 해상도 수렴 검증이 없어 제작 가능한 최적 설계로 볼 수 없습니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/07_anim_optimized.gif" data-lightbox=""><img src="/meep-examples/assets/meep/08/07_anim_optimized.gif" data-animation-src="/meep-examples/assets/meep/08/07_anim_optimized.gif" data-static-src="/meep-examples/assets/meep/08/06_verify.png" alt="최적화한 격자를 다섯 주기 반복한 유한 배열에서 비스듬히 나가는 짧은 펄스" /></a>
<button type="button" class="animation-toggle" hidden="">애니메이션 정지</button>
<figcaption>실제 펄스 전파 애니메이션입니다. 다섯 주기의 유한 배열에서 파면이 약 +59° 방향으로 기웁니다. 위 효율 표는 한 주기 주기경계 계산의 결과이므로 이 애니메이션 자체로 효율을 읽지는 않습니다.</figcaption>
</figure>

<h2 id="predict">2. 먼저 예측하기: gradient 방향이면 멀리 갈수록 좋을까?</h2>

<fieldset class="prediction">
<legend>현재 설계의 gradient 방향으로 한 번 움직일 때, step 크기 α를 계속 키우면?</legend>
<label><input type="radio" name="metagrating-prediction" value="always" /> +1차 효율이 계속 증가한다.</label>
<label><input type="radio" name="metagrating-prediction" value="local" /> 처음에는 증가해도 큰 step에서는 감소할 수 있다.</label>
</fieldset>

<details>
  <summary>예측과 실제 결과 비교하기</summary>

  <p>두 번째입니다. 원래 실행에서는 α = 0.8일 때 J = 0.6134까지 올랐지만, α = 2.0에서는 0.4840으로 출발점 0.4970보다 낮아졌습니다. gradient는 <strong>현재 설계 주변의 기울기</strong>이고 먼 설계의 성능을 보장하지 않습니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기: 기울기를 검증한 뒤 재료를 바꾸기</h2>

<p>밀도 ρ = 0은 공기, 1은 Si이며 사이는 유전율을 보간한 값입니다. 73개 변수는 가로 x 방향의 세로 띠를 바꿉니다. 한 띠의 높이 0.9 µm 전체는 같은 밀도를 사용하고 SiO₂ 기판은 고정합니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/00_concept.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/00_concept.png" alt="정방향 계산과 수반 계산으로 얻은 민감도로 73개 밀도를 갱신하고 별도 검증하는 개념도" loading="lazy" /></a>
<figcaption>설명용 개념도입니다. 기판 아래에서 +y 방향으로 입사하고 오른쪽 위 +1차를 목표로 합니다. forward와 adjoint는 별도 계산이며 회색 띠는 실제 최적화 결과가 아닙니다.</figcaption>
</figure>

<ol>
  <li><strong>Forward:</strong> 원래 광원으로 빛을 보내 +1차 모드 진폭을 구합니다.</li>
  <li><strong>Adjoint:</strong> 목적함수에서 유도한 source를 출력 monitor에 놓고 별도 계산합니다.</li>
  <li><strong>Gradient gate:</strong> 저장한 두 field와 재료의 밀도 의존성으로 구한 미분을 유한차분과 비교합니다.</li>
  <li><strong>갱신과 재측정:</strong> 먼저 손으로 한 걸음, 이어서 MMA로 갱신하고 새 시뮬레이션으로 차수별 power를 다시 잽니다.</li>
</ol>

<p>목적함수는 <strong>J = |a₊₁|²/P_in</strong>입니다. 이 단일 주파수·단일 목적함수 예제에서는 forward와 adjoint 두 계산으로 모든 밀도의 미분을 얻습니다. 하지만 두 field의 밝기를 그냥 곱한 그림이 곧 최종 형상은 아닙니다.</p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/03_gradient.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/03_gradient.png" alt="73개 밀도에 대한 실제 signed gradient와 두 번째 막대 가장자리에 모인 큰 양의 민감도" loading="lazy" /></a>
<figcaption>실제 초기 gradient입니다. 빨강은 밀도를 올리면 J가 증가하는 방향, 파랑은 감소시키는 방향입니다. 큰 양의 값 다섯 개가 두 번째 막대 주변 x = −0.275~−0.175 µm에 모였습니다.</figcaption>
</figure>

<p>gate에서는 0/1 경계에서 떨어진 내부점과 gradient 방향을 사용합니다. 중심차분이 clipping으로 잘리지 않아야 같은 미분을 비교할 수 있습니다. 세 step의 상대오차는 <strong>0.68%, 0.12%, 0.06%</strong>로 기준 20%를 통과했습니다. 이는 이 설정에서의 미분 검증이며, 최적화나 해상도 수렴의 증명은 아닙니다.</p>

<p class="lesson-note"><strong>모델 범위.</strong> 2D Ez, 파장 1.55 µm, x 주기경계·y PML, 해상도 40입니다. 설계 영역은 73 × 1이고 경계 평균·필터·투영을 사용하지 않습니다. 필터나 투영을 추가하면 그 mapping의 미분도 연결해야 합니다.</p>

<h2 id="run">4. 직접 실행하기: 한 번의 step 크기만 바꾸기</h2>

<p>Meep 1.33.0, nlopt, autograd가 준비된 환경에서 저장소의 <code>code/</code> 폴더를 사용합니다. 전체 코드와 공통 helper는 아래 참고 자료에서 확인할 수 있습니다. 먼저 원본 실행을 보관합니다. 원래 기록은 단일 코어 약 48초입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">OMP_NUM_THREADS</span><span class="o">=</span>1 python metagrating_inverse.py
</code></pre></div></div>

<p><strong>이번 실험은 α = 2.0을 1.2로 바꾸는 것 하나입니다.</strong> 손 step을 순회하는 <code>for alpha in (0.05, 0.3, 0.8, 2.0):</code>에서 마지막 값만 <code>1.2</code>로 바꾸고 같은 명령으로 실행하세요. gradient·출발점·MMA 평가 수는 그대로 둡니다.</p>

<p>실행 로그의 <code>one manual step</code>에서 α = 0.8, 1.2의 J와 ΔJ를 비교하세요. α = 1.2는 0.8보다 멀리 움직이지만 더 좋아진다는 보장은 없습니다. 새 결과는 직접 측정해야 하며, 기존 α = 2.0의 0.4840을 새 결과로 사용하지 않습니다.</p>

<h2 id="interpret">5. 결과 해석하기: 오른 것은 어떤 차수인가?</h2>

<table>
  <thead>
    <tr>
      <th>새 시뮬레이션의 측정값</th>
      <th style="text-align: right">원래 설계</th>
      <th style="text-align: right">갱신 설계</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>목표 +1차 효율</td>
      <td style="text-align: right">0.4959</td>
      <td style="text-align: right">0.6228</td>
    </tr>
    <tr>
      <td>0차 효율</td>
      <td style="text-align: right">0.0666</td>
      <td style="text-align: right">0.0169</td>
    </tr>
    <tr>
      <td>−1차 효율</td>
      <td style="text-align: right">0.1026</td>
      <td style="text-align: right">0.0973</td>
    </tr>
    <tr>
      <td>차수 합 = 총 투과율</td>
      <td style="text-align: right">0.6651</td>
      <td style="text-align: right">0.7369</td>
    </tr>
  </tbody>
</table>

<p>개선은 주로 0차 누설을 줄이는 데서 왔습니다. −1차는 거의 그대로입니다. 차수 합과 총 flux가 같은지도 함께 확인해야 차수 분해를 신뢰할 수 있습니다.</p>

<p>MMA 내부의 최고 J는 <strong>0.6241</strong>, 별도 검증의 +1차 효율은 <strong>0.6228</strong>입니다. 차이는 작지만, 보고하는 효율은 새 run에서 측정한 값입니다. 중간 4회차의 J = 0.0492처럼 평가가 나빠질 수 있으므로 마지막 평가 대신 보관한 최고 설계를 검증합니다.</p>

<h2 id="check">6. 이해 확인하기</h2>

<ol>
  <li>gradient gate가 통과했는데도 큰 α에서 효율이 떨어질 수 있는 이유는 무엇인가요?</li>
  <li>최종 효율로 MMA의 0.6241과 새 run의 0.6228 중 어느 값을 보고하고, 함께 확인할 것은 무엇인가요?</li>
</ol>

<details>
  <summary>두 질문의 답 확인하기</summary>

  <ol>
    <li>gate는 현재 내부점의 국소 미분을 검증합니다. 큰 이동에서는 선형 근사가 깨지고 밀도가 0/1로 clip될 수도 있어 성능 증가를 보장하지 않습니다.</li>
    <li>새 run의 <strong>0.6228</strong>을 보고합니다. 차수 합과 총 flux의 일치, 최고 설계의 선택, 회색조와 해상도·제작 제약의 한계를 함께 확인합니다.</li>
  </ol>

</details>

<h2 id="reference">7. 참고 자료와 전체 코드</h2>

<p>아래에는 원본의 자세한 설명·측정 표·실행 기록을 남겼습니다. 위의 한 가지 실험을 마친 뒤 필요한 항목을 펼쳐 보세요.</p>

<details>
  <summary>English summary</summary>

  <h3 id="tldr-english">TL;DR (English)</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/06_verify.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/06_verify.png" alt="격자의 빛을 원하는 방향으로 더 보내려면? — hero 원본 그림" loading="lazy" /></a>
</figure>

  <ul>
    <li><strong>What</strong>: the post-07 library design (four Si bars) becomes the starting point of an adjoint optimisation. The whole supercell period is a 1D design region of 73 density pixels; the objective is the +1-order efficiency. Four steps are enforced: differentiable materials, a finite-difference gate on the gradient, a short MMA run, and a fresh-simulation verification.</li>
    <li><strong>Result</strong>: the gradient passes the gate (0.7 %, 0.1 %, 0.06 % error at three step sizes). One hand-made gradient step lifts the efficiency from 0.497 to 0.613; five MMA evaluations reach 0.624. Measured again in a new simulation, order by order: +1 goes from 0.496 to 0.623 (61 % → 77 % of the 4-level bound), 0 drops from 0.067 to 0.017, −1 stays near 0.10.</li>
    <li><strong>Takeaway</strong>: adjoint gives you every pixel’s derivative for the price of two runs, but a wrong gradient fails silently. Gate it, take one step by hand before trusting an optimiser, and never report the optimiser’s own number: re-measure in a clean run. maxeval = 5 is a smoke test, not a converged design, and 27 of 73 pixels are still grey.</li>
    <li><strong>Code</strong>: full script at the bottom, ~48 s on one core.</li>
  </ul>

</details>

<details>
  <summary>배경·물리식·파라미터 자세히 보기</summary>

  <h3 id="section">원본 §0 · 이 글에서 배우는 것</h3>

  <ul>
    <li><code class="language-plaintext highlighter-rouge">meep.adjoint</code>의 세 요소: <code class="language-plaintext highlighter-rouge">MaterialGrid</code> 설계 변수, <code class="language-plaintext highlighter-rouge">DesignRegion</code>, <code class="language-plaintext highlighter-rouge">EigenmodeCoefficient</code> 목적함수를 묶는 <code class="language-plaintext highlighter-rouge">OptimizationProblem</code></li>
    <li>forward field와 adjoint field가 각각 무엇이고 gradient가 왜 둘의 곱인지</li>
    <li>gradient gate: gradient 방향의 중심차분과 g·v를 비교하는 법, 그리고 랜덤 방향·경계점을 쓰면 왜 틀리는지</li>
    <li>optimizer 전에 손으로 한 걸음 가 보기. step size가 커지면 선형 근사가 깨진다</li>
    <li>MMA 5회의 의미와 한계. 회색조 픽셀은 재료가 아니다</li>
    <li>계약 4: optimizer 내부 FOM이 아니라 새 시뮬레이션의 차수별 power로 다시 재기</li>
  </ul>

  <p><strong>전제 지식</strong>: 07편의 library와 supercell, 06편의 <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>. <strong>공식 문서</strong>: <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Adjoint_Solver/">Adjoint Solver 튜토리얼</a>, <a href="https://github.com/NanoComp/meep/blob/master/python/examples/adjoint_optimization/01-Introduction.ipynb">adjoint 예제 01</a>. <strong>이전 글</strong>: <a href="/meep-examples/meta-atom/">07 · Metalens의 meta-atom과 phase library</a> · <strong>다음 글</strong>: <a href="/meep-examples/bend-inverse/">09 · Waveguide bend inverse design</a></p>

  <h3 id="section-1">원본 §1 · 무엇을 알고 싶은가</h3>

  <p>07편의 4단계 설계는 +1차에 51%를 보냈고 상한 0.81의 63%였다. 모자란 이유는 library가 “이웃이 나와 같다”는 가정에서 나온 값이라는 것이었다. 그 가정을 버리고 73개 픽셀의 밀도를 전부 설계 변수로 열면 얼마나 회복되는가. 이것이 이 글의 질문이고, 답보다 중요한 것은 답을 믿어도 되는지 확인하는 절차다. adjoint 최적화는 gradient가 틀려도 에러 없이 조용히 엉뚱한 곳으로 수렴한다.</p>

  <h3 id="section-2">어디에 쓰이는가</h3>

  <p>metagrating은 LiDAR의 빔 조향과 대각도 회절 소자의 핵심이고, adjoint 역설계는 그 성능을 library 설계 너머로 올리는 표준 방법이다.</p>

  <table>
    <thead>
      <tr>
        <th>응용</th>
        <th>이 글의 어떤 것을 쓰는가</th>
        <th>그 다음에 필요한 것</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>LiDAR·빔 조향, 대각도 회절</td>
        <td>+1차 효율 최대화, 이웃을 고려한 비국소 설계</td>
        <td>—</td>
      </tr>
      <tr>
        <td>모든 topology optimization 입문</td>
        <td>adjoint 4단계 계약</td>
        <td>09편, 32~36편</td>
      </tr>
      <tr>
        <td>메타표면 제조 전 검증</td>
        <td>fresh-run 검증, 회색조 문제</td>
        <td>32편 filter·projection</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-3">원본 §2 · 물리 한 페이지</h3>

  <p>목적함수 J = |a₊₁|²/P_in은 73개 밀도 ρ의 함수다. 미분 ∂J/∂ρ_i를 하나씩 유한차분으로 구하면 146번의 시뮬레이션이 필요하다. adjoint 방법은 두 번으로 끝낸다. 원래 source로 쏜 forward field E_f와, 목적함수 monitor 자리에서 거꾸로 쏜 adjoint field E_a의 곱이 모든 픽셀의 gradient다. “빛이 실제로 지나는 곳”과 “목적함수가 민감한 곳”이 겹치는 픽셀에서 gradient가 크다.</p>

\[\frac{\partial J}{\partial \rho_i}\;\propto\;\mathrm{Re}\big(E_f\cdot E_a\big)\Big\lvert _{\text{pixel } i},\qquad
\text{gate: }\;\frac{\lvert \,g\cdot v - \mathrm{FD}_v\,\lvert }{\lvert \mathrm{FD}_v\lvert }\le 0.2,\quad v=\frac{g}{\lvert g\lvert },\quad
\mathrm{FD}_v=\frac{J(x+sv)-J(x-sv)}{2s}\]

  <p>gate에서 두 가지를 지킨다. 방향 v는 gradient 방향이다. 설계 변수가 N개일 때 랜덤 방향과 gradient의 내적은 1/√N 크기라 방향미분이 작아지고 몇 %의 절대오차가 수십 %의 상대오차로 부풀려진다. 그리고 경계(ρ = 0, 1)에서 떨어진 내부점에서 잰다. 0/1 설계에서 x ± sv는 항목마다 한쪽이 clip되어 중심차분이 한쪽 미분만 세고, adjoint의 정확히 절반이 나온다. adjoint 오류가 아니라 FD의 결함이다.</p>

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>ρ (73개)</td>
        <td>설계 밀도. 0 공기, 1 Si, 사이는 회색조</td>
        <td><code class="language-plaintext highlighter-rouge">x_baseline</code>, <code class="language-plaintext highlighter-rouge">x_optimized</code></td>
      </tr>
      <tr>
        <td>J</td>
        <td>+1차 효율 = |a₊₁|²/P_in</td>
        <td><code class="language-plaintext highlighter-rouge">fom(x)</code></td>
      </tr>
      <tr>
        <td>g</td>
        <td>adjoint gradient ∂J/∂ρ</td>
        <td><code class="language-plaintext highlighter-rouge">g_baseline</code></td>
      </tr>
      <tr>
        <td>v, s</td>
        <td>gate 방향(g/|g|), FD step</td>
        <td><code class="language-plaintext highlighter-rouge">v</code>, <code class="language-plaintext highlighter-rouge">steps</code></td>
      </tr>
      <tr>
        <td>α</td>
        <td>손 step 크기</td>
        <td><code class="language-plaintext highlighter-rouge">one_step</code></td>
      </tr>
      <tr>
        <td>k_diff</td>
        <td>+1차 평면파 방향 (1/Λ, √(f² − 1/Λ²))</td>
        <td><code class="language-plaintext highlighter-rouge">kdiff</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 2D Ez, 1D 설계 영역(높이 방향 1픽셀, 막대 높이 전체가 한 변수), 단일 주파수, <code class="language-plaintext highlighter-rouge">eps_averaging=False</code>로 경계 평균 없음. 제작 제약(최소 선폭, 이진화)은 없다.</p>

  <h3 id="section-4">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>gate 상대오차</td>
        <td>1% 안</td>
        <td>10_sources의 adjoint 튜토리얼 재현에서 2 × 10⁻⁶</td>
      </tr>
      <tr>
        <td>gradient가 큰 곳</td>
        <td>막대 가장자리</td>
        <td>경계를 옮기는 것이 가장 효과가 크다</td>
      </tr>
      <tr>
        <td>손 step</td>
        <td>α를 키우면 오르다가 꺾임</td>
        <td>선형 근사의 한계</td>
      </tr>
      <tr>
        <td>MMA 5회</td>
        <td>0.497에서 0.6 근처로, 중간에 추락 가능</td>
        <td>MMA가 신뢰영역을 넓게 잡았다 되돌림</td>
      </tr>
      <tr>
        <td>별도 검증 vs optimizer FOM</td>
        <td>소수 둘째 자리에서 다름</td>
        <td>설계 격자(MaterialGrid 73 px)와 분해 monitor가 같아 비슷하지만 종료 조건이 다르다</td>
      </tr>
      <tr>
        <td>회색조 픽셀</td>
        <td>수십 개</td>
        <td>이진화 없이 5회</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: gate 상대오차 &gt; 20%면 HOLD. 그 뒤는 해석하지 않는다. 차수 합 ≠ 총 flux면 분해 오류.</p>

  <h3 id="section-5">원본 §3 · 시뮬레이션 설계도</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/01_layout.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/01_layout.png" alt="07편 supercell과 같은 셀. 막대 자리가 1D `MaterialGrid` 설계 영역(폭 1.8 µm, 높이 0.9 µm, 73 픽셀)으로 바뀌었고 초기값은 library의 네 막대다. 빨간 가로선 = 기판 안 평면파, 파란 " loading="lazy" /></a>
<figcaption>07편 supercell과 같은 셀. 막대 자리가 1D <code class="language-plaintext highlighter-rouge">MaterialGrid</code> 설계 영역(폭 1.8 µm, 높이 0.9 µm, 73 픽셀)으로 바뀌었고 초기값은 library의 네 막대다. 빨간 가로선 = 기판 안 평면파, 파란 가로선 = 목적함수 monitor(+1차 진폭), 녹색 빗금 = y PML, x는 주기 경계. 동그라미 숫자는 §4의 단계 번호다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>셀·주기·높이·해상도</td>
        <td>07편과 동일 (1.8 × 4.9 µm, res 40)</td>
        <td>library를 그대로 초기값으로 쓰려면 모두 같아야 한다</td>
        <td>하나라도 다르면 baseline이 07편 설계가 아니다</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">Nx</code></td>
        <td>73 (25 nm 픽셀)</td>
        <td>셀 폭 × res + 1</td>
        <td>늘리면 변수는 늘지만 격자보다 가늘어져 의미 없다</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">decay_by</code></td>
        <td>1e-6</td>
        <td>adjoint run의 종료 기준. 느슨하면 adjoint만 무너진다(10_sources fdcheck)</td>
        <td>1e-4면 adjoint gradient가 81% 틀어진다</td>
      </tr>
      <tr>
        <td>gate steps</td>
        <td>2e-3, 5e-3, 1e-2</td>
        <td>절단오차와 반올림오차 사이</td>
        <td>1e-6이면 반올림 반등</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">maxeval</code></td>
        <td>5</td>
        <td>수업용 smoke test</td>
        <td>수렴을 보려면 수십 회 + 이진화</td>
      </tr>
      <tr>
        <td>손 step α</td>
        <td>0.05, 0.3, 0.8, 2.0</td>
        <td>꺾이는 지점(0.8 근처) 포함</td>
        <td>—</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/00_source.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/00_source.png" alt="source 파형과 스펙트럼. 07편과 같다. 빈 기판 run에서 monitor 높이의 x 방향 위상 변화는 0.0000 rad로 수직 입사가 확인됐다." loading="lazy" /></a>
<figcaption>source 파형과 스펙트럼. 07편과 같다. 빈 기판 run에서 monitor 높이의 x 방향 위상 변화는 0.0000 rad로 수직 입사가 확인됐다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 없다. 4단계 계약, 파라미터, 수치(gate 0.0068/0.0012/0.0006, MMA 0.497 → 0.624, 검증 0.496 → 0.623) 모두 강의 week 9와 같다. 이 글은 10_sources의 두 fdcheck 노트에서 얻은 “gate가 깨지는 네 가지 이유”를 §6에 더했다.</p>

</details>

<details>
  <summary>원본 코드 단계별 설명</summary>

  <h3 id="section-6">원본 §4 · 코드 따라가기</h3>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
이번 글의 ⑤는 “목적함수”이고 ⑥·⑦은 forward·adjoint·gate·MMA·검증으로 늘어난다.</p>
  </blockquote>

  <h3 id="section-7">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">wl</span><span class="p">,</span> <span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span> <span class="o">=</span> <span class="mf">1.55</span><span class="p">,</span> <span class="mi">1</span> <span class="o">/</span> <span class="mf">1.55</span><span class="p">,</span> <span class="mf">0.1</span> <span class="o">/</span> <span class="mf">1.55</span>
<span class="n">N_SEC</span><span class="p">,</span> <span class="n">LA</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="mf">0.45</span><span class="p">;</span> <span class="n">LAMBDA</span> <span class="o">=</span> <span class="n">N_SEC</span> <span class="o">*</span> <span class="n">LA</span><span class="p">;</span> <span class="n">H</span> <span class="o">=</span> <span class="mf">0.9</span><span class="p">;</span> <span class="n">RES</span> <span class="o">=</span> <span class="mi">40</span>
<span class="n">W_LIB</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mf">0.075</span><span class="p">,</span> <span class="mf">0.100</span><span class="p">,</span> <span class="mf">0.175</span><span class="p">,</span> <span class="mf">0.225</span><span class="p">])</span>          <span class="c1"># post-07 design (read from assets/07/result.json)
</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">round</span><span class="p">(</span><span class="n">RES</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">))</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span>                  <span class="c1"># 73 x 1 design pixels
</span><span class="n">x_grid</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="n">Nx</span><span class="p">)</span>
<span class="n">x_baseline</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">Nx</span><span class="p">)</span>
<span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">w</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">W_LIB</span><span class="p">):</span>
    <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">LA</span>
    <span class="n">x_baseline</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">x_grid</span> <span class="o">-</span> <span class="n">xj</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">w</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span>    <span class="c1"># the four bars, as 0/1 densities
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 07편 파라미터를 그대로 두고, library 설계를 73개 0/1 밀도로 옮긴다.</li>
    <li><strong>왜</strong>: 출발점이 랜덤이 아니라 “이미 괜찮은 설계”여야 “adjoint가 간극을 얼마나 메우는가”를 물을 수 있다. 랜덤 회색조는 +1차 효율 0.018에서 시작한다(§5).</li>
    <li><strong>틀리면</strong>: 픽셀 폭 25 nm와 library 폭(0.075 = 3 px)이 맞지 않으면 baseline이 07편과 다른 구조가 된다.</li>
  </ul>

  <h3 id="section-8">② 재료와 구조 — 무엇이 어디에 있는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">design_variables</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">MaterialGrid</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">,</span> <span class="n">Si</span><span class="p">,</span> <span class="n">grid_type</span><span class="o">=</span><span class="s">"U_MEAN"</span><span class="p">,</span> <span class="n">do_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>   <span class="c1"># contract 1
</span><span class="n">design_region</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">DesignRegion</span><span class="p">(</span><span class="n">design_variables</span><span class="p">,</span>
                                 <span class="n">volume</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">H</span><span class="p">)))</span>
<span class="n">geometry</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(...,</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">),</span>                                   <span class="c1"># substrate
</span>            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">center</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">size</span><span class="p">,</span> <span class="n">material</span><span class="o">=</span><span class="n">design_variables</span><span class="p">)]</span>
<span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry</span><span class="p">,</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 막대 대신 밀도 격자. <code class="language-plaintext highlighter-rouge">MaterialGrid</code>는 ρ = 0이면 공기, 1이면 Si, 사이는 선형 보간된 유전율이다.</li>
    <li><strong>왜</strong>: 미분하려면 유전율이 ρ의 매끄러운 함수여야 한다. <code class="language-plaintext highlighter-rouge">do_averaging=False</code>와 <code class="language-plaintext highlighter-rouge">eps_averaging=False</code>가 계약 1이다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">eps_averaging</code>을 기본값(True)으로 두면 Meep이 경계에서 유전율을 평균해 gradient와 실제 구조가 어긋난다.</li>
  </ul>

  <h3 id="source----">③ Source — 빛을 어떻게 넣는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SRC_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>
<span class="n">adjoint_sources</span> <span class="o">=</span> <span class="n">opt</span><span class="p">.</span><span class="n">adjoint_sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>      <span class="c1"># what opt actually fired for the adjoint run (an EigenModeSource at the monitor)
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: forward는 07편과 같은 평면파. adjoint source는 <code class="language-plaintext highlighter-rouge">OptimizationProblem</code>이 목적함수 monitor 자리에 스스로 만든다.</li>
    <li><strong>왜</strong>: adjoint source의 진폭과 모양은 목적함수의 미분값으로 정해진다. 우리가 고르는 게 아니라 <code class="language-plaintext highlighter-rouge">opt</code>가 계산한 것을 꺼내 볼 뿐이다.</li>
    <li><strong>틀리면</strong>: 빈 기판 run에서 monitor 높이의 위상이 x를 따라 변하면 source가 기울어진 것이고 “+1차 효율”이라는 말이 성립하지 않는다.</li>
  </ul>

  <h3 id="simulation-----pml">④ Simulation과 경계 — 계산 상자와 PML</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">common</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span>
              <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 07편 supercell과 같다. x 주기, y PML.</li>
    <li><strong>왜</strong>: 모든 run(forward, adjoint, FD, 검증)이 같은 셀을 써야 비교가 된다.</li>
    <li><strong>틀리면</strong>: 검증 run의 셀이 다르면 “optimizer FOM과 다르다”가 설계 때문인지 셀 때문인지 모른다.</li>
  </ul>

  <h3 id="monitor--">⑤ Monitor — 목적함수</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">kdiff</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">fcen</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">-</span> <span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">LAMBDA</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">))</span>          <span class="c1"># +1 order direction
</span><span class="n">emc</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">EigenmodeCoefficient</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span> <span class="n">mode</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
                               <span class="n">eig_parity</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">ODD_Z</span><span class="p">,</span> <span class="n">kpoint_func</span><span class="o">=</span><span class="k">lambda</span> <span class="o">*</span><span class="n">_</span><span class="p">:</span> <span class="n">kdiff</span><span class="p">,</span>
                               <span class="n">eig_vol</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">RES</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
<span class="n">opt</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">OptimizationProblem</span><span class="p">(</span><span class="n">simulation</span><span class="o">=</span><span class="n">sim</span><span class="p">,</span> <span class="n">objective_functions</span><span class="o">=</span><span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">npa</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span><span class="p">,</span>
                              <span class="n">objective_arguments</span><span class="o">=</span><span class="p">[</span><span class="n">emc</span><span class="p">],</span> <span class="n">design_regions</span><span class="o">=</span><span class="p">[</span><span class="n">design_region</span><span class="p">],</span> <span class="n">fcen</span><span class="o">=</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">nf</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">decay_by</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: monitor 선 위의 +1차 평면파 진폭 a₊₁을 목적함수 인자로, |a₊₁|²를 목적함수로.</li>
    <li><strong>왜</strong>: <code class="language-plaintext highlighter-rouge">kpoint_func</code>가 +1차 방향을 지정하고, <code class="language-plaintext highlighter-rouge">eig_vol</code>을 한 픽셀로 잡아 “평면파”임을 알린다(06편의 <code class="language-plaintext highlighter-rouge">DiffractedPlanewave</code>에 해당). <code class="language-plaintext highlighter-rouge">npa</code>(autograd의 numpy)로 써야 목적함수 자체가 미분된다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">eig_parity</code>를 빼면 다른 편광 모드가 섞인다. <code class="language-plaintext highlighter-rouge">decay_by</code>를 1e-4로 느슨하게 하면 forward와 FD는 멀쩡한데 adjoint gradient만 81% 틀어진다(10_sources fdcheck E4).</li>
  </ul>

  <h3 id="forward-adjoint-gate---mma">⑥ 실행 — forward, adjoint, gate, 한 걸음, MMA</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">f</span><span class="p">,</span> <span class="n">dJ</span> <span class="o">=</span> <span class="n">opt</span><span class="p">([</span><span class="n">x</span><span class="p">],</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>            <span class="c1"># forward + adjoint: J and dJ/drho for all 73 pixels
</span>
<span class="n">x_gate</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x_baseline</span><span class="p">,</span> <span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.98</span><span class="p">)</span>         <span class="c1"># interior point, away from 0/1
</span><span class="n">v</span> <span class="o">=</span> <span class="n">g_gate</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_gate</span><span class="p">)</span>              <span class="c1"># gradient direction
</span><span class="n">fd</span> <span class="o">=</span> <span class="p">(</span><span class="n">fom</span><span class="p">(</span><span class="n">x_gate</span> <span class="o">+</span> <span class="n">s</span> <span class="o">*</span> <span class="n">v</span><span class="p">)</span> <span class="o">-</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_gate</span> <span class="o">-</span> <span class="n">s</span> <span class="o">*</span> <span class="n">v</span><span class="p">))</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">s</span><span class="p">)</span>
<span class="n">ok</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">g_gate</span> <span class="o">@</span> <span class="n">v</span> <span class="o">-</span> <span class="n">fd</span><span class="p">)</span> <span class="o">/</span> <span class="nb">abs</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mf">0.20</span>

<span class="n">x_try</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x_baseline</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">g</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>    <span class="c1"># one step by hand
</span>
<span class="n">solver</span> <span class="o">=</span> <span class="n">nlopt</span><span class="p">.</span><span class="n">opt</span><span class="p">(</span><span class="n">nlopt</span><span class="p">.</span><span class="n">LD_MMA</span><span class="p">,</span> <span class="n">Nx</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_lower_bounds</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_upper_bounds</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">solver</span><span class="p">.</span><span class="n">set_max_objective</span><span class="p">(</span><span class="n">nlopt_objective</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_maxeval</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: <code class="language-plaintext highlighter-rouge">opt(...)</code> 한 번이 forward와 adjoint 두 run이다. gate는 세 step으로 중심차분. 그다음 손으로 한 걸음, 그다음 MMA 5회.</li>
    <li><strong>왜</strong>: 순서가 계약이다. gate를 통과하지 못한 gradient로는 아무것도 하지 않는다. 손 step은 “gradient 방향으로 가면 정말 오르는가, 얼마나 멀리까지”를 보여 준다.</li>
    <li><strong>틀리면</strong>: 0/1 baseline에서 바로 gate를 재면 clip 때문에 FD가 adjoint의 절반이 나와 HOLD가 된다. 랜덤 방향으로 재면 상대오차가 1/√73 배로 부풀려진다.</li>
  </ul>

  <h3 id="section-9">⑦ 후처리 — 계약 4, 별도 검증</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">forward_orders</span><span class="p">(</span><span class="n">weights</span><span class="p">):</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_with</span><span class="p">(</span><span class="n">weights</span><span class="p">),</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>   <span class="c1"># a NEW simulation
</span>    <span class="n">mon</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
    <span class="n">s</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_cond</span><span class="p">)</span>
    <span class="n">eff</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="nb">abs</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mon</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">DiffractedPlanewave</span><span class="p">((</span><span class="n">m</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">input_flux</span>
           <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)}</span>
    <span class="k">return</span> <span class="n">eff</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">mon</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">input_flux</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 최종 설계를 새 <code class="language-plaintext highlighter-rouge">Simulation</code>에 넣고 06편 방식으로 세 차수를 다시 잰다. 차수 합 = 총 flux도 검산한다.</li>
    <li><strong>왜</strong>: optimizer 안의 FOM은 그 optimizer의 종료 조건·monitor 설정에 묶인 숫자다. 보고할 값은 독립 run의 값이어야 한다.</li>
    <li><strong>틀리면</strong>: optimizer FOM(0.624)을 그대로 쓰면 검증값(0.623)과 미세하게 다르다. 이번엔 작지만 조건이 다르면 커진다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: 여기서 설계 변수는 x에 대한 밀도 하나뿐이고 mapping(필터·투영)이 없다. mapping을 넣으면 gradient에 chain rule을 걸어야 하고, 빠뜨리면 gate의 cosine이 −0.45로 방향이 반대가 된다(10_sources fdcheck E5).</p>
  </blockquote>

</details>

<details>
  <summary>원본 결과·검증 표·오류 진단·추가 탐구</summary>

  <h3 id="section-10">원본 §5 · 결과</h3>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/02_fields.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/02_fields.png" alt="왼쪽: library baseline의 forward field. 파면이 위로 갈수록 오른쪽으로 기운다(+1차). 가운데: 랜덤 회색조 출발점. 파면이 뭉개지고 J = 0.018이다. 오른쪽: adjoint field. monitor" loading="lazy" /></a>
<figcaption>왼쪽: library baseline의 forward field. 파면이 위로 갈수록 오른쪽으로 기운다(+1차). 가운데: 랜덤 회색조 출발점. 파면이 뭉개지고 J = 0.018이다. 오른쪽: adjoint field. monitor에서 아래로 내려오는 파. 절대 크기는 비교하지 않는다. 볼 것은 “어디에 있는가”다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/03_gradient.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/03_gradient.png" alt="baseline에서의 날것 gradient. 빨강은 밀도를 올리면 J가 오르는 자리, 파랑은 반대. 절대값이 큰 5개가 모두 두 번째 막대(x = −0.275~−0.175) 가장자리에 몰려 있다. 막대를 넓히라는 뜻이다." loading="lazy" /></a>
<figcaption>baseline에서의 날것 gradient. 빨강은 밀도를 올리면 J가 오르는 자리, 파랑은 반대. 절대값이 큰 5개가 모두 두 번째 막대(x = −0.275~−0.175) 가장자리에 몰려 있다. 막대를 넓히라는 뜻이다.</figcaption>
</figure>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/04_gate.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/04_gate.png" alt="gradient gate. 세 step 모두 FD와 adjoint가 1% 안에서 같다. PASS." loading="lazy" /></a>
<figcaption>gradient gate. 세 step 모두 FD와 adjoint가 1% 안에서 같다. PASS.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>step</th>
        <th>FD</th>
        <th>adjoint g·v</th>
        <th>상대오차</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>2e-3</td>
        <td>0.5410</td>
        <td>0.5447</td>
        <td>0.0068</td>
      </tr>
      <tr>
        <td>5e-3</td>
        <td>0.5454</td>
        <td>0.5447</td>
        <td>0.0012</td>
      </tr>
      <tr>
        <td>1e-2</td>
        <td>0.5451</td>
        <td>0.5447</td>
        <td>0.0006</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/05_step_mma.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/05_step_mma.png" alt="위: 손으로 한 걸음(α sweep)과 MMA history. α = 0.8까지 오르다 2.0에서 떨어진다. 아래: MMA 다섯 번의 설계. 3번째에서 0.624, 4번째에서 0.049로 추락했다가 5번째에 0.540으로 돌아온다. " loading="lazy" /></a>
<figcaption>위: 손으로 한 걸음(α sweep)과 MMA history. α = 0.8까지 오르다 2.0에서 떨어진다. 아래: MMA 다섯 번의 설계. 3번째에서 0.624, 4번째에서 0.049로 추락했다가 5번째에 0.540으로 돌아온다. 가장 좋은 3번째를 최종으로 둔다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>α</th>
        <th>J</th>
        <th>ΔJ</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0.05</td>
        <td>0.5075</td>
        <td>+0.011</td>
      </tr>
      <tr>
        <td>0.3</td>
        <td>0.5549</td>
        <td>+0.058</td>
      </tr>
      <tr>
        <td>0.8</td>
        <td>0.6134</td>
        <td>+0.116</td>
      </tr>
      <tr>
        <td>2.0</td>
        <td>0.4840</td>
        <td>−0.013</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/08/06_verify.png" data-lightbox=""><img src="/meep-examples/assets/meep/08/06_verify.png" alt="계약 4. 새 시뮬레이션에서 잰 차수별 효율(왼쪽)과 baseline·optimized의 Re(Ez)(가운데·오른쪽). 빨간 점선이 4단계 blazed 상한." loading="lazy" /></a>
<figcaption>계약 4. 새 시뮬레이션에서 잰 차수별 효율(왼쪽)과 baseline·optimized의 Re(Ez)(가운데·오른쪽). 빨간 점선이 4단계 blazed 상한.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>설계</th>
        <th>m = −1</th>
        <th>m = 0</th>
        <th>m = +1</th>
        <th>차수 합</th>
        <th>총 투과</th>
        <th>+1 / 상한</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>baseline (07편 library)</td>
        <td>0.1026</td>
        <td>0.0666</td>
        <td>0.4959</td>
        <td>0.6651</td>
        <td>0.6651</td>
        <td>61.2%</td>
      </tr>
      <tr>
        <td>optimized (MMA eval 3)</td>
        <td>0.0973</td>
        <td>0.0169</td>
        <td>0.6228</td>
        <td>0.7369</td>
        <td>0.7369</td>
        <td>76.8%</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-11">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>gate 상대오차</td>
        <td>1% 안</td>
        <td>0.7%, 0.1%, 0.06%</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>gradient 큰 곳</td>
        <td>막대 가장자리</td>
        <td>두 번째 막대 양 끝</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>손 step</td>
        <td>오르다 꺾임</td>
        <td>0.8에서 최대, 2.0에서 하락</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>MMA 5회</td>
        <td>0.6 근처, 중간 추락</td>
        <td>0.624, 4회차 0.049</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>검증 vs optimizer</td>
        <td>둘째 자리 차이</td>
        <td>0.6228 vs 0.6241</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>회색조</td>
        <td>수십 개</td>
        <td>27 / 73</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>예측대로였고, 숫자로 확인된 것은 두 가지다. 07편의 “이웃이 같다” 가정이 잃던 몫의 절반 가까이를 픽셀 자유도가 되찾았다(61% → 77%). 그리고 그 개선의 대부분은 0차 누설을 줄인 데서 왔다(0.067 → 0.017). −1차는 거의 그대로다. 계단 근사의 거울상 누설은 5회로는 못 건드렸다.</p>

  <h3 id="section-12">수렴성</h3>

  <p>이 글의 수렴성은 해상도가 아니라 gate의 세 step이다. step을 5배 바꿔도 FD가 0.541~0.545에서 안정이고 adjoint와 1% 안에 있다. 해상도 의존성은 07편의 library 수렴성(위상 0.82 rad 변동)이 그대로 이 설계에 옮겨 온다. res 60으로 다시 돌리면 baseline 효율부터 달라진다.</p>

  <h3 id="section-13">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: 이 셀·해상도에서 adjoint gradient는 유한차분과 1% 안에서 같다. library baseline에서 다섯 번의 MMA 평가로 +1차 효율이 0.50에서 0.62로 올랐고, 그 값은 별도 run으로 재확인됐다.</li>
    <li>할 수 없는 것: “최적 설계를 찾았다”. maxeval 5는 수렴이 아니다. 73개 중 27개가 회색조라 이 패턴은 실제 소자가 아니다. 최소 선폭 제약이 없어 이진화하면 효율이 달라진다. 다른 해상도·파장·편광에서의 값.</li>
  </ul>

  <h3 id="section-14">원본 §6 · 흔한 실수</h3>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>gate에서 FD가 adjoint의 정확히 1/2</td>
        <td>0/1 경계점에서 clip된 중심차분</td>
        <td>내부점(0.02~0.98)에서 재기</td>
      </tr>
      <tr>
        <td>gate 상대오차 수십 %</td>
        <td>랜덤 방향 사용</td>
        <td>gradient 방향 v = g/|g|</td>
      </tr>
      <tr>
        <td>gate에서 adjoint만 틀어짐</td>
        <td><code class="language-plaintext highlighter-rouge">decay_by</code> 느슨함</td>
        <td>1e-6 이하</td>
      </tr>
      <tr>
        <td>gate cosine이 음수</td>
        <td>mapping(필터·투영)의 chain rule 누락</td>
        <td>gradient에 mapping의 Jacobian 곱하기</td>
      </tr>
      <tr>
        <td>optimizer FOM과 검증값이 다름</td>
        <td>조건이 다른 run</td>
        <td>보고는 항상 새 run의 값으로</td>
      </tr>
      <tr>
        <td>MMA가 중간에 추락</td>
        <td>신뢰영역 과대</td>
        <td>정상 동작. 최고 평가를 보관</td>
      </tr>
      <tr>
        <td>회색조 설계를 소자로 해석</td>
        <td>이진화·선폭 제약 없음</td>
        <td>09편 이후: 필터·투영·β 스케줄</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-15">원본 §7 · 직접 해보기</h3>

  <table>
    <thead>
      <tr>
        <th>바꿀 것</th>
        <th>예상 변화</th>
        <th>확인할 수치</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>초기값을 균일 0.5로</td>
        <td>격자가 없어 +1차 0인 퇴화점. gradient가 어떻게 나오는지</td>
        <td>g, gate</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">maxeval</code> 5 → 30</td>
        <td>효율이 어디서 정체하는지</td>
        <td>history</td>
      </tr>
      <tr>
        <td>목적함수를 |a₊₁|² − |a₋₁|²로</td>
        <td>−1차 누설이 줄어드는지</td>
        <td>검증 표</td>
      </tr>
      <tr>
        <td>gate에서 <code class="language-plaintext highlighter-rouge">decay_by</code> 1e-6 → 1e-4</td>
        <td>adjoint만 틀어지는 것을 재현</td>
        <td>상대오차</td>
      </tr>
    </tbody>
  </table>

</details>

<details>
<summary>metagrating_inverse.py (클릭해서 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 08 - Metagrating inverse design (adjoint), with a four-step contract.

Start from the post-07 library design (four Si bars). Open the whole supercell period as a 1D design
region (73 pixels of density 0..1) and let the adjoint gradient move it. Every step is looked at:
  1. differentiability: eps_averaging=False, MaterialGrid do_averaging=False
  2. gradient gate: adjoint gradient vs centred finite differences along the gradient direction
  3. a short MMA run (maxeval 5): a smoke test, not a converged design
  4. verification in a FRESH simulation with DiffractedPlanewave, order by order
Plus: forward field of baseline and of a random start, adjoint field, raw gradient, one manual step.

Run:  python metagrating_inverse.py      (~1.5 min on one core)
Out:  00_source.png, 01_layout.png, 02_fields.png, 03_gradient.png, 04_gate.png, 05_step_mma.png,
      06_verify.png, 07_anim_optimized.gif, result.json   (-&gt; ../assets/08/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>
<span class="kn">import</span> <span class="nn">meep.adjoint</span> <span class="k">as</span> <span class="n">mpa</span>
<span class="kn">import</span> <span class="nn">nlopt</span>
<span class="kn">from</span> <span class="nn">autograd</span> <span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">npa</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">HERE</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"08"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">20260815</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- (1) units &amp; parameters: identical to post 07
</span><span class="n">wl</span> <span class="o">=</span> <span class="mf">1.55</span>
<span class="n">fcen</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">wl</span>
<span class="n">fwidth</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">Si</span><span class="p">,</span> <span class="n">SiO2</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">3.45</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="mf">1.45</span><span class="p">)</span>
<span class="n">N_SEC</span><span class="p">,</span> <span class="n">LA</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="mf">0.45</span>
<span class="n">LAMBDA</span> <span class="o">=</span> <span class="n">N_SEC</span> <span class="o">*</span> <span class="n">LA</span>
<span class="n">THETA_D</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arcsin</span><span class="p">(</span><span class="n">wl</span> <span class="o">/</span> <span class="n">LAMBDA</span><span class="p">)))</span>
<span class="n">H</span> <span class="o">=</span> <span class="mf">0.9</span>
<span class="n">RES</span> <span class="o">=</span> <span class="mi">40</span>
<span class="n">DPML</span><span class="p">,</span> <span class="n">DSUB</span><span class="p">,</span> <span class="n">DAIR</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span>
<span class="n">SY</span> <span class="o">=</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="n">DAIR</span> <span class="o">+</span> <span class="n">DPML</span>
<span class="n">Y_BOT</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SY</span>
<span class="n">Y_DEV</span> <span class="o">=</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span>
<span class="n">SRC_Y</span> <span class="o">=</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.3</span>
<span class="n">MON_Y</span> <span class="o">=</span> <span class="o">-</span><span class="n">Y_BOT</span> <span class="o">-</span> <span class="n">DPML</span> <span class="o">-</span> <span class="mf">0.3</span>
<span class="n">BLAZED_BOUND</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">N_SEC</span><span class="p">))</span> <span class="o">**</span> <span class="mi">2</span>
<span class="n">EXTENT</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="n">Y_BOT</span><span class="p">,</span> <span class="o">-</span><span class="n">Y_BOT</span><span class="p">]</span>

<span class="c1"># baseline widths: post-07 library design (read from its result.json if present)
</span><span class="k">try</span><span class="p">:</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"07"</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">))</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">W_LIB</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)[</span><span class="s">"design"</span><span class="p">][</span><span class="s">"widths"</span><span class="p">])</span>
<span class="k">except</span> <span class="nb">Exception</span><span class="p">:</span>
    <span class="n">W_LIB</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mf">0.075</span><span class="p">,</span> <span class="mf">0.100</span><span class="p">,</span> <span class="mf">0.175</span><span class="p">,</span> <span class="mf">0.225</span><span class="p">])</span>

<span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fwidth</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">SRC_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>
<span class="n">common</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">SY</span><span class="p">),</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span>
              <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">thickness</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">direction</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span> <span class="n">k_point</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">())</span>
<span class="n">stop_cond</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="mf">1e-7</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- (2) geometry: substrate + a 1D MaterialGrid design region
</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">round</span><span class="p">(</span><span class="n">RES</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">))</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span>
<span class="n">x_grid</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="n">Nx</span><span class="p">)</span>
<span class="n">design_variables</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">MaterialGrid</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">,</span> <span class="n">Si</span><span class="p">,</span> <span class="n">grid_type</span><span class="o">=</span><span class="s">"U_MEAN"</span><span class="p">,</span> <span class="n">do_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>   <span class="c1"># contract 1
</span><span class="n">design_region</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">DesignRegion</span><span class="p">(</span><span class="n">design_variables</span><span class="p">,</span> <span class="n">volume</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">H</span><span class="p">)))</span>
<span class="n">x_baseline</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">Nx</span><span class="p">)</span>
<span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">w</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">W_LIB</span><span class="p">):</span>
    <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">LA</span>
    <span class="n">x_baseline</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">x_grid</span> <span class="o">-</span> <span class="n">xj</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">w</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span>


<span class="k">def</span> <span class="nf">geometry_with</span><span class="p">(</span><span class="n">weights</span><span class="p">):</span>
    <span class="n">grid</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">MaterialGrid</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">,</span> <span class="n">Si</span><span class="p">,</span> <span class="n">weights</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">weights</span><span class="p">).</span><span class="n">reshape</span><span class="p">(</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span><span class="p">),</span> <span class="n">grid_type</span><span class="o">=</span><span class="s">"U_MEAN"</span><span class="p">,</span> <span class="n">do_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">center</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">size</span><span class="p">,</span> <span class="n">material</span><span class="o">=</span><span class="n">grid</span><span class="p">)]</span>


<span class="n">geometry</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">),</span>
            <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">center</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="n">design_region</span><span class="p">.</span><span class="n">size</span><span class="p">,</span> <span class="n">material</span><span class="o">=</span><span class="n">design_variables</span><span class="p">)]</span>

<span class="c1"># ---------------------------------------------------------------- (4) simulation + (5) objective: +1 order amplitude
</span><span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry</span><span class="p">,</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
<span class="n">kdiff</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">fcen</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">-</span> <span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">LAMBDA</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">))</span>      <span class="c1"># +1 order direction
</span><span class="n">emc</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">EigenmodeCoefficient</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span> <span class="n">mode</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
                               <span class="n">eig_parity</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">ODD_Z</span><span class="p">,</span> <span class="n">kpoint_func</span><span class="o">=</span><span class="k">lambda</span> <span class="o">*</span><span class="n">_</span><span class="p">:</span> <span class="n">kdiff</span><span class="p">,</span>
                               <span class="n">eig_vol</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">RES</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
<span class="n">opt</span> <span class="o">=</span> <span class="n">mpa</span><span class="p">.</span><span class="n">OptimizationProblem</span><span class="p">(</span><span class="n">simulation</span><span class="o">=</span><span class="n">sim</span><span class="p">,</span> <span class="n">objective_functions</span><span class="o">=</span><span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">npa</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span><span class="p">,</span> <span class="n">objective_arguments</span><span class="o">=</span><span class="p">[</span><span class="n">emc</span><span class="p">],</span>
                              <span class="n">design_regions</span><span class="o">=</span><span class="p">[</span><span class="n">design_region</span><span class="p">],</span> <span class="n">fcen</span><span class="o">=</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">nf</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">decay_by</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">)</span>
<span class="n">opt</span><span class="p">.</span><span class="n">update_design</span><span class="p">([</span><span class="n">x_baseline</span><span class="p">])</span>
<span class="n">annotated_layout</span><span class="p">(</span>
    <span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.2</span><span class="p">,</span> <span class="mf">7.0</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span>
    <span class="n">title</span><span class="o">=</span><span class="s">"supercell: 1D design region (73 px) replaces the bars"</span><span class="p">,</span>
    <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="n">wl</span><span class="si">}</span><span class="s"> res=</span><span class="si">{</span><span class="n">RES</span><span class="si">}</span><span class="se">\n</span><span class="s">Lambda=</span><span class="si">{</span><span class="n">LAMBDA</span><span class="si">}</span><span class="s"> H=</span><span class="si">{</span><span class="n">H</span><span class="si">}</span><span class="se">\n</span><span class="s">Nx=</span><span class="si">{</span><span class="n">Nx</span><span class="si">}</span><span class="s"> (25 nm px)"</span><span class="p">,</span>
    <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="mf">2.35</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">Y_BOT</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">decay_text_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">1.75</span><span class="p">),</span>
    <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"design region: MaterialGrid, baseline = library bars"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">Y_DEV</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="mf">1.25</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"plane wave in SiO2"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">SRC_Y</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="n">SRC_Y</span> <span class="o">-</span> <span class="mf">0.35</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
            <span class="n">Label</span><span class="p">(</span><span class="s">"objective: |a_+1|^2 on this line"</span><span class="p">,</span> <span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">0.85</span><span class="p">,</span> <span class="n">MON_Y</span> <span class="o">+</span> <span class="mf">0.35</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
<span class="n">source_figure</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1000.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">run_dft_field</span><span class="p">(</span><span class="n">src_list</span><span class="p">,</span> <span class="n">geometry_list</span><span class="p">):</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_list</span><span class="p">,</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="nb">dict</span><span class="p">(</span><span class="n">common</span><span class="p">,</span> <span class="n">sources</span><span class="o">=</span><span class="n">src_list</span><span class="p">))</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">SY</span><span class="p">))</span>
    <span class="n">s</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_cond</span><span class="p">)</span>
    <span class="n">field</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">eps</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_epsilon</span><span class="p">();</span> <span class="n">s</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">field</span><span class="p">,</span> <span class="n">eps</span>


<span class="c1"># ---------------------------------------------------------------- source check + input flux (empty substrate)
</span><span class="n">sim_ref</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">default_material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
<span class="n">fl</span> <span class="o">=</span> <span class="n">sim_ref</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
<span class="n">dft_ref</span> <span class="o">=</span> <span class="n">sim_ref</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">SY</span><span class="p">))</span>
<span class="n">sim_ref</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_cond</span><span class="p">)</span>
<span class="n">input_flux</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">fl</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">field_ref</span> <span class="o">=</span> <span class="n">sim_ref</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft_ref</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">sim_ref</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
<span class="n">row</span> <span class="o">=</span> <span class="n">field_ref</span><span class="p">[:,</span> <span class="n">field_ref</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">//</span> <span class="mi">2</span><span class="p">]</span>
<span class="n">phase_spread</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">ptp</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">row</span><span class="p">))))</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"source check: input_flux = </span><span class="si">{</span><span class="n">input_flux</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">e</span><span class="si">}</span><span class="s">, phase spread across x at mid-height = </span><span class="si">{</span><span class="n">phase_spread</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> rad (</span><span class="si">{</span><span class="s">'normal incidence'</span> <span class="k">if</span> <span class="n">phase_spread</span> <span class="o">&lt;</span> <span class="mf">0.2</span> <span class="k">else</span> <span class="s">'TILTED'</span><span class="si">}</span><span class="s">)"</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">fom</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
    <span class="s">"""+1 order efficiency = |a_+1|^2 / input_flux (and its gradient w.r.t. the 73 densities)."""</span>
    <span class="n">f</span><span class="p">,</span> <span class="n">dJ</span> <span class="o">=</span> <span class="n">opt</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)],</span> <span class="n">need_gradient</span><span class="o">=</span><span class="n">need_gradient</span><span class="p">)</span>
    <span class="n">f</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">f</span><span class="p">).</span><span class="n">squeeze</span><span class="p">()))</span> <span class="o">/</span> <span class="n">input_flux</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">need_gradient</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">f</span>
    <span class="k">return</span> <span class="n">f</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">squeeze</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">dJ</span><span class="p">))</span> <span class="o">/</span> <span class="n">input_flux</span>


<span class="c1"># ---------------------------------------------------------------- forward fields: baseline vs random start; adjoint field
</span><span class="n">field_fwd</span><span class="p">,</span> <span class="n">eps_fwd</span> <span class="o">=</span> <span class="n">run_dft_field</span><span class="p">(</span><span class="n">sources</span><span class="p">,</span> <span class="n">geometry_with</span><span class="p">(</span><span class="n">x_baseline</span><span class="p">))</span>
<span class="n">f_baseline</span><span class="p">,</span> <span class="n">g_baseline</span> <span class="o">=</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_baseline</span><span class="p">,</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">x_random</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">rand</span><span class="p">(</span><span class="n">Nx</span><span class="p">)</span>
<span class="n">field_rand</span><span class="p">,</span> <span class="n">eps_rand</span> <span class="o">=</span> <span class="n">run_dft_field</span><span class="p">(</span><span class="n">sources</span><span class="p">,</span> <span class="n">geometry_with</span><span class="p">(</span><span class="n">x_random</span><span class="p">))</span>
<span class="n">f_random</span> <span class="o">=</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_random</span><span class="p">)</span>
<span class="n">adjoint_sources</span> <span class="o">=</span> <span class="n">opt</span><span class="p">.</span><span class="n">adjoint_sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">field_adj</span><span class="p">,</span> <span class="n">eps_adj</span> <span class="o">=</span> <span class="n">run_dft_field</span><span class="p">(</span><span class="n">adjoint_sources</span><span class="p">,</span> <span class="n">geometry_with</span><span class="p">(</span><span class="n">x_baseline</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"forward: baseline +1 efficiency = </span><span class="si">{</span><span class="n">f_baseline</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (|grad| = </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_baseline</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">e</span><span class="si">}</span><span class="s">); random grayscale start = </span><span class="si">{</span><span class="n">f_random</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; "</span>
      <span class="sa">f</span><span class="s">"adjoint sources: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">adjoint_sources</span><span class="p">)</span><span class="si">}</span><span class="s"> x </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">adjoint_sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="n">__name__</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">xs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXTENT</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">EXTENT</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">eps_fwd</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="n">ys</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXTENT</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">EXTENT</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">eps_fwd</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">10.5</span><span class="p">,</span> <span class="mf">7.2</span><span class="p">))</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_fwd</span><span class="p">)),</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">field_rand</span><span class="p">)))</span>
<span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="p">(</span><span class="n">fld</span><span class="p">,</span> <span class="n">eps</span><span class="p">,</span> <span class="n">ttl</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(((</span><span class="n">field_fwd</span><span class="p">,</span> <span class="n">eps_fwd</span><span class="p">,</span> <span class="sa">f</span><span class="s">"forward, baseline (library bars)  J = </span><span class="si">{</span><span class="n">f_baseline</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">),</span>
                                       <span class="p">(</span><span class="n">field_rand</span><span class="p">,</span> <span class="n">eps_rand</span><span class="p">,</span> <span class="sa">f</span><span class="s">"forward, random grayscale start  J = </span><span class="si">{</span><span class="n">f_random</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">),</span>
                                       <span class="p">(</span><span class="n">field_adj</span><span class="p">,</span> <span class="n">eps_adj</span><span class="p">,</span> <span class="s">"adjoint: source placed at the objective monitor"</span><span class="p">))):</span>
    <span class="n">l</span> <span class="o">=</span> <span class="n">lim</span> <span class="k">if</span> <span class="n">col</span> <span class="o">&lt;</span> <span class="mi">2</span> <span class="k">else</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fld</span><span class="p">)))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">col</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">fld</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">l</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">l</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">col</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fld</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"inferno"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">[:,</span> <span class="n">col</span><span class="p">]:</span>
        <span class="n">a</span><span class="p">.</span><span class="n">contour</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">,</span> <span class="n">eps</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="p">[</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">],</span> <span class="n">colors</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.6</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">col</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="n">ttl</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mf">8.5</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"Re(Ez)  y [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"|Ez|  y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"the field follows the design; the adjoint field flows from the monitor back down"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_fields.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- raw gradient
</span><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mf">4.8</span><span class="p">),</span> <span class="n">sharex</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="n">g_baseline</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:purple"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">g_baseline</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="n">g_baseline</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:red"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.25</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"increase density here"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">g_baseline</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="n">g_baseline</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.25</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"decrease density here"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"dJ / d(density)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"raw adjoint gradient at the baseline (no filtering)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"upper right"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">step</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="n">x_baseline</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x_baseline</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.35</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"density (0 = air, 1 = Si)"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.05</span><span class="p">,</span> <span class="mf">1.15</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"current design"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">N_SEC</span><span class="p">):</span>
        <span class="n">a</span><span class="p">.</span><span class="n">axvline</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">LAMBDA</span> <span class="o">+</span> <span class="n">j</span> <span class="o">*</span> <span class="n">LA</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">":"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_gradient.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
<span class="n">top</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argsort</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">g_baseline</span><span class="p">))[::</span><span class="o">-</span><span class="mi">1</span><span class="p">][:</span><span class="mi">5</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="s">"gradient: largest 5 |dJ/drho| at x = "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">x_grid</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="n">g_baseline</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">, rho=</span><span class="si">{</span><span class="n">x_baseline</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">)"</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">top</span><span class="p">))</span>

<span class="c1"># ---------------------------------------------------------------- contract 2: gradient gate (interior point, gradient direction)
</span><span class="n">x_gate</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x_baseline</span><span class="p">,</span> <span class="mf">0.02</span><span class="p">,</span> <span class="mf">0.98</span><span class="p">)</span>
<span class="n">f_gate</span><span class="p">,</span> <span class="n">g_gate</span> <span class="o">=</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_gate</span><span class="p">,</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">g_gate</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_gate</span><span class="p">)</span>
<span class="n">adjoint_dd</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">g_gate</span><span class="p">,</span> <span class="n">v</span><span class="p">))</span>
<span class="n">steps</span> <span class="o">=</span> <span class="p">[</span><span class="mf">2e-3</span><span class="p">,</span> <span class="mf">5e-3</span><span class="p">,</span> <span class="mf">1e-2</span><span class="p">]</span>
<span class="n">gate_rows</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">step</span> <span class="ow">in</span> <span class="n">steps</span><span class="p">:</span>
    <span class="n">fd</span> <span class="o">=</span> <span class="p">(</span><span class="n">fom</span><span class="p">(</span><span class="n">x_gate</span> <span class="o">+</span> <span class="n">step</span> <span class="o">*</span> <span class="n">v</span><span class="p">)</span> <span class="o">-</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_gate</span> <span class="o">-</span> <span class="n">step</span> <span class="o">*</span> <span class="n">v</span><span class="p">))</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">step</span><span class="p">)</span>
    <span class="n">rel</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">adjoint_dd</span> <span class="o">-</span> <span class="n">fd</span><span class="p">)</span> <span class="o">/</span> <span class="nb">max</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">fd</span><span class="p">),</span> <span class="mf">1e-30</span><span class="p">)</span>
    <span class="n">gate_rows</span><span class="p">.</span><span class="n">append</span><span class="p">({</span><span class="s">"step"</span><span class="p">:</span> <span class="n">step</span><span class="p">,</span> <span class="s">"fd"</span><span class="p">:</span> <span class="n">fd</span><span class="p">,</span> <span class="s">"adjoint"</span><span class="p">:</span> <span class="n">adjoint_dd</span><span class="p">,</span> <span class="s">"rel_err"</span><span class="p">:</span> <span class="n">rel</span><span class="p">,</span> <span class="s">"pass"</span><span class="p">:</span> <span class="nb">bool</span><span class="p">(</span><span class="n">rel</span> <span class="o">&lt;=</span> <span class="mf">0.20</span> <span class="ow">and</span> <span class="n">np</span><span class="p">.</span><span class="n">sign</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span> <span class="o">==</span> <span class="n">np</span><span class="p">.</span><span class="n">sign</span><span class="p">(</span><span class="n">adjoint_dd</span><span class="p">))})</span>
<span class="n">gradient_gate</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="s">"pass"</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"gate: interior-point FOM = </span><span class="si">{</span><span class="n">f_gate</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; "</span> <span class="o">+</span> <span class="s">"; "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"step </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'step'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">: FD </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'fd'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s"> vs adjoint </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'adjoint'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">e</span><span class="si">}</span><span class="s">, rel </span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'rel_err'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> </span><span class="si">{</span><span class="s">'PASS'</span> <span class="k">if</span> <span class="n">r</span><span class="p">[</span><span class="s">'pass'</span><span class="p">]</span> <span class="k">else</span> <span class="s">'HOLD'</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">)</span>
      <span class="o">+</span> <span class="sa">f</span><span class="s">" -&gt; gradient gate </span><span class="si">{</span><span class="s">'PASS'</span> <span class="k">if</span> <span class="n">gradient_gate</span> <span class="k">else</span> <span class="s">'HOLD'</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">3.4</span><span class="p">))</span>
<span class="n">idx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">steps</span><span class="p">))</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">r</span><span class="p">[</span><span class="s">"fd"</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:orange"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"centred finite difference"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">adjoint_dd</span><span class="p">]</span> <span class="o">*</span> <span class="mi">3</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"adjoint  g . v"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticklabels</span><span class="p">([</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">s</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">steps</span><span class="p">]);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"finite-difference step"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"directional derivative"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"adjoint vs finite difference along the gradient direction"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">bars</span> <span class="o">=</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="p">[</span><span class="n">r</span><span class="p">[</span><span class="s">"rel_err"</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="p">[</span><span class="s">"tab:green"</span> <span class="k">if</span> <span class="n">r</span><span class="p">[</span><span class="s">"pass"</span><span class="p">]</span> <span class="k">else</span> <span class="s">"tab:red"</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">gate_rows</span><span class="p">])</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="mf">0.20</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"gate: 20 %"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">b</span><span class="p">,</span> <span class="n">r</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">bars</span><span class="p">,</span> <span class="n">gate_rows</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">get_x</span><span class="p">()</span> <span class="o">+</span> <span class="n">b</span><span class="p">.</span><span class="n">get_width</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">r</span><span class="p">[</span><span class="s">"rel_err"</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.004</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'rel_err'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xticklabels</span><span class="p">([</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">s</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">steps</span><span class="p">]);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.25</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"relative error"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"gradient gate: </span><span class="si">{</span><span class="s">'PASS'</span> <span class="k">if</span> <span class="n">gradient_gate</span> <span class="k">else</span> <span class="s">'HOLD'</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_gate.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">gradient_gate</span><span class="p">:</span>
    <span class="k">raise</span> <span class="nb">SystemExit</span><span class="p">(</span><span class="s">"gradient gate HOLD: do not interpret optimizer results"</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- one manual step, then MMA (contract 3)
</span><span class="n">direction</span> <span class="o">=</span> <span class="n">g_baseline</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">g_baseline</span><span class="p">)</span>
<span class="n">one_step</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">alpha</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">0.05</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">):</span>
    <span class="n">x_try</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x_baseline</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">direction</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">one_step</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="n">alpha</span><span class="p">,</span> <span class="n">x_try</span><span class="p">,</span> <span class="n">fom</span><span class="p">(</span><span class="n">x_try</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"one manual step: "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"alpha </span><span class="si">{</span><span class="n">a</span><span class="si">}</span><span class="s"> -&gt; </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="n">f</span> <span class="o">-</span> <span class="n">f_baseline</span><span class="si">:</span><span class="o">+</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">)"</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">one_step</span><span class="p">))</span>

<span class="n">history</span><span class="p">,</span> <span class="n">design_history</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>


<span class="k">def</span> <span class="nf">nlopt_objective</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">grad</span><span class="p">):</span>
    <span class="n">f</span><span class="p">,</span> <span class="n">dJ</span> <span class="o">=</span> <span class="n">fom</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">need_gradient</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">grad</span><span class="p">.</span><span class="n">size</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">grad</span><span class="p">[:]</span> <span class="o">=</span> <span class="n">dJ</span>
    <span class="n">history</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">f</span><span class="p">);</span> <span class="n">design_history</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">copy</span><span class="o">=</span><span class="bp">True</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">f</span>


<span class="n">solver</span> <span class="o">=</span> <span class="n">nlopt</span><span class="p">.</span><span class="n">opt</span><span class="p">(</span><span class="n">nlopt</span><span class="p">.</span><span class="n">LD_MMA</span><span class="p">,</span> <span class="n">Nx</span><span class="p">)</span>
<span class="n">solver</span><span class="p">.</span><span class="n">set_lower_bounds</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">Nx</span><span class="p">));</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_upper_bounds</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">ones</span><span class="p">(</span><span class="n">Nx</span><span class="p">))</span>
<span class="n">solver</span><span class="p">.</span><span class="n">set_max_objective</span><span class="p">(</span><span class="n">nlopt_objective</span><span class="p">);</span> <span class="n">solver</span><span class="p">.</span><span class="n">set_maxeval</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">x_optimized</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">solver</span><span class="p">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">x_baseline</span><span class="p">.</span><span class="n">copy</span><span class="p">()),</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">best_k</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">history</span><span class="p">))</span>
<span class="n">x_optimized</span> <span class="o">=</span> <span class="n">design_history</span><span class="p">[</span><span class="n">best_k</span><span class="p">]</span>                         <span class="c1"># keep the best evaluated design (MMA may overshoot)
</span><span class="n">gray</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">((</span><span class="n">x_optimized</span> <span class="o">&gt;</span> <span class="mf">0.02</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">x_optimized</span> <span class="o">&lt;</span> <span class="mf">0.98</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"MMA (maxeval 5): "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"eval </span><span class="si">{</span><span class="n">k</span><span class="o">+</span><span class="mi">1</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">f</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">history</span><span class="p">))</span> <span class="o">+</span> <span class="sa">f</span><span class="s">"; best eval </span><span class="si">{</span><span class="n">best_k</span><span class="o">+</span><span class="mi">1</span><span class="si">}</span><span class="s"> = </span><span class="si">{</span><span class="nb">max</span><span class="p">(</span><span class="n">history</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="nb">max</span><span class="p">(</span><span class="n">history</span><span class="p">)</span><span class="o">/</span><span class="n">history</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">x); grayscale pixels </span><span class="si">{</span><span class="n">gray</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="n">Nx</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mf">6.2</span><span class="p">))</span>
<span class="n">gs</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_gridspec</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="n">height_ratios</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
<span class="n">axs</span> <span class="o">=</span> <span class="p">[</span><span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)]</span>
<span class="n">axs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">step</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="n">x_baseline</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.1</span><span class="p">);</span> <span class="n">axs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x_baseline</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.4</span><span class="p">)</span>
<span class="n">axs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"baseline</span><span class="se">\n</span><span class="s">J = </span><span class="si">{</span><span class="n">f_baseline</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">axs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"density"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">x_try</span><span class="p">,</span> <span class="n">f_try</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">axs</span><span class="p">[</span><span class="mi">1</span><span class="p">:],</span> <span class="n">one_step</span><span class="p">):</span>
    <span class="n">a</span><span class="p">.</span><span class="n">step</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="n">x_try</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.1</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x_try</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:green"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.4</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"one step, alpha = </span><span class="si">{</span><span class="n">alpha</span><span class="si">}</span><span class="se">\n</span><span class="s">J = </span><span class="si">{</span><span class="n">f_try</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">axs</span><span class="p">:</span>
    <span class="n">a</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.05</span><span class="p">,</span> <span class="mf">1.08</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">axh</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">])</span>
<span class="n">axh</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">history</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="n">history</span><span class="p">,</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">);</span> <span class="n">axh</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="n">f_baseline</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"gray"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"baseline"</span><span class="p">)</span>
<span class="n">axh</span><span class="p">.</span><span class="n">set_xticks</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">history</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">));</span> <span class="n">axh</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"MMA evaluation"</span><span class="p">);</span> <span class="n">axh</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"+1 efficiency"</span><span class="p">);</span> <span class="n">axh</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"MMA history"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">axh</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">axh</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">design_history</span><span class="p">)):</span>
    <span class="n">a</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">])</span>
    <span class="n">a</span><span class="p">.</span><span class="n">step</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="n">design_history</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="n">where</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.0</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">design_history</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="n">step</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.4</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"MMA eval </span><span class="si">{</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">  J = </span><span class="si">{</span><span class="n">history</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="o">+</span> <span class="p">(</span><span class="s">"  (kept)"</span> <span class="k">if</span> <span class="n">k</span> <span class="o">==</span> <span class="n">best_k</span> <span class="k">else</span> <span class="s">""</span><span class="p">),</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.05</span><span class="p">,</span> <span class="mf">1.08</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">k</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">a</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"density"</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">])</span>
<span class="n">a</span><span class="p">.</span><span class="n">step</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="n">x_baseline</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"baseline"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">step</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="n">x_optimized</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"optimized"</span><span class="p">)</span>
<span class="n">a</span><span class="p">.</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x_grid</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x_optimized</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="s">"mid"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.05</span><span class="p">,</span> <span class="mf">1.08</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"final vs baseline (</span><span class="si">{</span><span class="n">gray</span><span class="si">}</span><span class="s"> gray px)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"top: one manual gradient step (alpha sweep) and the MMA history; bottom: the design at every MMA evaluation"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_step_mma.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>


<span class="c1"># ---------------------------------------------------------------- contract 4: verification in a fresh simulation
</span><span class="k">def</span> <span class="nf">forward_orders</span><span class="p">(</span><span class="n">weights</span><span class="p">):</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">geometry</span><span class="o">=</span><span class="n">geometry_with</span><span class="p">(</span><span class="n">weights</span><span class="p">),</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">common</span><span class="p">)</span>
    <span class="n">mon</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_mode_monitor</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">ModeRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">MON_Y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">SY</span><span class="p">))</span>
    <span class="n">s</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">stop_cond</span><span class="p">)</span>
    <span class="n">total</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">mon</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">input_flux</span><span class="p">)</span>
    <span class="n">eff</span> <span class="o">=</span> <span class="p">{</span><span class="n">m</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">get_eigenmode_coefficients</span><span class="p">(</span><span class="n">mon</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">DiffractedPlanewave</span><span class="p">((</span><span class="n">m</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)).</span><span class="n">alpha</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">input_flux</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)}</span>
    <span class="n">field</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">eps</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">get_epsilon</span><span class="p">();</span> <span class="n">s</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">eff</span><span class="p">,</span> <span class="n">total</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">eps</span>


<span class="n">report</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">tag</span><span class="p">,</span> <span class="n">weights</span> <span class="ow">in</span> <span class="p">((</span><span class="s">"baseline"</span><span class="p">,</span> <span class="n">x_baseline</span><span class="p">),</span> <span class="p">(</span><span class="s">"optimized"</span><span class="p">,</span> <span class="n">x_optimized</span><span class="p">)):</span>
    <span class="n">eff</span><span class="p">,</span> <span class="n">total</span><span class="p">,</span> <span class="n">fld</span><span class="p">,</span> <span class="n">eps</span> <span class="o">=</span> <span class="n">forward_orders</span><span class="p">(</span><span class="n">weights</span><span class="p">)</span>
    <span class="n">report</span><span class="p">[</span><span class="n">tag</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"orders"</span><span class="p">:</span> <span class="n">eff</span><span class="p">,</span> <span class="s">"sum"</span><span class="p">:</span> <span class="nb">sum</span><span class="p">(</span><span class="n">eff</span><span class="p">.</span><span class="n">values</span><span class="p">()),</span> <span class="s">"T_total"</span><span class="p">:</span> <span class="n">total</span><span class="p">,</span> <span class="s">"field"</span><span class="p">:</span> <span class="n">fld</span><span class="p">,</span> <span class="s">"eps"</span><span class="p">:</span> <span class="n">eps</span><span class="p">}</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"verify [</span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="s">]: m=-1 </span><span class="si">{</span><span class="n">eff</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, m=0 </span><span class="si">{</span><span class="n">eff</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, m=+1 </span><span class="si">{</span><span class="n">eff</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; sum </span><span class="si">{</span><span class="nb">sum</span><span class="p">(</span><span class="n">eff</span><span class="p">.</span><span class="n">values</span><span class="p">())</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> = total </span><span class="si">{</span><span class="n">total</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">; "</span>
          <span class="sa">f</span><span class="s">"+1 / bound = </span><span class="si">{</span><span class="n">eff</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="n">BLAZED_BOUND</span> <span class="o">*</span> <span class="mi">100</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> %"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">4.4</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"width_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">1.4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
<span class="n">ms</span> <span class="o">=</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">report</span><span class="p">[</span><span class="s">"baseline"</span><span class="p">][</span><span class="s">"orders"</span><span class="p">][</span><span class="n">m</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">ms</span><span class="p">],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:gray"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"baseline (post-07 library)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">bar</span><span class="p">(</span><span class="n">idx</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="n">report</span><span class="p">[</span><span class="s">"optimized"</span><span class="p">][</span><span class="s">"orders"</span><span class="p">][</span><span class="n">m</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">ms</span><span class="p">],</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"after MMA (eval </span><span class="si">{</span><span class="n">best_k</span> <span class="o">+</span> <span class="mi">1</span><span class="si">}</span><span class="s">)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="n">BLAZED_BOUND</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s">"--"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"crimson"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"4-level blazed bound </span><span class="si">{</span><span class="n">BLAZED_BOUND</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">ms</span><span class="p">):</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">k</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">report</span><span class="p">[</span><span class="s">"baseline"</span><span class="p">][</span><span class="s">"orders"</span><span class="p">][</span><span class="n">m</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.008</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">report</span><span class="p">[</span><span class="s">'baseline'</span><span class="p">][</span><span class="s">'orders'</span><span class="p">][</span><span class="n">m</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">report</span><span class="p">[</span><span class="s">"optimized"</span><span class="p">][</span><span class="s">"orders"</span><span class="p">][</span><span class="n">m</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.008</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">report</span><span class="p">[</span><span class="s">'optimized'</span><span class="p">][</span><span class="s">'orders'</span><span class="p">][</span><span class="n">m</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xticklabels</span><span class="p">([</span><span class="sa">f</span><span class="s">"m = </span><span class="si">{</span><span class="n">m</span><span class="si">:</span><span class="o">+</span><span class="n">d</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">ms</span><span class="p">]);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"efficiency (fresh forward run)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"contract 4: measured again in a new simulation"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s">"y"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
<span class="n">lim</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">report</span><span class="p">[</span><span class="s">"baseline"</span><span class="p">][</span><span class="s">"field"</span><span class="p">])),</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">report</span><span class="p">[</span><span class="s">"optimized"</span><span class="p">][</span><span class="s">"field"</span><span class="p">])))</span>
<span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">tag</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">:],</span> <span class="p">(</span><span class="s">"baseline"</span><span class="p">,</span> <span class="s">"optimized"</span><span class="p">)):</span>
    <span class="n">fld</span><span class="p">,</span> <span class="n">eps</span> <span class="o">=</span> <span class="n">report</span><span class="p">[</span><span class="n">tag</span><span class="p">][</span><span class="s">"field"</span><span class="p">],</span> <span class="n">report</span><span class="p">[</span><span class="n">tag</span><span class="p">][</span><span class="s">"eps"</span><span class="p">]</span>
    <span class="n">a</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">fld</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXTENT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
    <span class="n">a</span><span class="p">.</span><span class="n">contour</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">,</span> <span class="n">eps</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="p">[</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">],</span> <span class="n">colors</span><span class="o">=</span><span class="s">"w"</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.6</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"Re(Ez), </span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [um]"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [um]"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"06_verify.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- GIF: optimized pattern repeated 5 times, short pulse
</span><span class="n">periods</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">fw_anim</span> <span class="o">=</span> <span class="mf">0.4</span> <span class="o">*</span> <span class="n">fcen</span>
<span class="n">aperture</span> <span class="o">=</span> <span class="n">periods</span> <span class="o">*</span> <span class="n">LAMBDA</span>
<span class="n">sx_a</span> <span class="o">=</span> <span class="n">aperture</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="mf">1.0</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span>
<span class="n">sy_a</span> <span class="o">=</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span> <span class="o">+</span> <span class="n">H</span> <span class="o">+</span> <span class="mf">2.5</span> <span class="o">+</span> <span class="n">DPML</span>
<span class="n">yb</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">sy_a</span>
<span class="n">ydev</span> <span class="o">=</span> <span class="n">yb</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span>
<span class="n">geom_a</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">yb</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">)),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">+</span> <span class="n">DSUB</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">SiO2</span><span class="p">)]</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">periods</span><span class="p">):</span>
    <span class="n">xj</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">aperture</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">LAMBDA</span>
    <span class="n">geom_a</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xj</span><span class="p">,</span> <span class="n">ydev</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">H</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">LAMBDA</span><span class="p">,</span> <span class="n">H</span><span class="p">),</span>
                           <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">MaterialGrid</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">air</span><span class="p">,</span> <span class="n">Si</span><span class="p">,</span> <span class="n">weights</span><span class="o">=</span><span class="n">x_optimized</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">Nx</span><span class="p">,</span> <span class="n">Ny</span><span class="p">),</span> <span class="n">grid_type</span><span class="o">=</span><span class="s">"U_MEAN"</span><span class="p">,</span> <span class="n">do_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">)))</span>
<span class="n">sim_a</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">resolution</span><span class="o">=</span><span class="n">RES</span><span class="p">,</span> <span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx_a</span><span class="p">,</span> <span class="n">sy_a</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)],</span> <span class="n">geometry</span><span class="o">=</span><span class="n">geom_a</span><span class="p">,</span> <span class="n">eps_averaging</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
                      <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">fw_anim</span><span class="p">,</span> <span class="n">is_integrated</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                                         <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">yb</span> <span class="o">+</span> <span class="n">DPML</span> <span class="o">+</span> <span class="mf">0.3</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">aperture</span><span class="p">,</span> <span class="mi">0</span><span class="p">))])</span>
<span class="n">sim_a</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">vol_a</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx_a</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">sy_a</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">))</span>
<span class="n">eps_a</span> <span class="o">=</span> <span class="n">sim_a</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">vol_a</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">ext_a</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="p">(</span><span class="n">sx_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sx_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="n">sy_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sy_a</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">]</span>
<span class="n">t_src</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="n">fw_anim</span>
<span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_a</span><span class="p">,</span> <span class="n">vol_a</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t_src</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">fw_anim</span><span class="p">,</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t_src</span> <span class="o">+</span> <span class="mf">1.2</span> <span class="o">*</span> <span class="n">sy_a</span> <span class="o">*</span> <span class="mf">1.45</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="n">ext_a</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"07_anim_optimized.gif"</span><span class="p">),</span> <span class="n">eps</span><span class="o">=</span><span class="n">eps_a</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">6.4</span><span class="p">,</span> <span class="mf">4.6</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span>
               <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s">"optimized metagrating x</span><span class="si">{</span><span class="n">periods</span><span class="si">}</span><span class="s">: wavefront toward +</span><span class="si">{</span><span class="n">THETA_D</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> deg"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>

<span class="k">if</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">():</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"params"</span><span class="p">:</span> <span class="p">{</span><span class="s">"wl"</span><span class="p">:</span> <span class="n">wl</span><span class="p">,</span> <span class="s">"Lambda"</span><span class="p">:</span> <span class="n">LAMBDA</span><span class="p">,</span> <span class="s">"H"</span><span class="p">:</span> <span class="n">H</span><span class="p">,</span> <span class="s">"theta_d"</span><span class="p">:</span> <span class="n">THETA_D</span><span class="p">,</span> <span class="s">"Nx"</span><span class="p">:</span> <span class="n">Nx</span><span class="p">,</span> <span class="s">"w_lib"</span><span class="p">:</span> <span class="n">W_LIB</span><span class="p">.</span><span class="n">tolist</span><span class="p">()},</span>
                   <span class="s">"input_flux"</span><span class="p">:</span> <span class="n">input_flux</span><span class="p">,</span> <span class="s">"phase_spread"</span><span class="p">:</span> <span class="n">phase_spread</span><span class="p">,</span>
                   <span class="s">"fom"</span><span class="p">:</span> <span class="p">{</span><span class="s">"baseline"</span><span class="p">:</span> <span class="n">f_baseline</span><span class="p">,</span> <span class="s">"random"</span><span class="p">:</span> <span class="n">f_random</span><span class="p">,</span> <span class="s">"gate_point"</span><span class="p">:</span> <span class="n">f_gate</span><span class="p">},</span>
                   <span class="s">"gate"</span><span class="p">:</span> <span class="n">gate_rows</span><span class="p">,</span> <span class="s">"gate_pass"</span><span class="p">:</span> <span class="n">gradient_gate</span><span class="p">,</span>
                   <span class="s">"one_step"</span><span class="p">:</span> <span class="p">[{</span><span class="s">"alpha"</span><span class="p">:</span> <span class="n">a</span><span class="p">,</span> <span class="s">"fom"</span><span class="p">:</span> <span class="n">f</span><span class="p">}</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">one_step</span><span class="p">],</span>
                   <span class="s">"mma"</span><span class="p">:</span> <span class="p">{</span><span class="s">"history"</span><span class="p">:</span> <span class="n">history</span><span class="p">,</span> <span class="s">"best_eval"</span><span class="p">:</span> <span class="n">best_k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"gray_pixels"</span><span class="p">:</span> <span class="n">gray</span><span class="p">},</span>
                   <span class="s">"verify"</span><span class="p">:</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">{</span><span class="s">"orders"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"orders"</span><span class="p">],</span> <span class="s">"sum"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"sum"</span><span class="p">],</span> <span class="s">"T_total"</span><span class="p">:</span> <span class="n">v</span><span class="p">[</span><span class="s">"T_total"</span><span class="p">]}</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">report</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"blazed_bound"</span><span class="p">:</span> <span class="n">BLAZED_BOUND</span><span class="p">,</span> <span class="s">"x_baseline"</span><span class="p">:</span> <span class="n">x_baseline</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"x_optimized"</span><span class="p">:</span> <span class="n">x_optimized</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">,</span> <span class="s">"nlopt"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">nlopt</span><span class="p">.</span><span class="n">version_major</span><span class="p">()</span><span class="si">}</span><span class="s">.</span><span class="si">{</span><span class="n">nlopt</span><span class="p">.</span><span class="n">version_minor</span><span class="p">()</span><span class="si">}</span><span class="s">"</span><span class="p">},</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span></code></pre></figure>

</details>

<details>
  <summary>원본 실행 기록과 재현 환경</summary>

  <p>§4의 발췌 코드와 달리 전체 코드에는 그림 저장·GIF 녹화·result.json 기록이 들어 있다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

  <p><strong>실행 결과 (2026-10-23 실행)</strong>:</p>
  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>source check: input_flux = 1.86866e+01, phase spread across x at mid-height = 0.0000 rad (normal incidence)
forward: baseline +1 efficiency = 0.4970 (|grad| = 6.037e-01); random grayscale start = 0.0177; adjoint sources: 1 x EigenModeSource
gradient: largest 5 |dJ/drho| at x = -0.275 (+0.157, rho=0), -0.250 (+0.208, rho=1), -0.225 (+0.232, rho=1), -0.200 (+0.215, rho=1), -0.175 (+0.165, rho=0)
gate: interior-point FOM = 0.4871; step 2e-03: FD 5.4104e-01 vs adjoint 5.4472e-01, rel 0.0068 PASS; step 5e-03: FD 5.4538e-01 vs adjoint 5.4472e-01, rel 0.0012 PASS; step 1e-02: FD 5.4505e-01 vs adjoint 5.4472e-01, rel 0.0006 PASS -&gt; gradient gate PASS
one manual step: alpha 0.05 -&gt; 0.5075 (+0.0105), alpha 0.3 -&gt; 0.5549 (+0.0579), alpha 0.8 -&gt; 0.6134 (+0.1163), alpha 2.0 -&gt; 0.4840 (-0.0130)
MMA (maxeval 5): eval 1: 0.4970, eval 2: 0.5248, eval 3: 0.6241, eval 4: 0.0492, eval 5: 0.5398; best eval 3 = 0.6241 (1.256x); grayscale pixels 27/73
verify [baseline]: m=-1 0.1026, m=0 0.0666, m=+1 0.4959; sum 0.6651 = total 0.6651; +1 / bound = 61.2 %
verify [optimized]: m=-1 0.0973, m=0 0.0169, m=+1 0.6228; sum 0.7369 = total 0.7369; +1 / bound = 76.8 %
</code></pre></div>  </div>

  <p><strong>재현 환경</strong>: meep 1.33.0 · nlopt 2.x · autograd · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep nlopt autograd</code> · 실행 <code class="language-plaintext highlighter-rouge">python metagrating_inverse.py</code> (약 48 s, 단일 코어)</p>

</details>

<h3 id="공식-문서와-다음-글">공식 문서와 다음 글</h3>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Adjoint_Solver/">공식 Adjoint Solver 튜토리얼</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/adjoint_optimization/01-Introduction.ipynb">adjoint 예제 01 Introduction</a></li>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#materialgrid"><code class="language-plaintext highlighter-rouge">MaterialGrid</code> 레퍼런스</a> · <a href="https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/#mma-method-of-moving-asymptotes-and-ccsa">NLopt MMA</a></li>
  <li>이전 글: <a href="/meep-examples/meta-atom/">07 · Metalens의 meta-atom과 phase library</a> · 다음 글: <a href="/meep-examples/bend-inverse/">09 · Waveguide bend inverse design</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="adjoint" /><category term="inverse-design" /><category term="metagrating" /><category term="nlopt" /><category term="mma" /><summary type="html"><![CDATA[the post-07 library design (four Si bars) becomes the starting point of an adjoint optimisation. The whole supercell period is a 1D design region of 73 density pixels; the objective is the +1-order efficiency. Four steps are enforced: differentiable materials, a finite-difference gate on the gradient, a short MMA run, and a fresh-simulation verification.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/08/06_verify.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/08/06_verify.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 12 · 빛을 가두는 고리 — Harminv, Q, FSR, solve_cw 교차검증</title><link href="https://jin-castle.github.io/meep-examples/ring-resonator/" rel="alternate" type="text/html" title="Meep Example 12 · 빛을 가두는 고리 — Harminv, Q, FSR, solve_cw 교차검증" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/ring-resonator</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/ring-resonator/"><![CDATA[<h2 id="observe">1. 먼저 관찰하기</h2>

<p>고리에 짧은 펄스를 넣었다가 끄면 빛은 바로 사라질까요? 아래 영상에서 <strong>고리를 도는 울림과 바깥으로 새는 빛</strong>을 찾아보세요. 11편의 두 거울 대신, 이번에는 유전체 도파로를 둥글게 말아 빛을 가둡니다.</p>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/12/05_anim_ring.gif" data-lightbox=""><img src="/meep-examples/assets/meep/12/05_anim_ring.gif" data-animation-src="/meep-examples/assets/meep/12/05_anim_ring.gif" data-static-src="/meep-examples/assets/meep/12/03_modes.png" alt="광대역 펄스 뒤 고리에서 울리는 전기장과 바깥으로 새는 빛" loading="eager" /></a>
  <figcaption>펄스가 꺼진 뒤에도 세 모드가 함께 울려 맥놀이가 보입니다. 낮은 모드부터 PML 쪽으로 새어 나갑니다.</figcaption>
  <button type="button" class="animation-toggle" hidden="">애니메이션 정지</button>
</figure>

<p><strong>이번 질문:</strong> 어떤 주파수의 빛이 남고, 얼마나 오래 남으며, 그 답을 어떻게 검증할까요? 아래 측정은 <strong>2D Ez·손실 없는 고립 고리</strong>의 결과입니다. 도파로와의 결합 손실이나 3D 소자의 Q를 포함하지 않습니다.</p>

<details>
  <summary>English summary</summary>

  <ul>
    <li><strong>What</strong>: post 11 measured how much a dipole emits between two mirrors. On a chip the trap is a dielectric ring. This post asks the first questions about any resonator: at which frequencies does it trap light, for how long (Q), how far apart are the resonances (FSR), and what does each trapped mode look like. Official <code class="language-plaintext highlighter-rouge">ring.py</code> (Harminv on the ringing field), one narrow-band run per mode, and official <code class="language-plaintext highlighter-rouge">solve-cw.py</code> (the same mode solved in the frequency domain).</li>
    <li>
      <table>
        <tbody>
          <tr>
            <td><strong>Result</strong>: a broadband pulse in the band 0.10–0.20 excites three Ez modes; at the official resolution 10 Harminv gives f = 0.1181 / 0.1472 / 0.1753 with Q = 81 / 317 / 1675 (tutorial: 0.1181 / 0.1472 / 0.1752, Q 81 / 316 / 1677). The frequencies move by less than 0.3% between resolution 10 and 30; the Q of the sharpest mode goes 1675 → 2132 → 1610, not monotonically. The spacing 0.0292 / 0.0283 matches 1/(n_g L) with n_g = 3.69, and the three modes carry m = 3, 4, 5 wavelengths around the ring. <code class="language-plaintext highlighter-rouge">solve_cw</code> reproduces the time-domain DFT of the f = 0.118 mode to 0.40% relative L2 (</td>
            <td>Ez</td>
            <td>correlation 0.99998) after a complex scale factor.</td>
          </tr>
        </tbody>
      </table>
    </li>
    <li><strong>Takeaway</strong>: Harminv turns 300 time units of ringing into frequencies and Q without waiting for the field to decay, but Q converges much more slowly with resolution than the frequency does. One mode at a time needs a source as narrow as the mode. The frequency-domain solver and the time-domain pulse are two routes to the same steady state, and agreeing to a percent is what “the same mode” means.</li>
    <li><strong>Code</strong>: full script at the bottom, ~4 min (mpirun -np 4).</li>
  </ul>
</details>

<details>
  <summary>공진기는 어디에 쓰일까요?</summary>

  <p>11편의 금속 상자는 구멍 하나로 Q를 조절했다. 칩 위에서는 금속 상자를 쓰지 않는다. 유전체 도파로를 고리로 말면 빛이 전반사로 돌면서 갇히고, 05편에서 본 굽힘 방사가 유일한 손실이 된다. 이 고리에 펄스를 넣으면 어떤 주파수가 남는가, 얼마나 오래 남는가, 남은 주파수들은 얼마나 떨어져 있는가. 그리고 그 답을 어떻게 재는가. 시간영역에서 울림을 분해하는 Harminv와, 주파수 영역에서 정상상태를 직접 푸는 solve_cw 두 가지로 재고 서로 맞는지 본다.</p>

  <h3 id="section">어디에 쓰이는가</h3>

  <p>고리 공진기는 실리콘 포토닉스에서 가장 많이 쓰는 부품이다. 공진 주파수, Q, FSR 세 숫자가 그대로 소자 사양이 된다.</p>

  <p>| 응용 | 이 글의 어떤 것을 쓰는가 | 그 다음에 필요한 것 |
|—|—|—|
| 파장 필터, add-drop 다중화기(WDM), ring 변조기 | 공진 주파수와 FSR(채널 간격), Q(선폭 = 통과 대역) | 30편 GDS ring |
| 바이오·가스 센서 | 공진 이동 Δf를 선폭 f/Q로 나눈 것이 검출 한계 | 13편 디스크 공진기 |
| microring·microdisk 레이저, 주파수 빗(comb) | Q와 모드 부피(threshold), FSR(빗 간격) | 22편 비선형 |
| 모든 공진 구조의 측정 절차 | Harminv로 f·Q, 좁은 대역으로 모드 하나, solve_cw로 정상상태 | 26편 photonic crystal cavity |</p>
</details>

<h2 id="predict">2. 결과를 예측해 보기</h2>

<p>해상도를 10 → 20 → 30으로 높이면 <strong>주파수와 Q가 함께 매끄럽게 수렴할까요?</strong> 먼저 골라보세요.</p>

<fieldset class="prediction">
<legend>해상도를 높였을 때 두 숫자의 수렴을 예상해 보세요.</legend>
<label><input type="radio" name="ring-prediction" value="together" /> 주파수가 안정되면 Q도 비슷한 비율로 안정된다.</label>
<label><input type="radio" name="ring-prediction" value="different" /> 주파수가 안정되어도 Q는 크게 움직일 수 있다.</label>
</fieldset>

<details>
  <summary>예측 확인하기</summary>

  <p><strong>두 번째입니다.</strong> 세 번째 모드의 주파수는 0.17525 → 0.17564 → 0.17572지만, Q는 1675 → 2132 → 1610입니다. Q는 작은 방사 손실을 재므로 경계를 격자로 표현하는 방식에 더 민감합니다. 뒤에서 이 차이를 실제 표로 확인합니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기</h2>

<figure class="lesson-figure">
<svg viewBox="0 0 300 245" role="img" aria-labelledby="ring-principle-title ring-principle-desc" xmlns="http://www.w3.org/2000/svg">
  <title id="ring-principle-title">고리 공진의 원리</title>
  <desc id="ring-principle-desc">고리를 한 바퀴 돈 파동이 같은 위상으로 만나면 보강됩니다. 바깥으로 새는 빛이 울림의 수명을 제한합니다.</desc>
  <rect width="300" height="245" rx="12" fill="#f1f7f8" />
  <circle cx="144" cy="115" r="70" fill="none" stroke="#d5e5e9" stroke-width="34" />
  <circle cx="144" cy="115" r="70" fill="none" stroke="#157c8c" stroke-width="3" stroke-dasharray="9 5" />
  <path d="M144 45 A70 70 0 0 1 214 115" fill="none" stroke="#157c8c" stroke-width="5" />
  <path d="M205 105 L214 121 L222 104" fill="none" stroke="#157c8c" stroke-width="4" />
  <circle cx="214" cy="115" r="6" fill="#bb4f39" />
  <path d="M213 65 L249 38 M242 39 L250 37 L248 46" fill="none" stroke="#bb4f39" stroke-width="2.5" />
  <text x="144" y="108" text-anchor="middle" font-size="17" fill="#183744">한 바퀴 뒤</text>
  <text x="144" y="131" text-anchor="middle" font-size="17" fill="#183744">위상이 맞으면 보강</text>
  <text x="210" y="25" font-size="16" fill="#8c3d2e">방사 손실</text>
  <text x="144" y="222" text-anchor="middle" font-size="16" fill="#183744">둘레 L에 파장이 m개 들어가는 공진</text>
</svg>
<figcaption>원리 개념도입니다. 점선은 빛의 왕복 경로를, 화살표는 진행과 누설을 뜻합니다. 실제 전기장 분포나 손실 크기를 그린 그림은 아닙니다.</figcaption>
</figure>

<p>고리를 한 바퀴 돌아온 파동이 같은 위상으로 만나면 보강됩니다. 그래서 아무 주파수나 남는 것이 아니라, 둘레에 맞는 <strong>공진 주파수</strong>만 남습니다. <strong>Q</strong>는 그 울림이 얼마나 천천히 사라지는지, <strong>FSR</strong>은 이웃한 공진 주파수가 얼마나 떨어져 있는지를 말합니다.</p>

<p><code class="language-plaintext highlighter-rouge">Harminv</code>는 <strong>source가 꺼진 뒤 한 점에 남는 신호</strong>에서 주파수와 감쇠율을 함께 찾습니다. Q가 크다고 감쇠가 끝날 때까지 기다릴 필요는 없지만, 추정 오차를 확인해야 합니다. <strong>양의 Q·관측 대역 안의 모드</strong>와 <code class="language-plaintext highlighter-rouge">error &lt; f/(2Q)</code>가 기본 조건이며, 이 글의 세 모드는 error가 그 기준의 2% 아래입니다.</p>

<details>
  <summary>공진 식·기호와 정량 예측 자세히 보기</summary>

  <p>고리를 한 바퀴 돈 빛의 위상이 자기 자신과 맞을 때만 보강된다. 둘레 $L=2\pi R_{\mathrm{mid}}$에 파장이 정수 $m$개 들어가는 조건이 공진이고, 이웃한 $m$ 사이의 주파수 간격이 FSR이다. 군굴절률 $n_g$는 분산을 포함한 값이라 재료 굴절률과 다르다. 손실이 굽힘 방사뿐이면 주파수가 높을수록 빛이 고리 안쪽에 더 단단히 갇혀 Q가 커진다.</p>

\[m\,\lambda_m = n_{\mathrm{eff}}L,\qquad \mathrm{FSR}=f_{m+1}-f_m\approx\frac{1}{n_g L},\qquad
Q=\frac{f}{\Delta f}=\frac{\mathrm{Re}\,\omega}{-2\,\mathrm{Im}\,\omega}\]

  <p>Harminv는 source가 꺼진 뒤 한 점에서 기록한 field를 감쇠 사인파의 합 $\sum_k a_k e^{-i\omega_k t}$로 분해한다. 복소 $\omega_k$의 실수부가 공진 주파수, 허수부가 감쇠율이고 둘의 비가 Q다. 수명이 수천 time unit인 모드도 300 time unit의 기록으로 잡히지만, 각 모드에 붙는 <code class="language-plaintext highlighter-rouge">error</code>가 허수부보다 작아야 그 Q를 믿을 수 있다.</p>

  <p>주파수 영역 solver는 같은 문제를 다르게 푼다. 연속파 source를 켜고 $\nabla\times\nabla\times\mathbf E-\omega^2\varepsilon\mathbf E=i\omega\mathbf J$를 반복법(BiCGSTAB-L)으로 풀어 정상상태를 바로 얻는다. 시간영역의 펄스 + DFT와 같은 모드를 주어야 하지만 source 정규화와 전체 위상이 다르므로 복소 상수 하나를 맞춘 뒤 비교한다.</p>

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$R$, $w$, $n$</td>
        <td>안쪽 반지름 1, 폭 1, 굴절률 3.4 (단위 a = 1 µm)</td>
        <td><code class="language-plaintext highlighter-rouge">R</code>, <code class="language-plaintext highlighter-rouge">W</code>, <code class="language-plaintext highlighter-rouge">N_RING</code></td>
      </tr>
      <tr>
        <td>$L$</td>
        <td>평균 둘레 $2\pi(R+w/2)$ = 9.42</td>
        <td><code class="language-plaintext highlighter-rouge">L_RING</code></td>
      </tr>
      <tr>
        <td>$f_{\mathrm{cen}}$, $df$</td>
        <td>광대역 펄스 0.15 ± 0.05</td>
        <td><code class="language-plaintext highlighter-rouge">FCEN</code>, <code class="language-plaintext highlighter-rouge">DF</code></td>
      </tr>
      <tr>
        <td>$m$</td>
        <td>방위 차수(둘레의 파장 수)</td>
        <td><code class="language-plaintext highlighter-rouge">m_az</code></td>
      </tr>
      <tr>
        <td>$Q$, error</td>
        <td>Harminv 출력</td>
        <td><code class="language-plaintext highlighter-rouge">h.modes[k].Q</code>, <code class="language-plaintext highlighter-rouge">.err</code></td>
      </tr>
      <tr>
        <td>tol</td>
        <td>solve_cw 반복 종료 기준</td>
        <td><code class="language-plaintext highlighter-rouge">TOLS</code></td>
      </tr>
      <tr>
        <td>$\alpha$</td>
        <td>CW와 DFT를 맞추는 복소 상수</td>
        <td><code class="language-plaintext highlighter-rouge">alpha</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 2D Ez, 손실 없는 유전체, 단위 a = 1 µm(공진 파장 5.7~8.5 µm). 통신 파장으로 옮기려면 모든 길이에 0.27을 곱한다. 고리가 도파로와 결합하지 않은 고립 고리라 Q는 굽힘 방사만 반영한다.</p>

  <h3 id="section-1">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>대역 0.10~0.20의 모드 수</td>
        <td>3</td>
        <td>FSR ≈ 1/(3.5 × 9.42) ≈ 0.03, 대역 0.1</td>
      </tr>
      <tr>
        <td>공진 주파수 (res 10)</td>
        <td>0.118 / 0.147 / 0.175</td>
        <td>공식 튜토리얼</td>
      </tr>
      <tr>
        <td>Q의 경향</td>
        <td>고주파일수록 크다</td>
        <td>굽힘 방사는 느슨한 구속에서 크다</td>
      </tr>
      <tr>
        <td>res 10 → 30의 주파수 변화</td>
        <td>1% 안</td>
        <td>파장당 20칸 이상</td>
      </tr>
      <tr>
        <td>res 10 → 30의 최고 Q 변화</td>
        <td>수십 %</td>
        <td>노트: res 25에서 2515, 공식 res 10은 1677</td>
      </tr>
      <tr>
        <td>방위 차수 m</td>
        <td>연속 정수 세 개, 3~6 사이</td>
        <td>$m\approx n_{\mathrm{eff}}Lf$, $n_{\mathrm{eff}}&lt;3.4$</td>
      </tr>
      <tr>
        <td>solve_cw 오차</td>
        <td>tolerance를 조이면 단조 감소</td>
        <td>튜토리얼</td>
      </tr>
      <tr>
        <td>CW vs 시간영역 DFT</td>
        <td>L2 2% 안, 상관 0.999 이상</td>
        <td>노트 1.2%, 0.99992</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: FSR이 손계산과 30% 넘게 다르면 둘레나 굴절률을 의심한다. Harminv error가 허수부보다 크면 그 Q는 보고하지 않는다. CW와 DFT가 10% 넘게 다르면 source 대칭이나 주파수가 어긋난 것이다.</p>

</details>

<h2 id="run">4. 변수 하나 바꿔 실험하기</h2>

<p>이번에는 <strong>Harminv가 울림을 관측하는 시간만</strong> 바꿉니다. 저장소의 <code class="language-plaintext highlighter-rouge">code/</code> 폴더에서 공통 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>와 <code class="language-plaintext highlighter-rouge">ring_resonator.py</code>를 함께 두고 Meep 환경에서 실행하세요. 전체 코드는 아래 참고 자료에도 있습니다. 단일 CPU 기준 약 10분이며, 원문의 4분은 4개 MPI 프로세스를 사용한 기록입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">OMP_NUM_THREADS</span><span class="o">=</span>1 python ring_resonator.py
</code></pre></div></div>

<ol>
  <li>원본의 <code class="language-plaintext highlighter-rouge">T_HARMINV = 300.0</code>으로 실행해 각 모드의 f·Q·error를 기록합니다.</li>
  <li>이 값만 <code class="language-plaintext highlighter-rouge">600.0</code>으로 바꾸고 다시 실행합니다. 구조·해상도·source는 고정합니다.</li>
  <li>같은 주파수의 모드를 짝지어 error와 <code class="language-plaintext highlighter-rouge">f/(2Q)</code>를 비교합니다. 관측 시간을 늘리는 실험과 공간 해상도를 높이는 실험은 서로 다른 오차를 확인합니다.</li>
</ol>

<p><strong>판단 기준:</strong> 관측 시간을 늘린 뒤 주파수와 Q가 얼마나 움직였는지 직접 기록하세요. 시간이 길어졌다는 이유만으로 Q가 정확하다고 결론 내릴 수는 없습니다. 아래 수치는 원본의 <strong>300 time unit</strong> 결과이며, 600의 새 측정값은 아닙니다.</p>

<details>
  <summary>시뮬레이션 배치와 파라미터 확인하기</summary>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/12/01_layout.png" data-lightbox=""><img src="/meep-examples/assets/meep/12/01_layout.png" alt="고리와 source·Harminv probe·PML의 배치" loading="lazy" /></a>
<figcaption>16 × 16 셀(a = 1 µm), PML 2. 고리는 n = 3.4, 안쪽 반지름 1, 폭 1입니다. 빨간 점은 Ez 점원이자 Harminv probe(r + 0.1, 0)이며 flux monitor는 없습니다. 원의 번호는 아래 코드의 단계입니다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>고리</td>
        <td>n 3.4, R 1, w 1</td>
        <td>공식 ring.py</td>
        <td>둘레가 바뀌면 FSR이 바뀐다</td>
      </tr>
      <tr>
        <td>펄스</td>
        <td>fcen 0.15, df 0.1</td>
        <td>대역 0.10~0.20에 모드 셋</td>
        <td>대역이 좁으면 모드를 놓친다</td>
      </tr>
      <tr>
        <td>source 위치</td>
        <td>(R + 0.1, 0)</td>
        <td>대칭축에서 비켜 모든 Ez 모드를 여기</td>
        <td>축 위에 두면 odd 모드가 빠진다</td>
      </tr>
      <tr>
        <td>Harminv 창</td>
        <td>source 종료 후 300</td>
        <td>공식 값. Q 수천까지 분해</td>
        <td>너무 짧으면 error가 커진다</td>
      </tr>
      <tr>
        <td>해상도</td>
        <td>10 (공식), 20, 30</td>
        <td>수렴성</td>
        <td>Q가 해상도에 민감(§5)</td>
      </tr>
      <tr>
        <td>모드 영상</td>
        <td>df 0.01, DFT at f_k</td>
        <td>이웃 모드(0.03 떨어짐)를 배제</td>
        <td>df 0.1이면 세 모드가 겹친 그림</td>
      </tr>
      <tr>
        <td>solve_cw</td>
        <td>f 0.118, tol 1e-8/1e-10/1e-12, maxiters 10000, L 10</td>
        <td>공식 solve-cw.py</td>
        <td>L을 기본 2로 두면 수렴이 느리다</td>
      </tr>
      <tr>
        <td>CW source 대칭</td>
        <td>(±(R+0.1), 0)에 진폭 +1/−1, X odd</td>
        <td>0.118 모드의 parity</td>
        <td>parity가 틀리면 다른 모드를 푼다</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/12/00_source.png" data-lightbox=""><img src="/meep-examples/assets/meep/12/00_source.png" alt="광대역 Gaussian 펄스의 시간 파형과 스펙트럼" loading="lazy" /></a>
<figcaption>광대역 펄스의 파형과 스펙트럼(a 단위). 폭 10, 정점 t0 = 50. 300 time unit의 Harminv 창은 source가 꺼진 뒤 시작합니다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 강의 범위 밖이다. 10_sources의 0710 노트는 res 25 한 점, 0722 노트는 solve_cw tolerance 5점이었다. 이 글은 해상도 세 점(10/20/30)으로 주파수와 Q의 수렴 속도 차이를 보이고, 모드마다 좁은 대역으로 다시 돌려 방위 차수 m을 센다.</p>

</details>

<details>
  <summary>코드를 일곱 단계로 따라가기</summary>

  <blockquote>
    <p>읽는 순서: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
이번 글의 ⑤는 flux monitor가 아니라 <code class="language-plaintext highlighter-rouge">Harminv</code>(한 점의 시간 신호)와 <code class="language-plaintext highlighter-rouge">solve_cw</code>다.</p>
  </blockquote>

  <h3 id="section-2">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">N_RING</span><span class="p">,</span> <span class="n">W</span><span class="p">,</span> <span class="n">R</span> <span class="o">=</span> <span class="mf">3.4</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span>                <span class="c1"># index, ring width, inner radius  [a = 1 um]
</span><span class="n">PAD</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">=</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">2.0</span>
<span class="n">SXY</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="n">W</span> <span class="o">+</span> <span class="n">PAD</span> <span class="o">+</span> <span class="n">DPML</span><span class="p">)</span>              <span class="c1"># 16 x 16
</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">DF</span> <span class="o">=</span> <span class="mf">0.15</span><span class="p">,</span> <span class="mf">0.1</span>                        <span class="c1"># broadband pulse covering 0.10..0.20
</span><span class="n">T_HARMINV</span> <span class="o">=</span> <span class="mf">300.0</span>                           <span class="c1"># ringing window after the source (official)
</span><span class="n">L_RING</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">W</span><span class="p">)</span>          <span class="c1"># mean circumference, for the FSR estimate
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 공식 값 그대로. 둘레 $L$은 FSR 손계산용.</li>
    <li><strong>왜</strong>: 실행 전에 $1/(n_g L)$로 모드 수를 어림해 두면 Harminv가 모드를 빠뜨렸는지 바로 안다.</li>
    <li><strong>틀리면</strong>: PML이 고리에 가까우면(pad 작게) 방사장이 흡수되기 전에 되돌아와 Q가 틀어진다.</li>
  </ul>

  <h3 id="section-3">② 재료와 구조 — 두 원기둥으로 고리</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">geometry</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">R</span> <span class="o">+</span> <span class="n">W</span><span class="p">,</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_RING</span><span class="p">)),</span>     <span class="c1"># later objects win: outer dielectric first ...
</span>            <span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">R</span><span class="p">)]</span>                                             <span class="c1"># ... then the air hole
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 유전체 원기둥 위에 공기 원기둥을 덮어 고리를 만든다.</li>
    <li><strong>왜</strong>: Meep은 나중 객체가 앞 객체를 덮어쓴다. 순서가 반대면 유전체 원판이 된다.</li>
    <li><strong>틀리면</strong>: 11편의 금속 상자도 같은 규칙(금속 → 공기 → 구멍)이었다.</li>
  </ul>

  <h3 id="source--------">③ Source — 광대역 하나, 좁은 대역 셋, 연속파 둘</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">DF</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">)</span>                    <span class="c1"># A: broadband, every mode in the band
</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">f0</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.01</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">)</span>                    <span class="c1"># B: one mode at a time
</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">ContinuousSource</span><span class="p">(</span><span class="n">F_CW</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">)),</span>             <span class="c1"># C: continuous wave, antisymmetric pair
</span> <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">ContinuousSource</span><span class="p">(</span><span class="n">F_CW</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">)),</span> <span class="n">amplitude</span><span class="o">=-</span><span class="mi">1</span><span class="p">)]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 목적에 따라 세 가지 source. A는 모든 모드를 한 번에, B는 하나씩, C는 정상상태.</li>
    <li><strong>왜</strong>: 모드 하나를 보려면 이웃 모드(0.03 떨어짐)가 들어오지 않는 대역(0.01)이 필요하다. Harminv의 중심 주파수를 바꾸는 것만으로는 source 스펙트럼이 바뀌지 않는다. 공식 예제 하나(ring-mode-overlap.py)가 바로 그 실수를 하고 Meep이 경고를 낸다.</li>
    <li><strong>틀리면</strong>: 연속파 source 둘의 부호가 같으면 X-even 모드를 풀게 되어 시간영역의 0.118 모드와 맞지 않는다.</li>
  </ul>

  <h3 id="simulation-----field">④ Simulation과 경계 — 대칭과 복소 field</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SXY</span><span class="p">,</span> <span class="n">SXY</span><span class="p">),</span> <span class="n">geometry</span><span class="o">=</span><span class="n">geometry</span><span class="p">,</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">,</span>
                    <span class="n">symmetries</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">)],</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)])</span>                                   <span class="c1"># A, B
</span><span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">RES_IMG</span><span class="p">,</span> <span class="n">src_cw</span><span class="p">,</span> <span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">phase</span><span class="o">=+</span><span class="mi">1</span><span class="p">)),</span> <span class="n">force_complex_fields</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>  <span class="c1"># C
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 사방 PML 2. A·B는 Y 거울 대칭(source가 x축 위), C는 X odd + Y even과 복소 field.</li>
    <li><strong>왜</strong>: <code class="language-plaintext highlighter-rouge">solve_cw</code>는 정상상태의 진폭과 위상을 함께 주므로 복소 field가 필요하다. 대칭은 계산을 1/2, 1/4로 줄이고 모드의 parity를 고른다.</li>
    <li><strong>틀리면</strong>: 11편과 같은 규칙. 위상을 전부 +1로 두면 다른 parity의 모드를 푼다.</li>
  </ul>

  <h3 id="monitor--harminv-dft--solvecw">⑤ Monitor — Harminv와 DFT, 그리고 solve_cw</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">h</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Harminv</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">,</span> <span class="n">FCEN</span><span class="p">,</span> <span class="n">DF</span><span class="p">)</span>                   <span class="c1"># A: time signal at one point -&gt; (f, Q, amp, err) per mode
</span><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">after_sources</span><span class="p">(</span><span class="n">h</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">T_HARMINV</span><span class="p">)</span>
<span class="n">modes</span> <span class="o">=</span> <span class="p">[(</span><span class="n">m</span><span class="p">.</span><span class="n">freq</span><span class="p">,</span> <span class="n">m</span><span class="p">.</span><span class="n">Q</span><span class="p">,</span> <span class="nb">abs</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">amp</span><span class="p">),</span> <span class="n">m</span><span class="p">.</span><span class="n">err</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">h</span><span class="p">.</span><span class="n">modes</span> <span class="k">if</span> <span class="n">m</span><span class="p">.</span><span class="n">Q</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">]</span>

<span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">f0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="n">NONPML</span><span class="p">)</span>  <span class="c1"># B: steady-state field at the resonance
</span>
<span class="n">sim</span><span class="p">.</span><span class="n">init_sim</span><span class="p">();</span> <span class="n">sim</span><span class="p">.</span><span class="n">solve_cw</span><span class="p">(</span><span class="n">tol</span><span class="p">,</span> <span class="n">MAXITERS</span><span class="p">,</span> <span class="n">L_BICG</span><span class="p">)</span>        <span class="c1"># C: frequency-domain solve, then read the field
</span><span class="n">ez_cw</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">NONPML</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: Harminv는 한 점의 시간 신호를 받는 step function이다. <code class="language-plaintext highlighter-rouge">after_sources</code>로 source가 꺼진 뒤부터 기록한다. B의 DFT는 공진 주파수 하나의 정상상태. C는 solve 뒤 <code class="language-plaintext highlighter-rouge">get_array</code>로 field를 읽는다.</li>
    <li><strong>왜</strong>: 공진의 세 숫자는 한 점의 시간 신호에 다 들어 있다. 공간 monitor는 모드의 모양을 볼 때만 필요하다.</li>
    <li><strong>틀리면</strong>: Harminv probe를 모드의 마디(node)에 두면 그 모드가 안 보인다. source와 같은 점을 쓰면 적어도 여기된 모드는 보인다.</li>
  </ul>

  <h3 id="section-4">⑥ 실행 — 울림 창, 감쇠 조건, 반복 종료</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">after_sources</span><span class="p">(</span><span class="n">h</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span>                                              <span class="c1"># A: fixed window (official)
</span><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">,</span> <span class="mf">1e-6</span><span class="p">))</span>                  <span class="c1"># B
</span><span class="n">sim</span><span class="p">.</span><span class="n">solve_cw</span><span class="p">(</span><span class="n">tol</span><span class="p">,</span> <span class="mi">10000</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>                                                                        <span class="c1"># C
</span><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1523</span><span class="p">),</span> <span class="mf">1e-8</span><span class="p">))</span>   <span class="c1"># C, time-domain comparator
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: A는 고정 창(공식). B와 C의 시간영역은 감쇠 조건. C의 solve는 tolerance와 최대 반복.</li>
    <li><strong>왜</strong>: Harminv는 감쇠가 끝나기를 기다리지 않는다. 그것이 Harminv의 존재 이유다. 반대로 DFT는 field가 다 빠져야 정확하므로 Q가 큰 모드일수록 오래 돈다(11편의 2Q/f).</li>
    <li><strong>틀리면</strong>: B에서 감쇠 기준을 느슨하게 하면 DFT에 꼬리가 남아 모드 모양에 이웃 모드가 섞인다.</li>
  </ul>

  <h3 id="fsr-m--">⑦ 후처리 — FSR, m, 복소 정렬</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fsr</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">freqs</span><span class="p">);</span> <span class="n">ng</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="p">(</span><span class="n">fsr</span><span class="p">.</span><span class="n">mean</span><span class="p">()</span> <span class="o">*</span> <span class="n">L_RING</span><span class="p">)</span>                      <span class="c1"># group index from the spacing
</span><span class="n">ring_vals</span> <span class="o">=</span> <span class="n">ez</span><span class="p">[</span><span class="n">ix</span><span class="p">,</span> <span class="n">iy</span><span class="p">]</span>                                                     <span class="c1"># DFT field sampled on the mid-circle
</span><span class="n">m_az</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">rfft</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ring_vals</span><span class="p">)))[</span><span class="mi">1</span><span class="p">:])</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>   <span class="c1"># dominant azimuthal order
</span>
<span class="n">alpha</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">vdot</span><span class="p">(</span><span class="n">ez_td</span><span class="p">,</span> <span class="n">ref</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">vdot</span><span class="p">(</span><span class="n">ez_td</span><span class="p">,</span> <span class="n">ez_td</span><span class="p">)</span>                        <span class="c1"># best-fit complex scale
</span><span class="n">err_td</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">alpha</span> <span class="o">*</span> <span class="n">ez_td</span> <span class="o">-</span> <span class="n">ref</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">ref</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 공진 간격에서 $n_g$를 역산하고, 고리 가운데 원 위의 field를 Fourier 변환해 $m$을 세고, CW와 DFT를 복소 상수로 맞춘 뒤 L2를 잰다.</li>
    <li><strong>왜</strong>: source 정규화(연속파 vs 펄스의 DFT)와 전체 위상은 물리가 아니다. 그것을 빼고 남는 차이가 solver의 차이다.</li>
    <li><strong>틀리면</strong>: $\alpha$ 없이 비교하면 L2가 100%를 넘고, 위상만 다른 같은 모드를 다른 모드로 읽는다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: Harminv가 돌려주는 모드에는 Q가 음수이거나 error가 큰 가짜가 섞인다. Q &gt; 0이고 대역 안에 있는 것만 남기고, error를 허수부 $f/(2Q)$와 비교한다. 이 글의 세 모드는 모두 error가 허수부의 2% 아래다.</p>
  </blockquote>

</details>

<h2 id="interpret">5. 결과를 해석하기</h2>

<p>먼저 세 번째 모드의 <strong>주파수와 Q를 나란히</strong> 읽어보세요. 해상도 10 → 30에서 주파수 변화는 0.3% 이하지만 Q는 비단조로 움직입니다. 따라서 <strong>주파수는 안정적이어도 Q의 절대값은 아직 수렴했다고 주장할 수 없습니다.</strong></p>

<figure class="lesson-figure">
<a href="/meep-examples/assets/meep/12/02_harminv.png" data-lightbox=""><img src="/meep-examples/assets/meep/12/02_harminv.png" alt="해상도별 공진 주파수·Q와 FSR 비교" loading="lazy" /></a>
<figcaption>왼쪽의 주파수는 거의 움직이지 않지만 Q는 크게 바뀝니다. 오른쪽은 공진 간격 FSR과 손계산, 각 모드의 방위 차수 m입니다. 그림을 누르면 확대할 수 있습니다.</figcaption>
</figure>

<table>
  <thead>
    <tr>
      <th>res</th>
      <th>$f_1$ / $Q_1$</th>
      <th>$f_2$ / $Q_2$</th>
      <th>$f_3$ / $Q_3$</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>10 (공식)</td>
      <td>0.11810 / 81</td>
      <td>0.14716 / 317</td>
      <td>0.17525 / 1675</td>
    </tr>
    <tr>
      <td>20</td>
      <td>0.11818 / 79</td>
      <td>0.14736 / 342</td>
      <td>0.17564 / 2132</td>
    </tr>
    <tr>
      <td>30</td>
      <td>0.11822 / 79</td>
      <td>0.14740 / 336</td>
      <td>0.17572 / 1610</td>
    </tr>
  </tbody>
</table>

<table>
  <thead>
    <tr>
      <th>측정 FSR</th>
      <th>$n_g = 1/(\mathrm{FSR}\,L)$</th>
      <th>고리 굴절률</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0.0292 / 0.0283</td>
      <td>3.69</td>
      <td>3.4</td>
    </tr>
  </tbody>
</table>

<p><strong>FSR이 말하는 것:</strong> 간격 0.0292 / 0.0283에서 군굴절률 3.69를 얻습니다. 이는 재료 굴절률 3.4와 같은 양이 아닙니다. 아래 모드는 둘레에 각각 m = 3, 4, 5개의 파장이 들어갑니다.</p>

<details>
  <summary>모드 모양과 주파수 영역 교차검증 보기</summary>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/12/03_modes.png" data-lightbox=""><img src="/meep-examples/assets/meep/12/03_modes.png" alt="세 공진 모드의 전기장과 둘레 방향 진동 횟수" loading="lazy" /></a>
<figcaption>위는 각 주파수의 좁은 대역 DFT입니다. 아래는 r = 1.5인 원 위의 Re(Ez)이며, 둘레에 파장이 m개 들어갑니다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>모드</th>
        <th>f</th>
        <th>λ [a]</th>
        <th>Q (res 20)</th>
        <th>m</th>
        <th>$m/(n L f)$</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>0.1182</td>
        <td>8.46</td>
        <td>79</td>
        <td>3</td>
        <td>0.79</td>
      </tr>
      <tr>
        <td>2</td>
        <td>0.1474</td>
        <td>6.79</td>
        <td>342</td>
        <td>4</td>
        <td>0.85</td>
      </tr>
      <tr>
        <td>3</td>
        <td>0.1756</td>
        <td>5.69</td>
        <td>2132</td>
        <td>5</td>
        <td>0.89</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
<a href="/meep-examples/assets/meep/12/04_solve_cw.png" data-lightbox=""><img src="/meep-examples/assets/meep/12/04_solve_cw.png" alt="solve_cw tolerance 비교와 시간영역 DFT의 전기장 비교" loading="lazy" /></a>
<figcaption>왼쪽은 tolerance별 오차입니다. 가운데 주파수 영역 해와 오른쪽 시간영역 DFT는 복소 상수로 정규화와 전체 위상을 맞춘 뒤 비교합니다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>항목</th>
        <th>값</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>solve_cw tol 1e-8 / 1e-10 / 1e-12 소요</td>
        <td>5 / 6 / 7 s (4 프로세스)</td>
      </tr>
      <tr>
        <td>tol 1e-8, 1e-10의 상대오차 (vs 1e-12)</td>
        <td>4.2e-7, 1.1e-10</td>
      </tr>
      <tr>
        <td>시간영역 DFT vs CW, 복소 정렬 후 L2</td>
        <td>0.40%</td>
      </tr>
      <tr>
        <td>|Ez| 상관</td>
        <td>0.99998</td>
      </tr>
      <tr>
        <td>시간영역 run 길이 (감쇠 1e-8)</td>
        <td>2001 time unit</td>
      </tr>
    </tbody>
  </table>

</details>

<p><strong>두 해법의 확인:</strong> f = 0.118 모드에서 <code class="language-plaintext highlighter-rouge">solve_cw</code>와 시간영역 DFT는 복소 정렬 후 상대 L2 0.40%, 진폭 상관 0.99998로 일치합니다. 이 확인이 모든 모드의 Q 수렴까지 보장하지는 않습니다.</p>

<details>
  <summary>원래의 여덟 예측·수렴성·해석 자세히 보기</summary>

  <h3 id="section-5">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>모드 수</td>
        <td>3</td>
        <td>3</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>공진 주파수 (res 10)</td>
        <td>0.118 / 0.147 / 0.175</td>
        <td>0.1181 / 0.1472 / 0.1753</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>Q 경향</td>
        <td>고주파일수록 크다</td>
        <td>81 → 317 → 1675</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>res 10→30 주파수 변화</td>
        <td>1% 안</td>
        <td>0.3% 이하</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>res 10→30 최고 Q 변화</td>
        <td>수십 %</td>
        <td>1675 → 2132 → 1610 (비단조, ±30%)</td>
        <td>✅ (단조는 아님)</td>
      </tr>
      <tr>
        <td>방위 차수 m</td>
        <td>연속 정수, 3~6</td>
        <td>3, 4, 5</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>solve_cw 오차</td>
        <td>단조 감소</td>
        <td>4.2e-7, 1.1e-10</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>CW vs DFT</td>
        <td>L2 2% 안, 상관 0.999 이상</td>
        <td>0.40%, 0.99998</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>여덟 예측이 모두 방향은 맞았고, 숫자에서 두 가지를 배웠다. 첫째, Q의 해상도 의존은 단조가 아니다. 가장 날카로운 모드의 Q가 res 10에서 1675, 20에서 2132, 30에서 1610이다. 굽힘 방사는 고리 바깥 경계의 작은 누설이고, 그 누설이 격자가 경계를 어떻게 자르느냐(staircase)에 따라 달라지므로 해상도를 올려도 한 방향으로 수렴하지 않는다. 주파수는 세 해상도에서 0.3% 안이다. 둘째, $m/(n L f)$가 0.79, 0.85, 0.89로 1보다 작고 주파수가 높을수록 1에 가깝다. 모드가 고리 밖으로 새어 있어 유효 굴절률이 3.4보다 작고, 높은 모드일수록 안쪽에 갇혀 유효 굴절률이 재료값에 다가간다는 뜻이다. FSR에서 역산한 $n_g$ 3.69가 재료 굴절률보다 큰 것은 분산($n_g = n_{\mathrm{eff}} + f\,dn_{\mathrm{eff}}/df$)이고, 같은 현상의 다른 면이다. 모드 하나를 보는 run은 Q에 비례해 길어진다. Q 2132 모드는 감쇠 1e-6까지 19110 time unit이 걸렸다. Harminv가 300으로 끝내는 일을 DFT는 60배 긴 시간에 한다. solve_cw는 세 tolerance 모두 수 초였고, 시간영역 DFT와 0.4%에서 같다.</p>

  <h3 id="section-6">수렴성</h3>

  <table>
    <thead>
      <tr>
        <th>변수</th>
        <th>값</th>
        <th>결과</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>해상도 (Harminv)</td>
        <td>10 / 20 / 30</td>
        <td>$f_3$: 0.17525 / 0.17564 / 0.17572, $Q_3$: 1675 / 2132 / 1610</td>
        <td>주파수는 20칸/파장에서 수렴, Q는 아직</td>
      </tr>
      <tr>
        <td>Harminv 창</td>
        <td>300 (공식)</td>
        <td>error ≤ 1e-5, 허수부 f/(2Q)의 2% 아래</td>
        <td>창을 늘리면 error가 준다</td>
      </tr>
      <tr>
        <td>solve_cw tolerance</td>
        <td>1e-8 / 1e-10 / 1e-12</td>
        <td>4.2e-7, 1.1e-10</td>
        <td>노트: 1e-11 근처에서 비단조</td>
      </tr>
    </tbody>
  </table>

  <h3 id="section-7">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: 이 고리(2D, n 3.4, R 1, w 1)의 대역 0.10~0.20에는 Ez 모드가 셋 있고 주파수는 해상도 10에서 이미 1% 안이다. 간격은 $n_g$ 3.69의 $1/(n_gL)$과 같다. f = 0.118 모드는 시간영역과 주파수 영역이 0.40% 안에서 같다.</li>
    <li>할 수 없는 것: Q의 절대값. 해상도 30에서도 수렴하지 않았고 Harminv 창 300의 값이다. 도파로와 결합한 고리의 Q(결합 손실이 더해진다). 3D 디스크의 값. 통신 파장으로 축소했을 때의 재료 분산.</li>
  </ul>

</details>

<details>
  <summary>결과가 예상과 다를 때 확인할 것</summary>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Harminv가 모드를 하나만 줌</td>
        <td>source 대역이 좁거나 probe가 마디</td>
        <td>df를 넓히고 probe를 source 점에</td>
      </tr>
      <tr>
        <td>Q가 수만, error도 큼</td>
        <td>가짜 모드</td>
        <td>Q &gt; 0, error &lt; f/(2Q), 대역 안만</td>
      </tr>
      <tr>
        <td>모드 그림에 이웃 모드가 섞임</td>
        <td>모드 영상 source 대역이 FSR보다 넓음</td>
        <td>df &lt; FSR/3</td>
      </tr>
      <tr>
        <td>Harminv 중심만 바꿨는데 결과 그대로</td>
        <td>source 스펙트럼은 안 바뀜</td>
        <td>source를 새로 만든다(공식 ring-mode-overlap.py의 경고)</td>
      </tr>
      <tr>
        <td>solve_cw가 수렴 안 함</td>
        <td>L = 2, 복소 field 없음</td>
        <td>L = 10, <code class="language-plaintext highlighter-rouge">force_complex_fields=True</code></td>
      </tr>
      <tr>
        <td>CW와 DFT가 100% 다름</td>
        <td>정규화·위상 미정렬, 또는 parity 다름</td>
        <td>복소 상수 α로 정렬, source 부호 확인</td>
      </tr>
      <tr>
        <td>해상도를 올렸더니 Q가 크게 변함</td>
        <td>정상. Q는 느리게 수렴</td>
        <td>Q는 해상도 사다리와 함께 보고</td>
      </tr>
    </tbody>
  </table>

</details>

<details>
  <summary>추가 실험 아이디어</summary>

  <table>
    <thead>
      <tr>
        <th>바꿀 것</th>
        <th>예상 변화</th>
        <th>확인할 수치</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>고리 폭 w 1 → 0.5</td>
        <td>구속이 약해져 Q 감소, FSR 증가(둘레 ↓)</td>
        <td>f, Q, FSR</td>
      </tr>
      <tr>
        <td>source를 y축 위 (0, R + 0.1)에</td>
        <td>기존 Y 대칭과 호환되는지 먼저 확인</td>
        <td>모드 수와 source 대칭</td>
      </tr>
      <tr>
        <td>Harminv 창 300 → 1000</td>
        <td>error 감소, Q 안정</td>
        <td>error, Q</td>
      </tr>
      <tr>
        <td>res 40</td>
        <td>Q_3 수렴 여부</td>
        <td>Q_3</td>
      </tr>
      <tr>
        <td>ω–2ω 겹침 (ring-mode-overlap.py)</td>
        <td>0.118과 0.236 모드의 공간 겹침 0.05</td>
        <td>정규화 overlap</td>
      </tr>
    </tbody>
  </table>

</details>

<h2 id="check">6. 이해했는지 확인하기</h2>

<ol>
  <li>주파수가 0.3% 안에서 안정되었는데 Q가 1675 → 2132 → 1610이라면 무엇을 보고해야 할까요?</li>
  <li>Harminv 관측 시간을 늘리는 것과 해상도를 높이는 것은 같은 검증일까요?</li>
</ol>

<details>
  <summary>답과 이유 확인하기</summary>

  <ol>
    <li>주파수는 안정적이지만 Q의 절대값은 아직 수렴하지 않았다고 보고합니다. 사용한 해상도·관측 시간·error를 함께 제시합니다.</li>
    <li>다릅니다. 관측 시간은 시간 신호에서 모드를 추정하는 오차를, 해상도는 구조와 장을 공간 격자로 표현하는 오차를 확인합니다. 작은 Harminv error만으로 공간 수렴을 보장할 수 없습니다.</li>
  </ol>

</details>

<h2 id="reference">7. 코드와 참고자료</h2>

<p><strong>공식 예제</strong>: <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Basics/#modes-of-a-ring-resonator">Basics 튜토리얼의 ring resonator</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Frequency_Domain_Solver/">Frequency-domain solver 튜토리얼</a> · 스크립트 <a href="https://github.com/NanoComp/meep/blob/master/python/examples/ring.py">ring.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/solve-cw.py">solve-cw.py</a>.</p>

<h3 id="전체-코드">전체 코드</h3>

<details>
  <summary>code/ring_resonator.py 전체 (클릭하여 펼치기)</summary>

  <figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 12 - A ring that traps light: Harminv resonances, Q, FSR, and a solve_cw cross-check.

Post 11 measured how much a dipole emits between two mirrors. On a chip the trap is a dielectric ring, and
the first questions about any resonator are: at which frequencies does it trap light, for how long (Q),
how far apart are the resonances (FSR), and what does each trapped mode look like.
  A. Official ring.py: a broadband Ez pulse inside the ring, Harminv on the ringing field after the source
     stops -&gt; frequencies and Q of the modes in the band. Repeated at resolution 10 (official), 20, 30:
     frequencies converge fast, Q of the sharpest mode does not.
  B. Each resonance imaged alone: a narrow-band pulse at that frequency and a DFT field at the same frequency.
     The number of azimuthal lobes m is counted from the field along the ring.
  C. Official solve-cw.py: the same mode at f = 0.118 solved in the frequency domain (continuous source,
     BiCGSTAB-L), tolerance sweep, and compared with a time-domain DFT of the same mode after complex alignment.
Written to run under MPI: collective calls (run, get_array, solve_cw) on every rank, plotting on the master only.

Run:  python ring_resonator.py        (~10 min on one core, ~4 min with mpirun -np 4)
Out:  00_source.png, 01_layout.png, 02_harminv.png, 03_modes.png, 04_solve_cw.png, 05_anim_ring.gif, result.json
      (-&gt; ../assets/12/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="n">Label</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span>   <span class="c1"># noqa: E402
</span>
<span class="n">HERE</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">HERE</span><span class="p">,</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"12"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">MASTER</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">()</span>
<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">say</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>


<span class="c1"># ---------------------------------------------------------------- (1) parameters (official ring.py; a = 1 um)
</span><span class="n">N_RING</span><span class="p">,</span> <span class="n">W</span><span class="p">,</span> <span class="n">R</span> <span class="o">=</span> <span class="mf">3.4</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span>                <span class="c1"># index, ring width, inner radius  [a = 1 um]
</span><span class="n">PAD</span><span class="p">,</span> <span class="n">DPML</span> <span class="o">=</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">2.0</span>
<span class="n">SXY</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="n">W</span> <span class="o">+</span> <span class="n">PAD</span> <span class="o">+</span> <span class="n">DPML</span><span class="p">)</span>              <span class="c1"># 16 x 16
</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">DF</span> <span class="o">=</span> <span class="mf">0.15</span><span class="p">,</span> <span class="mf">0.1</span>                        <span class="c1"># broadband pulse covering 0.10..0.20
</span><span class="n">T_HARMINV</span> <span class="o">=</span> <span class="mf">300.0</span>                           <span class="c1"># ringing window after the source (official)
</span><span class="n">SRC_PT</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">)</span>                <span class="c1"># inside the ring, off the symmetry axes of the modes
</span><span class="n">RES_LIST</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>                     <span class="c1"># official 10, plus two finer
</span><span class="n">RES_IMG</span> <span class="o">=</span> <span class="mi">20</span>                                <span class="c1"># resolution for mode images, solve_cw, GIF
</span><span class="n">R_MID</span> <span class="o">=</span> <span class="n">R</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">W</span>
<span class="n">L_RING</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">R_MID</span>                  <span class="c1"># mean circumference
</span><span class="n">NONPML</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SXY</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">SXY</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">))</span>
<span class="n">EXT</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SXY</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">SXY</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">SXY</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">SXY</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">]</span>

<span class="n">geometry</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">R</span> <span class="o">+</span> <span class="n">W</span><span class="p">,</span> <span class="n">material</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="n">N_RING</span><span class="p">)),</span>     <span class="c1"># later objects win: outer dielectric first ...
</span>            <span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">R</span><span class="p">)]</span>                                             <span class="c1"># ... then the air hole
</span>

<span class="k">def</span> <span class="nf">make_sim</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">sources</span><span class="p">,</span> <span class="n">symmetries</span><span class="o">=</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">),),</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">SXY</span><span class="p">,</span> <span class="n">SXY</span><span class="p">),</span> <span class="n">geometry</span><span class="o">=</span><span class="n">geometry</span><span class="p">,</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">res</span><span class="p">,</span>
                         <span class="n">symmetries</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="n">symmetries</span><span class="p">),</span> <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">DPML</span><span class="p">)],</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>


<span class="c1"># ================================================================ A. Harminv at three resolutions
</span><span class="n">harm</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">t_a</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">for</span> <span class="n">res</span> <span class="ow">in</span> <span class="n">RES_LIST</span><span class="p">:</span>
    <span class="n">src</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">DF</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">)]</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">src</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">res</span> <span class="o">==</span> <span class="n">RES_LIST</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
        <span class="n">annotated_layout</span><span class="p">(</span><span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">6.6</span><span class="p">,</span> <span class="mf">6.2</span><span class="p">),</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">2.0</span><span class="p">,</span>
                         <span class="n">title</span><span class="o">=</span><span class="s">"ring resonator (res 10 shown): n = 3.4, inner radius 1, width 1, a = 1 um"</span><span class="p">,</span>
                         <span class="n">params_text</span><span class="o">=</span><span class="sa">f</span><span class="s">"n=</span><span class="si">{</span><span class="n">N_RING</span><span class="si">}</span><span class="s">, r=</span><span class="si">{</span><span class="n">R</span><span class="si">}</span><span class="s">, w=</span><span class="si">{</span><span class="n">W</span><span class="si">}</span><span class="se">\n</span><span class="s">fcen=</span><span class="si">{</span><span class="n">FCEN</span><span class="si">}</span><span class="s">, df=</span><span class="si">{</span><span class="n">DF</span><span class="si">}</span><span class="se">\n</span><span class="s">res </span><span class="si">{</span><span class="n">RES_LIST</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">7.6</span><span class="p">,</span> <span class="mf">7.0</span><span class="p">),</span>
                         <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">7.6</span><span class="p">,</span> <span class="o">-</span><span class="mf">6.6</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
                         <span class="n">labels</span><span class="o">=</span><span class="p">[</span><span class="n">Label</span><span class="p">(</span><span class="s">"Ez point source at (r + 0.1, 0): every Ez mode in the band"</span><span class="p">,</span> <span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">7.6</span><span class="p">,</span> <span class="mf">4.6</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"ring = dielectric cylinder minus air cylinder"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="n">R_MID</span> <span class="o">*</span> <span class="mf">0.7</span><span class="p">,</span> <span class="n">R_MID</span> <span class="o">*</span> <span class="mf">0.7</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">7.6</span><span class="p">,</span> <span class="mf">3.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                                 <span class="n">Label</span><span class="p">(</span><span class="s">"Harminv probe = the source point, after the source"</span><span class="p">,</span> <span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.3</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">5.2</span><span class="p">,</span> <span class="o">-</span><span class="mf">4.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">)])</span>
    <span class="n">h</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Harminv</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">,</span> <span class="n">FCEN</span><span class="p">,</span> <span class="n">DF</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">after_sources</span><span class="p">(</span><span class="n">h</span><span class="p">),</span> <span class="n">until_after_sources</span><span class="o">=</span><span class="n">T_HARMINV</span><span class="p">)</span>
    <span class="n">modes</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">([(</span><span class="n">m</span><span class="p">.</span><span class="n">freq</span><span class="p">,</span> <span class="n">m</span><span class="p">.</span><span class="n">Q</span><span class="p">,</span> <span class="nb">abs</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">amp</span><span class="p">),</span> <span class="nb">abs</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">err</span><span class="p">))</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">h</span><span class="p">.</span><span class="n">modes</span> <span class="k">if</span> <span class="n">m</span><span class="p">.</span><span class="n">Q</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">FCEN</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DF</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">.</span><span class="n">freq</span> <span class="o">&lt;=</span> <span class="n">FCEN</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DF</span><span class="p">])</span>
    <span class="n">harm</span><span class="p">[</span><span class="n">res</span><span class="p">]</span> <span class="o">=</span> <span class="n">modes</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"A [res </span><span class="si">{</span><span class="n">res</span><span class="si">}</span><span class="s">]: "</span> <span class="o">+</span> <span class="s">"; "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"f </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">5</span><span class="n">f</span><span class="si">}</span><span class="s"> Q </span><span class="si">{</span><span class="n">q</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> |amp| </span><span class="si">{</span><span class="n">a</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">e</span><span class="si">}</span><span class="s"> err </span><span class="si">{</span><span class="n">e</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">e</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">f</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">modes</span><span class="p">))</span>
<span class="n">modes_ref</span> <span class="o">=</span> <span class="n">harm</span><span class="p">[</span><span class="n">RES_IMG</span><span class="p">]</span>
<span class="n">fsr</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">diff</span><span class="p">([</span><span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">modes_ref</span><span class="p">])</span>
<span class="n">ng</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">fsr</span><span class="p">)</span> <span class="o">*</span> <span class="n">L_RING</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"A: FSR </span><span class="si">{</span><span class="s">', '</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">'</span><span class="si">{</span><span class="n">x</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">' for x in fsr)</span><span class="si">}</span><span class="s"> -&gt; effective group index n_g = 1 / (FSR L) = </span><span class="si">{</span><span class="n">ng</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> (ring index </span><span class="si">{</span><span class="n">N_RING</span><span class="si">}</span><span class="s">); </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_a</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
    <span class="n">source_figure</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">DF</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">wl_scale</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"um/c"</span><span class="p">)</span>

<span class="c1"># ================================================================ B. one narrow-band run per resonance: field image + azimuthal order
</span><span class="n">imgs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">t_b</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">for</span> <span class="n">f0</span><span class="p">,</span> <span class="n">q0</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">modes_ref</span><span class="p">:</span>
    <span class="n">df0</span> <span class="o">=</span> <span class="mf">0.01</span>
    <span class="n">src</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">f0</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">df0</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">)]</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">RES_IMG</span><span class="p">,</span> <span class="n">src</span><span class="p">)</span>
    <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">f0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="n">NONPML</span><span class="p">)</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">,</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">ez</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="n">t_end</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">meep_time</span><span class="p">()</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
    <span class="c1"># azimuthal order: sample the DFT field on the ring's mid-circle and count the dominant Fourier index
</span>    <span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">=</span> <span class="n">ez</span><span class="p">.</span><span class="n">shape</span>
    <span class="n">xs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXT</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">EXT</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">nx</span><span class="p">);</span> <span class="n">ys</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXT</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">EXT</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">ny</span><span class="p">)</span>
    <span class="n">phis</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="mi">720</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
    <span class="n">ix</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">searchsorted</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">R_MID</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">phis</span><span class="p">)),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span> <span class="n">iy</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">clip</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">searchsorted</span><span class="p">(</span><span class="n">ys</span><span class="p">,</span> <span class="n">R_MID</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">phis</span><span class="p">)),</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ny</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">ring_vals</span> <span class="o">=</span> <span class="n">ez</span><span class="p">[</span><span class="n">ix</span><span class="p">,</span> <span class="n">iy</span><span class="p">]</span>
    <span class="n">spec</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">rfft</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ring_vals</span><span class="p">)))</span>
    <span class="n">m_az</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">spec</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">imgs</span><span class="p">.</span><span class="n">append</span><span class="p">({</span><span class="s">"f"</span><span class="p">:</span> <span class="n">f0</span><span class="p">,</span> <span class="s">"Q"</span><span class="p">:</span> <span class="n">q0</span><span class="p">,</span> <span class="s">"ez"</span><span class="p">:</span> <span class="n">ez</span><span class="p">,</span> <span class="s">"m"</span><span class="p">:</span> <span class="n">m_az</span><span class="p">,</span> <span class="s">"t_end"</span><span class="p">:</span> <span class="n">t_end</span><span class="p">,</span> <span class="s">"ring_vals"</span><span class="p">:</span> <span class="n">ring_vals</span><span class="p">})</span>
    <span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"B [f </span><span class="si">{</span><span class="n">f0</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">]: azimuthal order m = </span><span class="si">{</span><span class="n">m_az</span><span class="si">}</span><span class="s"> (m / (n L f) = </span><span class="si">{</span><span class="n">m_az</span> <span class="o">/</span> <span class="p">(</span><span class="n">N_RING</span> <span class="o">*</span> <span class="n">L_RING</span> <span class="o">*</span> <span class="n">f0</span><span class="p">)</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">); run ended at t = </span><span class="si">{</span><span class="n">t_end</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"B done in </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_b</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="c1"># ================================================================ C. solve_cw at f = 0.118 vs a time-domain DFT of the same mode
</span><span class="n">F_CW</span> <span class="o">=</span> <span class="n">modes_ref</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
<span class="n">sym_cw</span> <span class="o">=</span> <span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">X</span><span class="p">,</span> <span class="n">phase</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Mirror</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">phase</span><span class="o">=+</span><span class="mi">1</span><span class="p">))</span>
<span class="n">src_cw</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">ContinuousSource</span><span class="p">(</span><span class="n">F_CW</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">)),</span>
          <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">ContinuousSource</span><span class="p">(</span><span class="n">F_CW</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">)),</span> <span class="n">amplitude</span><span class="o">=-</span><span class="mi">1</span><span class="p">)]</span>
<span class="n">TOLS</span> <span class="o">=</span> <span class="p">(</span><span class="mf">1e-8</span><span class="p">,</span> <span class="mf">1e-10</span><span class="p">,</span> <span class="mf">1e-12</span><span class="p">)</span>
<span class="n">MAXITERS</span><span class="p">,</span> <span class="n">L_BICG</span> <span class="o">=</span> <span class="mi">10000</span><span class="p">,</span> <span class="mi">10</span>
<span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">RES_IMG</span><span class="p">,</span> <span class="n">src_cw</span><span class="p">,</span> <span class="n">sym_cw</span><span class="p">,</span> <span class="n">force_complex_fields</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">cw</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">t_c</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">for</span> <span class="n">tol</span> <span class="ow">in</span> <span class="n">TOLS</span><span class="p">:</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
    <span class="n">t1</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">solve_cw</span><span class="p">(</span><span class="n">tol</span><span class="p">,</span> <span class="n">MAXITERS</span><span class="p">,</span> <span class="n">L_BICG</span><span class="p">)</span>
    <span class="n">cw</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="n">tol</span><span class="p">,</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">NONPML</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">),</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t1</span><span class="p">))</span>
<span class="n">eps_cw</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">NONPML</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
<span class="n">ref</span> <span class="o">=</span> <span class="n">cw</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="n">cw_err</span> <span class="o">=</span> <span class="p">[</span><span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="n">ref</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">ref</span><span class="p">))</span> <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">cw</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]]</span>
<span class="n">say</span><span class="p">(</span><span class="s">"C: solve_cw "</span> <span class="o">+</span> <span class="s">"; "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"tol </span><span class="si">{</span><span class="n">t</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">s</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span> <span class="k">for</span> <span class="n">t</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">cw</span><span class="p">)</span> <span class="o">+</span> <span class="s">" | rel error vs tightest: "</span> <span class="o">+</span> <span class="s">", "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">t</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">e</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">e</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">),</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">cw</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">cw_err</span><span class="p">)))</span>

<span class="n">src_td</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">F_CW</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.08</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">)),</span>
          <span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">F_CW</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.08</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">)),</span> <span class="n">amplitude</span><span class="o">=-</span><span class="mi">1</span><span class="p">)]</span>
<span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">RES_IMG</span><span class="p">,</span> <span class="n">src_td</span><span class="p">,</span> <span class="n">sym_cw</span><span class="p">)</span>
<span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">F_CW</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="n">NONPML</span><span class="p">)</span>
<span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1523</span><span class="p">),</span> <span class="mf">1e-8</span><span class="p">))</span>
<span class="n">ez_td</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="n">t_td</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">meep_time</span><span class="p">()</span>
<span class="n">sim</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>
<span class="n">alpha</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">vdot</span><span class="p">(</span><span class="n">ez_td</span><span class="p">,</span> <span class="n">ref</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">vdot</span><span class="p">(</span><span class="n">ez_td</span><span class="p">,</span> <span class="n">ez_td</span><span class="p">)</span>          <span class="c1"># best-fit complex scale: CW and DFT differ by amplitude and global phase
</span><span class="n">err_td</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">alpha</span> <span class="o">*</span> <span class="n">ez_td</span> <span class="o">-</span> <span class="n">ref</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">norm</span><span class="p">(</span><span class="n">ref</span><span class="p">))</span>
<span class="n">corr</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">corrcoef</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez_td</span><span class="p">).</span><span class="n">ravel</span><span class="p">(),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ref</span><span class="p">).</span><span class="n">ravel</span><span class="p">())[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"C: time-domain DFT (decay 1e-8, ended t = </span><span class="si">{</span><span class="n">t_td</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">) vs solve_cw after complex alignment: rel L2 </span><span class="si">{</span><span class="n">err_td</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, |Ez| correlation </span><span class="si">{</span><span class="n">corr</span><span class="si">:</span><span class="p">.</span><span class="mi">6</span><span class="n">f</span><span class="si">}</span><span class="s">; </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_c</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">)</span>

<span class="c1"># ================================================================ GIF: broadband pulse rings the resonator (monitor-free)
</span><span class="n">sim_g</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">RES_IMG</span><span class="p">,</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">FCEN</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">DF</span><span class="p">),</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">SRC_PT</span><span class="p">)])</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
<span class="n">eps_g</span> <span class="o">=</span> <span class="n">sim_g</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">NONPML</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
<span class="n">t0g</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">/</span> <span class="n">DF</span>
<span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_g</span><span class="p">,</span> <span class="n">NONPML</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="n">t0g</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">DF</span><span class="p">,</span> <span class="n">t_end</span><span class="o">=</span><span class="n">t0g</span> <span class="o">+</span> <span class="mi">260</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">80</span><span class="p">)</span>
<span class="n">sim_g</span><span class="p">.</span><span class="n">reset_meep</span><span class="p">()</span>

<span class="c1"># ================================================================ figures (master only)
</span><span class="k">if</span> <span class="n">MASTER</span><span class="p">:</span>
    <span class="c1"># A: Harminv results vs resolution
</span>    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">))</span>
    <span class="n">cols</span> <span class="o">=</span> <span class="p">{</span><span class="mi">10</span><span class="p">:</span> <span class="s">"tab:gray"</span><span class="p">,</span> <span class="mi">20</span><span class="p">:</span> <span class="s">"tab:blue"</span><span class="p">,</span> <span class="mi">30</span><span class="p">:</span> <span class="s">"tab:red"</span><span class="p">}</span>
    <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">modes</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">harm</span><span class="p">.</span><span class="n">items</span><span class="p">()):</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">plot</span><span class="p">([</span><span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">modes</span><span class="p">],</span> <span class="p">[</span><span class="n">m</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">modes</span><span class="p">],</span> <span class="s">"o-"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="n">res</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s">"res </span><span class="si">{</span><span class="n">res</span><span class="si">}</span><span class="s">: Q = "</span> <span class="o">+</span> <span class="s">" / "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">m</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">modes</span><span class="p">))</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_yscale</span><span class="p">(</span><span class="s">"log"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"resonance frequency f [c/a]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"Q (Harminv)"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"three Ez modes in the band 0.10-0.20: Q climbs with f (less bending radiation)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">"both"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"upper left"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">modes_ref</span><span class="p">):</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axvline</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.2</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="mf">0.88</span><span class="p">,</span> <span class="sa">f</span><span class="s">"m = </span><span class="si">{</span><span class="n">imgs</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'m'</span><span class="p">]</span><span class="si">}</span><span class="se">\n</span><span class="s">f = </span><span class="si">{</span><span class="n">f</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">axvspan</span><span class="p">(</span><span class="n">FCEN</span> <span class="o">-</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DF</span><span class="p">,</span> <span class="n">FCEN</span> <span class="o">+</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="n">DF</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"orange"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.12</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"source band"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">fsr</span><span class="p">)):</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">annotate</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="n">modes_ref</span><span class="p">[</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="mf">0.5</span><span class="p">),</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="n">modes_ref</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="mf">0.5</span><span class="p">),</span> <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">arrowstyle</span><span class="o">=</span><span class="s">"&lt;-&gt;"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"k"</span><span class="p">))</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">modes_ref</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">modes_ref</span><span class="p">[</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]),</span> <span class="mf">0.55</span><span class="p">,</span> <span class="sa">f</span><span class="s">"FSR </span><span class="si">{</span><span class="n">fsr</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">"center"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">text</span><span class="p">(</span><span class="mf">0.102</span><span class="p">,</span> <span class="mf">0.15</span><span class="p">,</span> <span class="sa">f</span><span class="s">"1 / (n_g L) with n_g = </span><span class="si">{</span><span class="n">ng</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">, L = 2 pi </span><span class="si">{</span><span class="n">R_MID</span><span class="si">}</span><span class="s"> = </span><span class="si">{</span><span class="n">L_RING</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlim</span><span class="p">(</span><span class="mf">0.095</span><span class="p">,</span> <span class="mf">0.205</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_yticks</span><span class="p">([]);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"f [c/a]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"free spectral range and azimuthal order (res 20)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">legend</span><span class="p">(</span><span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"02_harminv.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

    <span class="c1"># B: mode images
</span>    <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">8.2</span><span class="p">),</span> <span class="n">gridspec_kw</span><span class="o">=</span><span class="p">{</span><span class="s">"height_ratios"</span><span class="p">:</span> <span class="p">[</span><span class="mf">1.6</span><span class="p">,</span> <span class="mi">1</span><span class="p">]})</span>
    <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">d</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">imgs</span><span class="p">):</span>
        <span class="n">ez</span> <span class="o">=</span> <span class="n">d</span><span class="p">[</span><span class="s">"ez"</span><span class="p">];</span> <span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">percentile</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ez</span><span class="p">),</span> <span class="mf">99.5</span><span class="p">))</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ez</span><span class="p">).</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">contour</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXT</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">EXT</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">eps_cw</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXT</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">EXT</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">eps_cw</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">eps_cw</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="p">[</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">N_RING</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)],</span> <span class="n">colors</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.6</span><span class="p">)</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"f = </span><span class="si">{</span><span class="n">d</span><span class="p">[</span><span class="s">'f'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (lambda = </span><span class="si">{</span><span class="mi">1</span> <span class="o">/</span> <span class="n">d</span><span class="p">[</span><span class="s">'f'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> a), Q = </span><span class="si">{</span><span class="n">d</span><span class="p">[</span><span class="s">'Q'</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">, m = </span><span class="si">{</span><span class="n">d</span><span class="p">[</span><span class="s">'m'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [a]"</span><span class="p">)</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="mi">720</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="bp">False</span><span class="p">)),</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="s">"ring_vals"</span><span class="p">])</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="s">"ring_vals"</span><span class="p">])),</span> <span class="n">color</span><span class="o">=</span><span class="s">"tab:blue"</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"angle around the ring [deg]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s">"Re(Ez) on the mid-circle r = </span><span class="si">{</span><span class="n">R_MID</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">d</span><span class="p">[</span><span class="s">'m'</span><span class="p">]</span><span class="si">}</span><span class="s"> periods"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">].</span><span class="n">set_xlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">360</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"y [a]"</span><span class="p">);</span> <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"normalized"</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"each resonance imaged alone (narrow-band source, DFT at the resonance): the azimuthal order m counts the wavelengths around the ring"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">();</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_modes.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

    <span class="c1"># C: solve_cw
</span>    <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mf">4.4</span><span class="p">))</span>
    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">loglog</span><span class="p">([</span><span class="n">t</span> <span class="k">for</span> <span class="n">t</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">cw</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]],</span> <span class="n">cw_err</span><span class="p">,</span> <span class="s">"bo-"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">invert_xaxis</span><span class="p">()</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">s</span><span class="p">),</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">cw</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">cw_err</span><span class="p">):</span>
        <span class="n">ax</span><span class="p">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">s</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s"</span><span class="p">,</span> <span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">e</span><span class="p">),</span> <span class="n">textcoords</span><span class="o">=</span><span class="s">"offset points"</span><span class="p">,</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="o">-</span><span class="mi">12</span><span class="p">),</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
    <span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"solve_cw tolerance"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="sa">f</span><span class="s">"relative error vs tol </span><span class="si">{</span><span class="n">TOLS</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s"> field"</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"frequency-domain solver: tighter tolerance, smaller change"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">ax</span><span class="p">.</span><span class="n">grid</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">"both"</span><span class="p">)</span>
    <span class="n">lim</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">percentile</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">ref</span><span class="p">),</span> <span class="mf">99.5</span><span class="p">))</span>
    <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">ttl</span> <span class="ow">in</span> <span class="p">((</span><span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">ref</span><span class="p">),</span> <span class="sa">f</span><span class="s">"solve_cw at f = </span><span class="si">{</span><span class="n">F_CW</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> (tol </span><span class="si">{</span><span class="n">TOLS</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">e</span><span class="si">}</span><span class="s">)"</span><span class="p">),</span>
                         <span class="p">(</span><span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="n">real</span><span class="p">(</span><span class="n">alpha</span> <span class="o">*</span> <span class="n">ez_td</span><span class="p">),</span> <span class="sa">f</span><span class="s">"time-domain DFT, aligned: rel L2 </span><span class="si">{</span><span class="n">err_td</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)):</span>
        <span class="n">a</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="n">EXT</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="s">"lower"</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">"RdBu"</span><span class="p">,</span> <span class="n">vmin</span><span class="o">=-</span><span class="n">lim</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="n">lim</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">)</span>
        <span class="n">a</span><span class="p">.</span><span class="n">contour</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXT</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">EXT</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">eps_cw</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">EXT</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">EXT</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">eps_cw</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">eps_cw</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="p">[</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">N_RING</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)],</span> <span class="n">colors</span><span class="o">=</span><span class="s">"k"</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.6</span><span class="p">)</span>
        <span class="n">a</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="n">ttl</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">);</span> <span class="n">a</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"x [a]"</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s">"the same mode from two solvers: continuous source + BiCGSTAB-L (left, centre) and a pulse + DFT (right)"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
    <span class="n">fig</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">(</span><span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.93</span><span class="p">]);</span> <span class="n">fig</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_solve_cw.png"</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="n">close</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>

    <span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="n">EXT</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"05_anim_ring.gif"</span><span class="p">),</span> <span class="n">eps</span><span class="o">=</span><span class="n">eps_g</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.6</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span> <span class="n">clip_percentile</span><span class="o">=</span><span class="mf">99.0</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"a"</span><span class="p">,</span>
                   <span class="n">points</span><span class="o">=</span><span class="p">[(</span><span class="n">R</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"source / probe"</span><span class="p">)],</span> <span class="n">title</span><span class="o">=</span><span class="s">"broadband pulse, then ringing"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower left"</span><span class="p">)</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f_</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"params"</span><span class="p">:</span> <span class="p">{</span><span class="s">"n"</span><span class="p">:</span> <span class="n">N_RING</span><span class="p">,</span> <span class="s">"r"</span><span class="p">:</span> <span class="n">R</span><span class="p">,</span> <span class="s">"w"</span><span class="p">:</span> <span class="n">W</span><span class="p">,</span> <span class="s">"pad"</span><span class="p">:</span> <span class="n">PAD</span><span class="p">,</span> <span class="s">"dpml"</span><span class="p">:</span> <span class="n">DPML</span><span class="p">,</span> <span class="s">"fcen"</span><span class="p">:</span> <span class="n">FCEN</span><span class="p">,</span> <span class="s">"df"</span><span class="p">:</span> <span class="n">DF</span><span class="p">,</span> <span class="s">"T_harminv"</span><span class="p">:</span> <span class="n">T_HARMINV</span><span class="p">,</span> <span class="s">"L_ring"</span><span class="p">:</span> <span class="n">L_RING</span><span class="p">},</span>
                   <span class="s">"harminv"</span><span class="p">:</span> <span class="p">{</span><span class="nb">str</span><span class="p">(</span><span class="n">k</span><span class="p">):</span> <span class="p">[{</span><span class="s">"f"</span><span class="p">:</span> <span class="n">f</span><span class="p">,</span> <span class="s">"Q"</span><span class="p">:</span> <span class="n">q</span><span class="p">,</span> <span class="s">"amp"</span><span class="p">:</span> <span class="n">a</span><span class="p">,</span> <span class="s">"err"</span><span class="p">:</span> <span class="n">e</span><span class="p">}</span> <span class="k">for</span> <span class="n">f</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">v</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">harm</span><span class="p">.</span><span class="n">items</span><span class="p">()},</span>
                   <span class="s">"fsr"</span><span class="p">:</span> <span class="n">fsr</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"n_g"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">ng</span><span class="p">),</span>
                   <span class="s">"modes"</span><span class="p">:</span> <span class="p">[{</span><span class="s">"f"</span><span class="p">:</span> <span class="n">d</span><span class="p">[</span><span class="s">"f"</span><span class="p">],</span> <span class="s">"Q"</span><span class="p">:</span> <span class="n">d</span><span class="p">[</span><span class="s">"Q"</span><span class="p">],</span> <span class="s">"m"</span><span class="p">:</span> <span class="n">d</span><span class="p">[</span><span class="s">"m"</span><span class="p">],</span> <span class="s">"t_end"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="s">"t_end"</span><span class="p">])}</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">imgs</span><span class="p">],</span>
                   <span class="s">"solve_cw"</span><span class="p">:</span> <span class="p">{</span><span class="s">"f"</span><span class="p">:</span> <span class="n">F_CW</span><span class="p">,</span> <span class="s">"tols"</span><span class="p">:</span> <span class="nb">list</span><span class="p">(</span><span class="n">TOLS</span><span class="p">),</span> <span class="s">"seconds"</span><span class="p">:</span> <span class="p">[</span><span class="n">s</span> <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">cw</span><span class="p">],</span> <span class="s">"rel_err_vs_tightest"</span><span class="p">:</span> <span class="n">cw_err</span><span class="p">,</span>
                                <span class="s">"td_vs_cw_rel_l2"</span><span class="p">:</span> <span class="n">err_td</span><span class="p">,</span> <span class="s">"td_vs_cw_corr"</span><span class="p">:</span> <span class="n">corr</span><span class="p">,</span> <span class="s">"td_t_end"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">t_td</span><span class="p">)},</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">,</span> <span class="s">"np"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">count_processors</span><span class="p">()},</span> <span class="n">f_</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">say</span><span class="p">(</span><span class="sa">f</span><span class="s">"total </span><span class="si">{</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s on </span><span class="si">{</span><span class="n">mp</span><span class="p">.</span><span class="n">count_processors</span><span class="p">()</span><span class="si">}</span><span class="s"> process(es)"</span><span class="p">)</span></code></pre></figure>

</details>

<p>§4의 발췌 코드와 달리 전체 코드에는 해상도 사다리, 모드 영상과 방위 차수 계산, solve_cw sweep, GIF, result.json 기록이 들어 있다. MPI로 돌릴 수 있게 collective 호출(run, get_array, solve_cw)은 모든 rank에서, 그림 저장은 master rank에서만 한다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

<p><strong>실행 결과 (2026-10-23 실행, mpirun -np 4)</strong>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A [res 10]: f 0.11810 Q 81 |amp| 3.41e-03 err 1.0e-05; f 0.14716 Q 317 |amp| 2.86e-02 err 7.3e-07; f 0.17525 Q 1675 |amp| 7.21e-03 err 2.0e-07
A [res 20]: f 0.11818 Q 79 |amp| 3.51e-03 err 6.8e-06; f 0.14736 Q 342 |amp| 2.81e-02 err 1.7e-07; f 0.17564 Q 2132 |amp| 6.76e-03 err 1.4e-06
A [res 30]: f 0.11822 Q 79 |amp| 3.52e-03 err 2.6e-06; f 0.14740 Q 336 |amp| 2.82e-02 err 1.5e-07; f 0.17572 Q 1610 |amp| 6.79e-03 err 9.7e-08
A: FSR 0.0292, 0.0283 -&gt; effective group index n_g = 1 / (FSR L) = 3.69 (ring index 3.4)
B [f 0.1182]: azimuthal order m = 3 (m / (n L f) = 0.792); run ended at t = 2101
B [f 0.1474]: azimuthal order m = 4 (m / (n L f) = 0.847); run ended at t = 5453
B [f 0.1756]: azimuthal order m = 5 (m / (n L f) = 0.888); run ended at t = 19110
C: solve_cw tol 1e-08: 5 s; tol 1e-10: 6 s; tol 1e-12: 7 s | rel error vs tightest: 1e-08: 4.24e-07, 1e-10: 1.08e-10
C: time-domain DFT (decay 1e-8, ended t = 2001) vs solve_cw after complex alignment: rel L2 0.0040, |Ez| correlation 0.999984
total ~4 min on 4 processes
</code></pre></div></div>

<p><strong>재현 환경</strong>: meep 1.33.0 (MPI) · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep=*=mpi_mpich_*</code> · 실행 <code class="language-plaintext highlighter-rouge">mpirun -np 4 python ring_resonator.py</code> (약 4 min (mpirun -np 4))</p>

<details>
  <summary>심화 질문: 다음 편과 연결하기</summary>

  <ol>
    <li>Harminv는 300 time unit의 신호로 수명이 수천인 모드의 Q를 준다. 그것이 가능한 이유와, 그 Q를 믿어도 되는 조건(error)을 말해 보라.</li>
    <li>주파수는 해상도 10에서 1% 안인데 Q는 해상도 30에서도 수렴하지 않았다. 두 양의 수렴 속도가 다른 이유를 굽힘 방사와 격자로 설명해 보라.</li>
    <li>이 고리는 2D 단면이다. 실제 마이크로디스크는 축대칭 3D 구조이고 모드는 방위 차수 m을 가진다. 3D 셀을 돌리지 않고 m 하나당 2D 계산으로 끝내는 좌표계는 무엇이고, 그때 m은 어디에 들어가는가. (13편)</li>
  </ol>

</details>

<h3 id="더-읽기">더 읽기</h3>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Basics/#modes-of-a-ring-resonator">Basics 튜토리얼: modes of a ring resonator</a> · <a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Frequency_Domain_Solver/">Frequency-domain solver</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#harminv">Harminv 레퍼런스</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#frequency-domain-solver">solve_cw</a></li>
  <li>스크립트: <a href="https://github.com/NanoComp/meep/blob/master/python/examples/ring.py">ring.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/solve-cw.py">solve-cw.py</a> · <a href="https://github.com/NanoComp/meep/blob/master/python/examples/ring-mode-overlap.py">ring-mode-overlap.py</a></li>
  <li>이전 글: <a href="/meep-examples/cavity-ldos/">11 · 두 거울 사이의 점광원</a> · 05편의 bend 손실: <a href="/meep-examples/waveguide-bend-90/">05 · Bent waveguide와 radius trade-off</a> · 다음 글: <a href="/meep-examples/cylindrical-dipole/">13 · 회전 대칭으로 3D를 계산하기</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="ring-resonator" /><category term="harminv" /><category term="q-factor" /><category term="fsr" /><category term="solve_cw" /><category term="frequency-domain" /><summary type="html"><![CDATA[post 11 measured how much a dipole emits between two mirrors. On a chip the trap is a dielectric ring. This post asks the first questions about any resonator: at which frequencies does it trap light, for how long (Q), how far apart are the resonances (FSR), and what does each trapped mode look like. Official `ring.py` (Harminv on the ringing field), one narrow-band run per mode, and official `solve-cw.py` (the same mode solved in the frequency domain).]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/12/03_modes.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/12/03_modes.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="ko"><title type="html">Meep Example 05 · Bent waveguide와 radius trade-off — 2-run flux 정규화, sharp bend 기준값, radius sweep</title><link href="https://jin-castle.github.io/meep-examples/waveguide-bend-90/" rel="alternate" type="text/html" title="Meep Example 05 · Bent waveguide와 radius trade-off — 2-run flux 정규화, sharp bend 기준값, radius sweep" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://jin-castle.github.io/meep-examples/waveguide-bend-90</id><content type="html" xml:base="https://jin-castle.github.io/meep-examples/waveguide-bend-90/"><![CDATA[<details>
  <summary>English summary</summary>

  <ul>
    <li><strong>What</strong>: a dielectric waveguide (ε = 12, width 1) turns a sharp 90° corner. We measure how much power goes around the corner, how much comes back, and how much leaks out.</li>
    <li><strong>Result</strong>: T = 0.20, R = 0.22, radiated = 0.58 at the center wavelength. Most of the light is lost at the sharp corner. Rounding it recovers the light: T = 0.91 at a bend radius of 0.35 µm and 0.99 at 0.70 µm.</li>
    <li><strong>Takeaway</strong>: two-run flux normalization. A straight reference run gives the input power and the incident fields; subtracting them in the bend run leaves only the reflection. A sharp corner is not usable in a photonic circuit.</li>
    <li><strong>Code</strong>: full script at the bottom, ~95 s on one core (the sharp bend alone takes 10 s).</li>
  </ul>

</details>

<h2 id="observe">1. 관찰 · 빛의 경로를 먼저 보기</h2>

<p>같은 폭의 도파로를 직각으로 꺾었습니다. 입력은 왼쪽, 출력은 위쪽입니다. 수평 암에서 코너까지 온 파면이 <strong>수직 암으로만 이어지는지, 주변 공기로도 퍼지는지</strong> 보세요. 필드의 밝기를 바로 투과율로 읽지 말고 뒤의 flux 측정과 연결합니다.</p>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/05/02_field.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/02_field.png" alt="날카로운 L자 도파로의 실제 Re(Ez)와 진폭. 코너 밖으로 방사파가 퍼지고 출력 암은 약하다." loading="lazy" />
  </a>
  <figcaption>1550 nm의 실제 필드입니다. 가는 선은 도파로 경계이며, 코너 바깥의 파면과 입력 암의 정상파가 각각 방사와 반사의 단서입니다.</figcaption>
</figure>

<figure class="lesson-figure lesson-animation">
  <a href="/meep-examples/assets/meep/05/06_anim_sharp.gif" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/06_anim_sharp.gif" alt="날카로운 코너에서 펄스가 반사·방사·투과로 나뉘는 시간 전개" loading="lazy" data-animation-src="/meep-examples/assets/meep/05/06_anim_sharp.gif" data-static-src="/meep-examples/assets/meep/05/02_field.png" />
  </a>
  <button class="animation-toggle" type="button" hidden="">애니메이션 정지</button>
  <figcaption>sharp 코너의 시간 전개. 펄스가 코너에 닿는 순간 cladding으로 큰 파면이 퍼져 나가고, 수직 암으로는 일부만 올라간다. 되돌아오는 파가 수평 암에서 입사파와 겹친다.</figcaption>
</figure>

<figure class="lesson-figure lesson-animation">
  <a href="/meep-examples/assets/meep/05/06_anim_round.gif" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/06_anim_round.gif" alt="반지름 3a의 둥근 코너를 따라 펄스가 출력으로 이동하는 시간 전개" loading="lazy" data-animation-src="/meep-examples/assets/meep/05/06_anim_round.gif" data-static-src="/meep-examples/assets/meep/05/05_field_round.png" />
  </a>
  <button class="animation-toggle" type="button" hidden="">애니메이션 정지</button>
  <figcaption>반지름 3a 코너의 시간 전개. 같은 펄스가 코너를 돌아 수직 암 위의 투과 단면(파란 선)까지 거의 그대로 간다.</figcaption>
</figure>

<h2 id="predict">2. 예측 · 결과를 읽기 전에</h2>

<p>재료가 빛을 흡수하지 않아도, 위쪽 도파로로 나가는 몫 T는 줄어들 수 있을까요?</p>

<fieldset class="prediction">
  <legend>먼저 하나를 골라보세요.</legend>
  <label><input type="radio" name="prediction-05" value="0" /> 흡수가 없으므로 T는 거의 1이다</label>
  <label><input type="radio" name="prediction-05" value="1" /> 반사와 방사가 있으므로 T는 1보다 작다</label>
</fieldset>

<details>
  <summary>예측의 근거 확인하기</summary>

  <p>두 번째입니다. 손실 없는 재료라는 말은 출력 도파로가 모든 power를 받는다는 뜻이 아닙니다. 입력으로 되돌아가는 반사 R과 주변 공기로 새는 방사 L도 함께 세어야 합니다. 이 구조에서는 방사가 가장 큰 몫인지 측정으로 확인합니다.</p>

</details>

<h2 id="understand">3. 원리 이해하기 · 관찰을 설명하는 방법</h2>

<!-- concept-illustration:part-05:start -->

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/05/00_concept.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/00_concept.png" alt="직선 기준, 날카로운 L자 굽힘, 둥근 굽힘을 비교한다. 입력은 왼쪽, 출력은 위쪽이며 날카로운 코너의 반사와 바깥 방사 경로를 표시한다." loading="lazy" />
  </a>
  <figcaption>공기 속 ε = 12 유전체 도파로에서 직선 기준과 날카로운 직각, 둥근 굽힘을 비교합니다. 유효 입사광은 왼쪽에서 +x 방향으로 들어오고 출력은 위쪽 +y 방향입니다. 코너에서는 투과·반사·바깥 방사가 나뉠 수 있습니다. 그림의 R ≈ 0.70 µm는 둥근 굽힘의 중심선 곡률반경 0.6975 µm를 반올림한 값입니다. 점선은 위치 안내선입니다. 화살표 굵기는 계산된 전력 비율을 나타내지 않습니다. 파장을 1550 nm로 읽는 이 글의 환산에서 폭은 232.5 nm입니다.</figcaption>
</figure>

<!-- concept-illustration:part-05:end -->

<h3 id="먼저-직선에서-기준을-만든다">먼저 직선에서 기준을 만든다</h3>

<p>기준 run은 같은 재료·폭·source를 가진 직선 도파로입니다. 여기서 실제로 전달된 power를 입력값 P_in으로 저장하고, 반사 단면에서는 입사장의 DFT 데이터를 저장합니다. 굽힘 run에서는 같은 반사 단면에 <code class="language-plaintext highlighter-rouge">load_minus_flux_data</code>를 적용해 <strong>필드 수준에서 입사 성분을 뺍니다</strong>. power 숫자끼리 빼면 간섭항이 남습니다.</p>

<h3 id="출력-되돌아옴-바깥으로-샘을-나눈다">출력, 되돌아옴, 바깥으로 샘을 나눈다</h3>

\[T=P_{\mathrm{tran}}/P_{\mathrm{in}},\qquad R=-P_{\mathrm{refl}}/P_{\mathrm{in}},\qquad L=1-T-R\]

<p>반사파는 −x로 가므로 flux가 음수이고, R 앞의 마이너스가 이를 양의 비율로 바꿉니다. 투과 monitor는 +y로 가는 빛을 가로지르는 <strong>가로선</strong>이어야 합니다. 코너가 급할수록 모드의 방향과 모양이 갑자기 바뀌어 반사·방사가 생깁니다. 둥근 코너는 그 변화를 완만하게 만듭니다.</p>

<aside class="lesson-note">
  <p><strong>이 모델의 범위:</strong> 2D Ez, 손실 없는 ε = 12 재료입니다. L은 별도 방사 monitor로 잰 값이 아니라 잔여입니다. 1a = 232.5 nm로 환산해 폭 1a와 파장 6.67a를 각각 232.5 nm와 1550 nm로 읽습니다. 다른 재료나 3D 구조의 최소 반지름으로 그대로 옮길 수 없습니다.</p>
</aside>

<details>
  <summary>기호·설계 가정과 예측표 자세히 보기</summary>

  <p>도파로를 따라가던 모드는 코너에서 갑자기 방향이 바뀐 도파로를 만난다. 입력 모드와 수직 암의 모드는 모양이 겹치는 부분이 작아서(mode mismatch), 겹치지 않는 부분만큼 밖으로 방사되거나 되돌아간다. 닫힌 해석해는 없고, 에너지 보존이 결과를 구속한다.</p>

\[T=\frac{P_{\mathrm{tran}}}{P_{\mathrm{in}}},\qquad
R=\frac{-P_{\mathrm{refl}}}{P_{\mathrm{in}}},\qquad
T+R+L_{\mathrm{rad}}=1\]

  <table>
    <thead>
      <tr>
        <th>기호</th>
        <th>뜻</th>
        <th>코드 변수</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>$P_{\mathrm{in}}$</td>
        <td>직선 기준 run에서 도파로를 지나간 power</td>
        <td><code class="language-plaintext highlighter-rouge">P_in</code></td>
      </tr>
      <tr>
        <td>$P_{\mathrm{tran}}$</td>
        <td>bend run에서 수직 암 단면을 지나는 power</td>
        <td><code class="language-plaintext highlighter-rouge">mp.get_fluxes(tran)</code></td>
      </tr>
      <tr>
        <td>$P_{\mathrm{refl}}$</td>
        <td>bend run의 반사 단면 flux. 입사 성분을 뺀 값이라 뒤로 가는 power만 남고 <strong>음수</strong></td>
        <td><code class="language-plaintext highlighter-rouge">mp.get_fluxes(refl)</code></td>
      </tr>
      <tr>
        <td>$L_{\mathrm{rad}}$</td>
        <td>코너에서 밖으로 새는 power. 직접 재지 않고 잔여로 추정</td>
        <td><code class="language-plaintext highlighter-rouge">L = 1 - T - R</code></td>
      </tr>
    </tbody>
  </table>

  <p><strong>가정과 유효 범위</strong>: 2D, lossless 재료(잔여는 전부 방사), Ez 편광(면에 수직한 전기장), 공식 예제의 무차원 단위(길이 단위 a, ε = 12, 파장 6.67a). 그림에서는 a = 232.5 nm로 읽어 중심 파장을 1550 nm, 길이를 µm로 표시한다.</p>

  <h3 id="section">결과 보기 전에 맞춰보기</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측</th>
        <th>근거</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>T</td>
        <td>0.5 미만, 수십 %</td>
        <td>굴절률 대비가 크고(√12 ≈ 3.5) 코너가 급해 모드 겹침이 작다</td>
      </tr>
      <tr>
        <td>R</td>
        <td>수십 %</td>
        <td>코너 벽이 거울처럼 일부를 되돌린다</td>
      </tr>
      <tr>
        <td>L (방사)</td>
        <td>가장 큰 몫</td>
        <td>코너에서 위상이 맞는 방향이 없어 대부분 밖으로 흩어진다</td>
      </tr>
      <tr>
        <td>필드 모양</td>
        <td>코너 주변 cladding으로 퍼지는 방사 lobe, 수직 암은 희미</td>
        <td>mode mismatch</td>
      </tr>
      <tr>
        <td>T + R</td>
        <td>1 이하</td>
        <td>에너지 보존</td>
      </tr>
    </tbody>
  </table>

  <p><strong>판정 기준</strong>: 이 sharp 구조의 낮은 T와 에너지 수지를 먼저 확인합니다. 작은 T + R 초과는 수치 오차일 수 있으므로 부호·정규화와 수렴성을 함께 점검합니다.</p>

</details>

<h2 id="run">4. 직접 실행 · 변수 하나만 바꾸기</h2>

<h3 id="한-번만-바꿔보기-도파로-폭">한 번만 바꿔보기: 도파로 폭</h3>

<ol>
  <li>아래 전체 코드와 공통 <code class="language-plaintext highlighter-rouge">blogfig.py</code>를 같은 <code class="language-plaintext highlighter-rouge">code/</code> 폴더에 두고, 그 폴더에서 <code class="language-plaintext highlighter-rouge">python bend90.py</code>를 실행합니다. 원본의 <code class="language-plaintext highlighter-rouge">w = 1.0</code> 결과와 <code class="language-plaintext highlighter-rouge">result.json</code>을 별도 보관합니다.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">w = 1.0</code> 한 줄만 <code class="language-plaintext highlighter-rouge">w = 0.8</code>로 바꿔</strong> 다시 실행합니다. 재료·파장·반지름 목록·해상도는 그대로 둡니다.</li>
  <li>두 실행의 <code class="language-plaintext highlighter-rouge">radius_sweep</code>에서 같은 반지름의 T·R·L을 비교합니다. T가 0.9를 넘는 첫 반지름과 sharp bend의 T도 적어 보세요.</li>
</ol>

<p>폭이 바뀌면 모드의 구속과 코너에서의 겹침도 바뀝니다. 어느 반지름에서 차이가 커질지 먼저 예상해 보세요. <strong>폭 0.8의 결과는 이 글에 측정되어 있지 않으며</strong>, 원본 곡선은 폭 1.0의 기준입니다. 실행할 때 출력 파일이 갱신되므로 비교용 기준 결과를 먼저 보관합니다.</p>

<details>
  <summary>계산 배치·광원·파라미터 보기</summary>

  <figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/05/01_layout.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/01_layout.png" alt="L자 도파로의 광원, 반사·투과 flux 단면, PML과 종료 감시점" loading="lazy" />
  </a>
  <figcaption>검은 L자 = 수평 암 + 수직 암(`geometry`, 양 끝이 PML 관통), 빨간 선 = Ez line source(x = −6.5), 파란 세로선 = 반사 flux 단면(x = −5.5, source 하류), 파란 가로선 = 투과 flux 단면(y = +6.5, 수직 암 위), 녹색 빗금 = PML, 보라 × = bend run의 종료 조건이 감시하는 점(4, 6.5). 좌표는 코드의 a 단위이고 축 눈금은 a = 232.5 nm로 환산한 µm다(cell 16a = 3.72 µm). 동그라미 숫자는 §4의 코드 단계 번호다. ① 파라미터 박스, ② 구조, ③ source, ④ PML, ⑤ monitor, ⑥ 종료 감시점이고, ⑦ 후처리는 그릴 것이 없다. 기준 run(직선)은 같은 source·반사 단면에 수평 암만 쭉 이어진 구조다.</figcaption>
</figure>

  <table>
    <thead>
      <tr>
        <th>파라미터</th>
        <th>값</th>
        <th>왜 이 값인가</th>
        <th>바꾸면</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">eps_wg</code>, <code class="language-plaintext highlighter-rouge">w</code></td>
        <td>12, 1</td>
        <td>공식 튜토리얼 값 (n ≈ 3.46)</td>
        <td>ε 낮추면 confinement 약해져 L ↑</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">fcen</code>, <code class="language-plaintext highlighter-rouge">df</code></td>
        <td>0.15, 0.1</td>
        <td>파장 6.67a = 1550 nm (a = 232.5 nm). 대역 5–10a = 1160–2325 nm</td>
        <td>대역 가장자리는 source power가 작아 값이 튄다</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">resolution</code></td>
        <td>25</td>
        <td>공식 10 → 상향. 도파로 폭 25 px, 유도 파장 48 px</td>
        <td>10이면 코너 형상이 거칠어 수치 변동</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">dpml</code></td>
        <td>1.0</td>
        <td>파장의 1/6 이상. 양 암이 PML을 관통</td>
        <td>얇으면 PML 반사가 R에 섞임</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">sx = sy</code></td>
        <td>16</td>
        <td>코너 주변 방사가 PML에 닿기 전 퍼질 여유</td>
        <td>좁히면 방사가 monitor에 되돌아옴</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">src_x</code>, <code class="language-plaintext highlighter-rouge">refl_x</code></td>
        <td>−6.5, −5.5</td>
        <td>source는 PML 밖 0.5, 반사 단면은 source <strong>하류</strong> 1.0</td>
        <td>반사 단면이 source 상류면 입사 성분 분리 실패</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">span</code></td>
        <td>w + 2</td>
        <td>core 양쪽 1a씩 evanescent tail 포함</td>
        <td>core 폭만 잡으면 P_in 과소 → T 과대</td>
      </tr>
    </tbody>
  </table>

  <figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/05/00_source.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/00_source.png" alt="굽힘 실험 가우시안 광원의 시간 파형과 대역 끝이 약한 스펙트럼" loading="lazy" />
  </a>
  <figcaption>source의 시간 파형(왼쪽)과 power 스펙트럼(오른쪽). width = 1/fwidth = 10, 펄스 정점 t0 = 50. monitor 대역(1162–2325 nm) 가장자리의 source power는 중심의 0.005%다. 그래서 §5 스펙트럼의 양 끝 값은 0에 가까운 수를 0에 가까운 수로 나눈 것이고, 경향만 본다.</figcaption>
</figure>

  <p><strong>강의 노트북과의 차이</strong>: 강의 week 6은 n 3.4/1.44, 폭 0.6 µm의 곡선 bend에서 radius 0.6–3.0 µm를 훑는다. 이 글은 공식 sharp bend(ε = 12, w = 1a)를 기준값으로 두고, 같은 구조의 코너만 둥글려 radius를 훑는다.</p>

</details>

<details>
  <summary>코드 단계별 설명 보기</summary>

  <blockquote>
    <p>읽는 순서는 04편과 같다: 단위·파라미터 → 재료·구조 → source → Simulation·경계 → monitor → 실행·종료 → 후처리.
이번에는 run이 두 번이라 ⑤·⑥이 기준 run과 bend run에 한 번씩 나온다.</p>
  </blockquote>

  <h3 id="section-1">① 단위와 파라미터 — 어떤 숫자를 고정하는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="c1"># Dimensionless units as in the official tutorial: 1 length unit = a (think 1 um).
</span><span class="n">eps_wg</span> <span class="o">=</span> <span class="mf">12.0</span>            <span class="c1"># waveguide permittivity (n = sqrt(12) = 3.46)
</span><span class="n">w</span> <span class="o">=</span> <span class="mf">1.0</span>                  <span class="c1"># waveguide width
</span><span class="n">fcen</span> <span class="o">=</span> <span class="mf">0.15</span>              <span class="c1"># center frequency -&gt; wavelength 1/0.15 = 6.67 units
</span><span class="n">df</span> <span class="o">=</span> <span class="mf">0.1</span>                 <span class="c1"># source bandwidth
</span><span class="n">nfreq</span> <span class="o">=</span> <span class="mi">11</span>               <span class="c1"># number of frequencies in the flux monitors
</span>
<span class="n">resolution</span> <span class="o">=</span> <span class="mi">25</span>          <span class="c1"># pixels per unit -&gt; width = 25 px, wavelength in the guide (1.92) = 48 px
</span><span class="n">dpml</span> <span class="o">=</span> <span class="mf">1.0</span>               <span class="c1"># PML thickness
</span><span class="n">sx</span> <span class="o">=</span> <span class="n">sy</span> <span class="o">=</span> <span class="mf">16.0</span>           <span class="c1"># square cell, PML included
</span>
<span class="n">ycen</span> <span class="o">=</span> <span class="o">-</span><span class="mf">4.0</span>              <span class="c1"># y of the input (horizontal) arm
</span><span class="n">xcen</span> <span class="o">=</span> <span class="o">+</span><span class="mf">4.0</span>              <span class="c1"># x of the output (vertical) arm  -&gt; corner at (xcen, ycen)
</span>
<span class="n">src_x</span> <span class="o">=</span> <span class="o">-</span><span class="mf">6.5</span>             <span class="c1"># source: 0.5 outside the left PML (PML edge at x = -7)
</span><span class="n">refl_x</span> <span class="o">=</span> <span class="o">-</span><span class="mf">5.5</span>            <span class="c1"># reflection flux plane: downstream of the source
</span><span class="n">tran_straight_x</span> <span class="o">=</span> <span class="o">+</span><span class="mf">6.5</span>   <span class="c1"># transmission plane for the straight reference run
</span><span class="n">tran_bend_y</span> <span class="o">=</span> <span class="o">+</span><span class="mf">6.5</span>       <span class="c1"># transmission plane for the bend run (on the vertical arm)
</span><span class="n">span</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">w</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span>   <span class="c1"># source / monitor line: core + 1 unit on each side (evanescent tail)
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 공식 튜토리얼의 무차원 설정(ε = 12, w = 1, f = 0.15)과 코너 위치, source·monitor 좌표를 고정한다.</li>
    <li><strong>왜</strong>: 04편은 1 = 1 µm였지만 여기서는 길이 단위 a를 정하지 않는다. Maxwell 방정식은 scale-invariant라서 a = 1 µm로 읽으면 파장 6.67 µm, a = 0.23 µm로 읽으면 1.55 µm 결과가 그대로 된다. 이 글의 그림은 그 둘째 읽기(a = 232.5 nm)로 환산해 파장은 nm, 길이는 µm로 표시한다. 좌표는 모두 PML 경계(±7)를 기준으로 잡는다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">refl_x</code>를 source보다 왼쪽(상류)에 두면 입사 펄스가 그 단면을 지나지 않아 <code class="language-plaintext highlighter-rouge">load_minus_flux_data</code>가 뺄 것이 없고 R이 엉뚱해진다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: <code class="language-plaintext highlighter-rouge">df = 0.1</code>은 대역 5–10a로 넓다. 가장자리 파장에서는 source power가 거의 없어 T·R이 튄다. 중심 근처만 믿는다(§5).</p>
  </blockquote>

  <h3 id="section-2">② 재료와 구조 — 무엇이 어디에 있는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">make_geometry</span><span class="p">(</span><span class="n">bend</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
    <span class="s">"""Straight reference (bend=False) or the L-shaped bend (bend=True). Same width and material."""</span>
    <span class="n">wg</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">epsilon</span><span class="o">=</span><span class="n">eps_wg</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">bend</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">w</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">)]</span>
    <span class="n">horizontal</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="o">-</span><span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">xcen</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">ycen</span><span class="p">),</span>
                          <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">xcen</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">w</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">)</span>   <span class="c1"># left PML -&gt; corner
</span>    <span class="n">vertical</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xcen</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">ycen</span> <span class="o">-</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)),</span>
                        <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">ycen</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">)</span>     <span class="c1"># corner -&gt; top PML
</span>    <span class="k">return</span> <span class="p">[</span><span class="n">horizontal</span><span class="p">,</span> <span class="n">vertical</span><span class="p">]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 같은 함수가 플래그 하나로 직선 기준 구조와 L자 bend 구조를 만든다. 두 <code class="language-plaintext highlighter-rouge">Block</code>은 코너에서 폭 w만큼 겹쳐 빈틈 없는 직각을 이룬다.</li>
    <li><strong>왜</strong>: 기준 run과 bend run은 구조만 다르고 나머지는 같아야 정규화가 성립한다. 함수로 묶으면 재료·폭·좌표가 어긋날 여지가 없다. 수평 암은 왼쪽 PML을, 수직 암은 위쪽 PML을 관통해야 끝면 반사가 없다.</li>
    <li><strong>틀리면</strong>: 수평 암을 코너에서 <code class="language-plaintext highlighter-rouge">xcen - w/2</code>까지만 그리면 코너에 빈 사각형이 생겨 R이 커진다. 수직 암이 cell 안에서 끝나면 끝면 반사가 T에 섞인다.</li>
  </ul>

  <h3 id="section-3">②′ 둥근 코너 — 사분원 고리</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">r</span> <span class="o">=</span> <span class="n">radius</span>
<span class="n">cx</span><span class="p">,</span> <span class="n">cy</span> <span class="o">=</span> <span class="n">xcen</span> <span class="o">-</span> <span class="n">r</span><span class="p">,</span> <span class="n">ycen</span> <span class="o">+</span> <span class="n">r</span>                      <span class="c1"># center of the quarter ring
</span><span class="n">big</span> <span class="o">=</span> <span class="n">r</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="mf">1.0</span>
<span class="n">geom</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">r</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">),</span>    <span class="c1"># outer disk: waveguide
</span>        <span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">r</span> <span class="o">-</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">air</span><span class="p">),</span>   <span class="c1"># inner disk: air -&gt; ring
</span>        <span class="c1"># keep only the lower-right quadrant (x &gt; cx, y &lt; cy): cover the other three with air
</span>        <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span> <span class="o">-</span> <span class="n">big</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">cy</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">big</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">big</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">air</span><span class="p">),</span>
        <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span> <span class="o">+</span> <span class="n">big</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">cy</span> <span class="o">+</span> <span class="n">big</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">big</span><span class="p">,</span> <span class="n">big</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">air</span><span class="p">)]</span>
<span class="c1"># the two arms are appended AFTER this list, so they are drawn on top of the air blocks
</span></code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 반지름 r + w/2의 원판에서 r − w/2의 원판을 빼 고리를 만들고, 공기 블록으로 세 사분면을 덮어 오른쪽 아래 1/4만 남긴다. 수평 암은 x = xcen − r에서, 수직 암은 y = ycen + r에서 고리와 만난다.</li>
    <li><strong>왜</strong>: Meep의 geometry는 나중 객체가 앞 객체를 덮어쓴다. 그래서 “원판 → 공기 원판 → 공기 블록 → 암” 순서가 곧 차집합 연산이다. r = 0이면 고리가 없고 sharp 코너로 돌아간다.</li>
    <li><strong>틀리면</strong>: 암을 공기 블록보다 먼저 넣으면 블록이 암의 끝을 지운다. 공기 블록을 빠뜨리면 고리 전체가 남아 도파로가 원을 그린다.</li>
  </ul>

  <h3 id="source----">③ Source — 빛을 어떻게 넣는가</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># A plain Ez line source (not an eigenmode source), as in the official tutorial.
</span><span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">df</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                     <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">src_x</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">)]</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 수평 암을 가로지르는 길이 3a의 세로선에서 Ez 성분 가우시안 펄스를 쏜다.</li>
    <li><strong>왜</strong>: 04편의 <code class="language-plaintext highlighter-rouge">EigenModeSource</code>와 달리 모드 모양을 맞추지 않은 단순 선 source다. 모드가 아닌 성분도 섞여 들어가지만, 기준 run이 실제로 도파로를 따라간 power를 재므로 그 몫은 P_in에서 빠진다. 2-run 정규화가 필요한 이유 중 하나다.</li>
    <li><strong>틀리면</strong>: <code class="language-plaintext highlighter-rouge">component</code>를 <code class="language-plaintext highlighter-rouge">Ey</code>로 바꾸면 2D에서 면내 편광이 되어 다른 모드(다른 confinement)를 보게 된다. <code class="language-plaintext highlighter-rouge">size</code>를 core 폭만큼만 잡아도 돌아가지만 모드 결합이 나빠져 방사 잡음이 늘어난다.</li>
  </ul>

  <h3 id="simulation-----pml">④ Simulation과 경계 — 계산 상자와 PML</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">make_sim</span><span class="p">(</span><span class="n">bend</span><span class="p">:</span> <span class="nb">bool</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">sy</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span>
                         <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">dpml</span><span class="p">)],</span>
                         <span class="n">geometry</span><span class="o">=</span><span class="n">make_geometry</span><span class="p">(</span><span class="n">bend</span><span class="p">),</span> <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 16 × 16 상자, 네 변 PML 1a, 같은 source·해상도로 구조만 바꿔 <code class="language-plaintext highlighter-rouge">Simulation</code>을 만드는 함수.</li>
    <li><strong>왜</strong>: Meep의 <code class="language-plaintext highlighter-rouge">Simulation</code> 객체는 run이 끝나면 필드가 남아 있어 재사용하기 어렵다. 매 run마다 새로 만드는 것이 가장 안전하고, 함수로 묶으면 두 run의 설정 일치가 보장된다.</li>
    <li><strong>틀리면</strong>: 두 run에서 <code class="language-plaintext highlighter-rouge">resolution</code>이나 <code class="language-plaintext highlighter-rouge">cell_size</code>가 다르면 격자 위치가 달라져 <code class="language-plaintext highlighter-rouge">load_minus_flux_data</code>가 크기가 다른 배열을 빼려다 오류를 낸다.</li>
  </ul>

  <h3 id="monitor-----run">⑤ Monitor — 무엇을 재는가 (기준 run)</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">bend</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">refl</span>  <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">refl_x</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">))</span>
<span class="n">tran0</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">tran_straight_x</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 직선 구조에 반사 단면(x = −5.5)과 투과 단면(x = +6.5)을 둔다. <code class="language-plaintext highlighter-rouge">add_flux</code>는 그 선을 지나는 Poynting flux를 주파수별로 누적한다.</li>
    <li><strong>왜</strong>: 직선은 반사가 없으므로 투과 단면 flux가 곧 source가 도파로에 넣은 power P_in이다. 반사 단면은 이 run에서는 입사 펄스를 기록하는 용도다.</li>
    <li><strong>틀리면</strong>: 투과 단면을 PML 안에 두면 이미 흡수된 값을 재서 P_in이 작아지고 T가 과대평가된다.</li>
  </ul>

  <h3 id="run">⑥ 실행과 종료 조건 (기준 run)</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span>
            <span class="mi">25</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">tran_straight_x</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>

<span class="n">P_in</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">tran0</span><span class="p">))</span>     <span class="c1"># what actually travels down the guide = input power
</span><span class="n">refl_data</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_flux_data</span><span class="p">(</span><span class="n">refl</span><span class="p">)</span>       <span class="c1"># incident fields at the reflection plane (to subtract later)
</span><span class="n">freqs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_flux_freqs</span><span class="p">(</span><span class="n">tran0</span><span class="p">))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 투과 단면 근처의 Ez가 최대값의 10⁻⁶으로 줄 때까지 돌리고, P_in과 반사 단면의 DFT 필드 데이터를 꺼내 둔다.</li>
    <li><strong>왜</strong>: <code class="language-plaintext highlighter-rouge">get_fluxes</code>는 숫자(power)지만 <code class="language-plaintext highlighter-rouge">get_flux_data</code>는 필드 자체다. 다음 run에서 필드 수준에서 빼야 간섭항까지 정확히 제거된다. power끼리 빼면 틀린다.</li>
    <li><strong>틀리면</strong>: 종료가 이르면 펄스 꼬리가 단면을 다 지나지 못해 P_in이 작아지고, 다음 run의 입사 데이터도 불완전해 R에 잔여 입사 성분이 남는다.</li>
  </ul>

  <h3 id="monitor----bend-run">⑤′ Monitor — 무엇을 재는가 (bend run)</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">bend</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">refl</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">refl_x</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">))</span>
<span class="n">sim</span><span class="p">.</span><span class="n">load_minus_flux_data</span><span class="p">(</span><span class="n">refl</span><span class="p">,</span> <span class="n">refl_data</span><span class="p">)</span>  <span class="c1"># subtract the incident part -&gt; this monitor now sees reflection only
</span><span class="n">tran</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span>
                    <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xcen</span><span class="p">,</span> <span class="n">tran_bend_y</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: bend 구조에 같은 위치의 반사 단면을 만들고, 기준 run의 입사 데이터를 음수로 미리 채운다. 투과 단면은 수직 암 위(y = +6.5)의 가로선이다.</li>
    <li><strong>왜</strong>: 반사 단면에는 입사 펄스(오른쪽으로)와 반사 펄스(왼쪽으로)가 모두 지나간다. 입사 성분을 미리 빼 두면 run이 끝났을 때 반사 성분만 남는다.</li>
    <li><strong>틀리면</strong>: 이 줄을 빼먹으면 반사 단면에 입사 성분도 남는다. 같은 부호식으로 계산한 R은 과소평가되거나 음수가 될 수 있다.</li>
  </ul>

  <blockquote>
    <p><strong>함정</strong>: 투과 단면의 <code class="language-plaintext highlighter-rouge">size</code>가 <code class="language-plaintext highlighter-rouge">(w + 2, 0)</code>, 즉 가로선이다. 수직 암에서는 빛이 +y로 가므로 단면은 x 방향으로 펼쳐야 한다. <code class="language-plaintext highlighter-rouge">span</code>을 그대로 쓰면 세로선이 되어 빛과 평행하게 놓인다.</p>
  </blockquote>

  <h3 id="bend-run">⑥′ 실행과 종료 조건 (bend run)</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span>
            <span class="mi">25</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xcen</span><span class="p">,</span> <span class="n">tran_bend_y</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 이번에는 수직 암 끝(투과 단면 위치)의 Ez가 줄어들 때까지 돌린다.</li>
    <li><strong>왜</strong>: 감시점은 빛이 마지막으로 지나가는 곳이어야 한다. bend에서는 그곳이 수직 암 끝이다.</li>
    <li><strong>틀리면</strong>: 감시점을 기준 run과 같은 (+6.5, −4)로 두면 bend 구조에서는 그곳에 도파로가 없어 필드가 금방 사라지고, 투과 펄스가 다 지나기 전에 run이 끝난다.</li>
  </ul>

  <h3 id="section-4">⑦ 후처리 — 숫자로 바꾸기</h3>

  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">T</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">tran</span><span class="p">))</span> <span class="o">/</span> <span class="n">P_in</span>      <span class="c1"># transmitted fraction
</span><span class="n">R</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">refl</span><span class="p">))</span> <span class="o">/</span> <span class="n">P_in</span>     <span class="c1"># backward flux is negative -&gt; flip the sign
</span><span class="n">L</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">-</span> <span class="n">T</span> <span class="o">-</span> <span class="n">R</span>                               <span class="c1"># what is left: radiated out at the corner
</span><span class="n">ic</span> <span class="o">=</span> <span class="n">nfreq</span> <span class="o">//</span> <span class="mi">2</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"T = </span><span class="si">{</span><span class="n">T</span><span class="p">[</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, R = </span><span class="si">{</span><span class="n">R</span><span class="p">[</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, radiation loss = </span><span class="si">{</span><span class="n">L</span><span class="p">[</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div>  </div>

  <ul>
    <li><strong>무엇</strong>: 두 flux를 P_in으로 나눠 T·R을 얻고, 1에서 뺀 나머지를 방사 손실로 해석한다.</li>
    <li><strong>왜</strong>: Meep의 flux는 방향이 있다. 반사 단면의 flux는 −x 방향이라 음수로 나오므로 부호를 뒤집어야 반사된 양이 된다. <code class="language-plaintext highlighter-rouge">1 - T - R</code>은 방사 monitor를 따로 두지 않았을 때의 잔여 추정이다.</li>
    <li><strong>틀리면</strong>: 부호를 안 뒤집으면 R이 음수, L이 1을 넘는다.</li>
  </ul>

</details>

<h2 id="interpret">5. 해석 · 측정값과 한계를 함께 읽기</h2>

<h3 id="투과가-낮아진-이유를-숫자로-확인하기">투과가 낮아진 이유를 숫자로 확인하기</h3>

<table>
  <thead>
    <tr>
      <th>1550 nm의 구조</th>
      <th>T</th>
      <th>R</th>
      <th>L = 1 − T − R</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>날카로운 코너</td>
      <td>0.1997</td>
      <td>0.2202</td>
      <td>0.5801</td>
    </tr>
    <tr>
      <td>반지름 3a = 0.6975 µm</td>
      <td>0.9859</td>
      <td>0.0003</td>
      <td>0.0138</td>
    </tr>
  </tbody>
</table>

<p>sharp bend에서는 입력의 약 20%만 위쪽 암에 도달하고 잔여 방사가 약 58%입니다. 반지름을 늘리면 반사는 약 1a에서 먼저 작아지고, 방사는 더 천천히 줄어듭니다. 이 사례의 변화가 완만해지는 구간은 1.5–2a 부근입니다.</p>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/05/03_spectrum.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/03_spectrum.png" alt="파장별 sharp bend의 투과율, 반사율과 잔여 방사율" loading="lazy" />
  </a>
  <figcaption>중심 파장 1550 nm(점선) 근처에서 방사(초록)가 가장 크고 T(파랑)는 0.2 부근이다. 대역 가장자리(1160 nm, 2325 nm)는 source power가 작아 값이 튀므로 경향만 본다. 파장이 길수록 T가 올라가는 것은 모드가 덜 갇혀(cladding으로 더 퍼져) 코너의 급격함을 덜 느끼기 때문이다.</figcaption>
</figure>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/05/04_radius_sweep.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/04_radius_sweep.png" alt="코너 반지름을 늘릴 때 투과율이 높아지고 반사·방사가 줄어드는 측정 곡선" loading="lazy" />
  </a>
  <figcaption>같은 구조에서 코너 반지름만 바꿨을 때의 T, R, 방사. 반지름 0이 위의 sharp bend다. 축은 a = 232.5 nm로 환산한 µm.</figcaption>
</figure>

<figure class="lesson-figure">
  <a href="/meep-examples/assets/meep/05/05_field_round.png" data-lightbox="">
    <img src="/meep-examples/assets/meep/05/05_field_round.png" alt="반지름 3a인 둥근 도파로의 실제 Re(Ez)와 진폭 필드" loading="lazy" />
  </a>
  <figcaption>반지름 3a = 0.70 µm. 수평 암의 정상파 마디가 사라지고(반사 0.03%), 코너 밖으로 새는 빛이 거의 없다.</figcaption>
</figure>

<aside class="lesson-note">
  <p><strong>숫자의 유효 자리도 결과입니다.</strong> sharp bend의 T는 해상도 25→40에서 0.1997→0.1894, PML 두께 1→1.5와 monitor 이동을 함께 바꾸면 0.1703으로 변합니다. 따라서 T ≈ 0.2의 경향을 읽어야 합니다. 반지름 4a의 T = 1.0031은 이득이 아니라 수치 오차입니다. source power가 중심의 0.005%인 대역 끝의 비율은 신뢰도가 낮습니다.</p>
</aside>

<details>
  <summary>전체 측정표·예측 비교·수렴성 기록 보기</summary>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>값 @ 1550 nm (6.67a)</th>
        <th>비교 대상</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>T</td>
        <td>0.1997</td>
        <td>공식 튜토리얼도 “낮은 T” 시연 목적</td>
      </tr>
      <tr>
        <td>R</td>
        <td>0.2202</td>
        <td>—</td>
      </tr>
      <tr>
        <td>L (방사, 잔여)</td>
        <td>0.5801</td>
        <td>—</td>
      </tr>
      <tr>
        <td>T + R</td>
        <td>0.4199</td>
        <td>≤ 1 성립</td>
      </tr>
    </tbody>
  </table>

  <h3 id="radius-sweep">코너를 둥글리면: radius sweep</h3>

  <table>
    <thead>
      <tr>
        <th>반지름</th>
        <th>µm</th>
        <th>T</th>
        <th>R</th>
        <th>방사</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0 (sharp)</td>
        <td>0</td>
        <td>0.200</td>
        <td>0.220</td>
        <td>0.580</td>
      </tr>
      <tr>
        <td>0.5a</td>
        <td>0.12</td>
        <td>0.487</td>
        <td>0.052</td>
        <td>0.462</td>
      </tr>
      <tr>
        <td>1a</td>
        <td>0.23</td>
        <td>0.746</td>
        <td>0.001</td>
        <td>0.253</td>
      </tr>
      <tr>
        <td>1.5a</td>
        <td>0.35</td>
        <td>0.907</td>
        <td>0.001</td>
        <td>0.092</td>
      </tr>
      <tr>
        <td>2a</td>
        <td>0.47</td>
        <td>0.964</td>
        <td>0.000</td>
        <td>0.036</td>
      </tr>
      <tr>
        <td>3a</td>
        <td>0.70</td>
        <td>0.986</td>
        <td>0.000</td>
        <td>0.014</td>
      </tr>
      <tr>
        <td>4a</td>
        <td>0.93</td>
        <td>1.003</td>
        <td>0.000</td>
        <td>−0.003</td>
      </tr>
      <tr>
        <td>6a</td>
        <td>1.40</td>
        <td>1.000</td>
        <td>0.000</td>
        <td>0.000</td>
      </tr>
    </tbody>
  </table>

  <p>반사는 반지름 1a(파장의 1/7)에서 이미 사라진다. 방사는 더 천천히 줄어 1.5a에서 10% 아래로, 3a에서 1% 대로 내려간다. 손실이 꺾이는 무릎(knee)은 1.5–2a, 즉 도파로 안 파장(1.92a)의 한 배 근처다. 그보다 큰 반지름은 면적만 늘린다. 4a에서 T가 1을 0.3% 넘는 것은 정규화 run과 bend run의 수치 오차이지 이득이 아니다.</p>

  <h3 id="sharp-bend">수렴성 (sharp bend)</h3>

  <table>
    <thead>
      <tr>
        <th>resolution</th>
        <th>dpml</th>
        <th>T</th>
        <th>R</th>
        <th>방사</th>
        <th>비고</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>25</td>
        <td>1.0</td>
        <td>0.200</td>
        <td>0.220</td>
        <td>0.580</td>
        <td>기준</td>
      </tr>
      <tr>
        <td>10</td>
        <td>1.0</td>
        <td>0.198</td>
        <td>0.229</td>
        <td>0.573</td>
        <td>공식 예제 해상도</td>
      </tr>
      <tr>
        <td>40</td>
        <td>1.0</td>
        <td>0.189</td>
        <td>0.224</td>
        <td>0.587</td>
        <td>해상도 1.6배</td>
      </tr>
      <tr>
        <td>25</td>
        <td>1.5</td>
        <td>0.170</td>
        <td>0.217</td>
        <td>0.612</td>
        <td>PML 두껍게. source·monitor 면이 0.5a 안쪽으로</td>
      </tr>
    </tbody>
  </table>

  <p>해상도 10에서 40까지 T는 5% 안에서 움직인다. 그런데 PML을 두껍게 하면서 source와 monitor 면을 0.5a 안쪽으로 옮기자 T가 15% 내려갔다. 코너에서 방사된 빛이 투과 단면과 PML 사이에서 어떻게 잡히느냐에 따라 값이 달라진다는 뜻이다. sharp bend의 T = 0.20은 첫째 자리까지만 의미가 있다. 둥근 bend(R ≥ 2a)는 방사가 거의 없어서 이 민감도가 사라진다.</p>

  <h3 id="section-5">예측과 비교</h3>

  <table>
    <thead>
      <tr>
        <th>물리량</th>
        <th>내 예측 (§2)</th>
        <th>시뮬레이션</th>
        <th>판정</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>T</td>
        <td>0.5 미만</td>
        <td>0.20</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>R</td>
        <td>수십 %</td>
        <td>0.22</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>L</td>
        <td>가장 큰 몫</td>
        <td>0.58</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>필드 모양</td>
        <td>코너 방사 lobe, 수직 암 희미</td>
        <td>그림 확인</td>
        <td>✅</td>
      </tr>
      <tr>
        <td>T + R</td>
        <td>≤ 1</td>
        <td>0.42</td>
        <td>✅</td>
      </tr>
    </tbody>
  </table>

  <p>방향은 모두 맞았지만 T = 0.20이라는 값은 계산해 봐야 안다. T + R ≤ 1은 예측이 아니라 검산이다. 깨지면 물리가 아니라 코드가 틀린 것이다.</p>

  <p><strong>검증 체크</strong>: T + R = 0.42 ≤ 1 · source(x = −6.5)·반사 단면(−5.5)·투과 단면(y = 6.5) 모두 PML(|x|, |y| &gt; 7) 밖 · 두 run 모두 field decay 기준 종료.</p>

  <h3 id="section-6">주장할 수 있는 것 / 없는 것</h3>

  <ul>
    <li>할 수 있는 것: sharp bend는 power의 절반 이상을 방사로 잃는다. 반지름을 도파로 안 파장의 한 배(1.5–2a, 0.35–0.47 µm) 이상 주면 손실이 10% 아래로 떨어지고, 3a 이상에서는 더 얻을 것이 없다.</li>
    <li>할 수 없는 것: sharp bend의 T = 0.20의 둘째 자리. 해상도와 monitor 위치에 따라 0.17–0.20으로 움직인다. 3D 도파로나 다른 굴절률 대비에서의 knee 위치. 방사 monitor 없이 잔여로 추정한 방사량의 정확한 값.</li>
  </ul>

</details>

<details>
  <summary>증상별 점검표 보기</summary>

  <table>
    <thead>
      <tr>
        <th>증상</th>
        <th>원인</th>
        <th>고치는 법</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>반사율 과소평가·음수</td>
        <td><code class="language-plaintext highlighter-rouge">load_minus_flux_data</code>를 빼먹음</td>
        <td>bend run에서 반사 monitor를 만든 <strong>직후</strong> 호출</td>
      </tr>
      <tr>
        <td>R이 음수</td>
        <td>뒤로 가는 flux 부호를 안 뒤집음</td>
        <td><code class="language-plaintext highlighter-rouge">R = -get_fluxes(refl) / P_in</code></td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">load_minus_flux_data</code> 배열 크기 오류</td>
        <td>두 run의 resolution·cell·monitor 위치 불일치</td>
        <td><code class="language-plaintext highlighter-rouge">make_sim</code> 같은 함수로 두 run 생성</td>
      </tr>
      <tr>
        <td>투과 T ≈ 0</td>
        <td>투과 단면이 세로선(<code class="language-plaintext highlighter-rouge">span</code>)으로 빛과 평행</td>
        <td>수직 암에서는 <code class="language-plaintext highlighter-rouge">size=(w+2, 0)</code> 가로선</td>
      </tr>
      <tr>
        <td>스펙트럼 가장자리가 튐</td>
        <td>대역이 넓어 가장자리 source power ≈ 0</td>
        <td><code class="language-plaintext highlighter-rouge">df</code>를 줄이거나 중심 ±30%만 해석</td>
      </tr>
      <tr>
        <td>R이 이상하게 큼</td>
        <td>반사 단면이 source 상류, 또는 PML 얇음</td>
        <td>반사 단면은 source <strong>하류</strong>, <code class="language-plaintext highlighter-rouge">dpml ≥ λ/6</code></td>
      </tr>
    </tbody>
  </table>

</details>

<h2 id="check">6. 확인 · 두 질문에 답해보기</h2>

<h3 id="1-입사장을-빼는-줄을-지우면-반사율은-어떻게-달라질까요">1. 입사장을 빼는 줄을 지우면 반사율은 어떻게 달라질까요?</h3>

<details>
  <summary>설명 확인하기</summary>

  <p>반사 monitor에 입사와 반사 성분이 함께 남습니다. 이때 같은 마이너스 부호로 R을 계산하면 반사율을 과소평가하거나 음수로 얻을 수 있습니다. 이 줄은 필드를 바꾸는 source가 아니므로 투과장의 전파 자체를 바꾸지는 않습니다.</p>

</details>

<h3 id="2-l--1--t--r가-058이면-방사를-정확히-58-측정한-것일까요">2. L = 1 − T − R가 0.58이면 방사를 정확히 58% 측정한 것일까요?</h3>

<details>
  <summary>설명 확인하기</summary>

  <p>아닙니다. 여기서는 흡수 없는 모델의 잔여를 방사로 해석했습니다. monitor 위치·PML·격자 오차도 잔여에 영향을 주므로 직접 방사 flux 측정과 수렴성 확인 없이는 그 정밀도를 주장할 수 없습니다.</p>

</details>

<h2 id="reference">7. 참고 · 전체 코드와 원본 기록</h2>

<p>아래 전체 프로그램은 원본 그대로입니다. 실행 환경과 결과 기록을 함께 확인하세요.</p>

<details>
<summary>bend90.py (클릭해서 펼치기)</summary>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="s">"""Meep Example 05 - Bent waveguide and the radius trade-off (two-run flux normalization).

A dielectric waveguide (eps = 12, width 1) turns a 90 degree corner.
Run 1: straight waveguide  -&gt; input power P_in and the "incident" flux data at the reflection plane.
Run 2: bent waveguide      -&gt; transmitted flux (vertical arm) and reflected flux (incident part subtracted).
T = P_tran / P_in,  R = -P_refl / P_in,  radiation loss = 1 - T - R.
The sharp corner (radius 0) follows the official bend-flux tutorial; then the corner is rounded
with a quarter-ring of radius R and T is swept over R to find where the loss disappears.

Run:  python bend90.py            (~3 min on one core: sharp + radius sweep + convergence)
Out:  00_source.png, 01_layout.png, 02_field.png, 03_spectrum.png, 04_radius_sweep.png,
      05_field_round.png, 06_anim_sharp.gif, 06_anim_round.gif, result.json   (-&gt; ../assets/05/)
"""</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib</span>
<span class="n">matplotlib</span><span class="p">.</span><span class="n">use</span><span class="p">(</span><span class="s">"Agg"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">meep</span> <span class="k">as</span> <span class="n">mp</span>

<span class="n">sys</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)))</span>
<span class="kn">from</span> <span class="nn">blogfig</span> <span class="kn">import</span> <span class="p">(</span><span class="n">Label</span><span class="p">,</span> <span class="n">animate_fields</span><span class="p">,</span> <span class="n">annotated_layout</span><span class="p">,</span> <span class="n">field_figure</span><span class="p">,</span> <span class="n">line_figure</span><span class="p">,</span>   <span class="c1"># noqa: E402
</span>                     <span class="n">record_frames</span><span class="p">,</span> <span class="n">source_figure</span><span class="p">,</span> <span class="n">spectrum_figure</span><span class="p">)</span>

<span class="n">OUT</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)),</span> <span class="s">".."</span><span class="p">,</span> <span class="s">"assets"</span><span class="p">,</span> <span class="s">"05"</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="c1"># ---------------------------------------------------------------- (1) units &amp; parameters
# Dimensionless units as in the official tutorial: 1 length unit = a (think 1 um).
</span><span class="n">eps_wg</span> <span class="o">=</span> <span class="mf">12.0</span>            <span class="c1"># waveguide permittivity (n = sqrt(12) = 3.46)
</span><span class="n">w</span> <span class="o">=</span> <span class="mf">1.0</span>                  <span class="c1"># waveguide width
</span><span class="n">fcen</span> <span class="o">=</span> <span class="mf">0.15</span>              <span class="c1"># center frequency -&gt; wavelength 1/0.15 = 6.67 units
</span><span class="n">df</span> <span class="o">=</span> <span class="mf">0.1</span>                 <span class="c1"># source bandwidth
</span><span class="n">nfreq</span> <span class="o">=</span> <span class="mi">11</span>               <span class="c1"># number of frequencies in the flux monitors
</span>
<span class="c1"># Physical reading used only for the figures: choose a so that the center wavelength is 1550 nm.
</span><span class="n">a_nm</span> <span class="o">=</span> <span class="mi">1550</span> <span class="o">*</span> <span class="n">fcen</span>       <span class="c1"># = 232.5 nm per unit  -&gt; waveguide width 233 nm, cell 3.72 um
</span><span class="n">a_um</span> <span class="o">=</span> <span class="n">a_nm</span> <span class="o">/</span> <span class="mi">1000</span>

<span class="n">RESOLUTION</span> <span class="o">=</span> <span class="mi">25</span>          <span class="c1"># pixels per unit -&gt; width = 25 px, wavelength in the guide (1.92) = 48 px
</span><span class="n">DPML</span> <span class="o">=</span> <span class="mf">1.0</span>               <span class="c1"># PML thickness
</span><span class="n">sx</span> <span class="o">=</span> <span class="n">sy</span> <span class="o">=</span> <span class="mf">16.0</span>           <span class="c1"># square cell, PML included
</span>
<span class="n">ycen</span> <span class="o">=</span> <span class="o">-</span><span class="mf">4.0</span>              <span class="c1"># y of the input (horizontal) arm
</span><span class="n">xcen</span> <span class="o">=</span> <span class="o">+</span><span class="mf">4.0</span>              <span class="c1"># x of the output (vertical) arm  -&gt; corner at (xcen, ycen)
</span><span class="n">span</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">w</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span>   <span class="c1"># source / monitor line: core + 1 unit on each side (evanescent tail)
</span>

<span class="k">def</span> <span class="nf">positions</span><span class="p">(</span><span class="n">dpml</span><span class="p">):</span>
    <span class="s">"""Source and monitor planes measured from the PML edge, so a thicker PML keeps them outside it."""</span>
    <span class="n">edge</span> <span class="o">=</span> <span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">dpml</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"src_x"</span><span class="p">:</span> <span class="o">-</span><span class="n">edge</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">,</span>          <span class="c1"># source: 0.5 outside the left PML
</span>            <span class="s">"refl_x"</span><span class="p">:</span> <span class="o">-</span><span class="n">edge</span> <span class="o">+</span> <span class="mf">1.5</span><span class="p">,</span>         <span class="c1"># reflection flux plane: downstream of the source
</span>            <span class="s">"tran_straight_x"</span><span class="p">:</span> <span class="n">edge</span> <span class="o">-</span> <span class="mf">0.5</span><span class="p">,</span>  <span class="c1"># transmission plane for the straight reference run
</span>            <span class="s">"tran_bend_y"</span><span class="p">:</span> <span class="n">edge</span> <span class="o">-</span> <span class="mf">0.5</span><span class="p">}</span>      <span class="c1"># transmission plane for the bend run (on the vertical arm)
</span>

<span class="c1"># ---------------------------------------------------------------- (2) materials &amp; geometry
</span><span class="k">def</span> <span class="nf">make_geometry</span><span class="p">(</span><span class="n">bend</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">radius</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">):</span>
    <span class="s">"""Straight reference (bend=False), sharp corner (radius=0) or rounded corner (radius&gt;0).

    The rounded corner is a quarter ring: outer cylinder (waveguide) minus inner cylinder (air),
    cut down to one quadrant with air blocks; the two arms are drawn last so they stay intact.
    """</span>
    <span class="n">wg</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">epsilon</span><span class="o">=</span><span class="n">eps_wg</span><span class="p">)</span>
    <span class="n">air</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Medium</span><span class="p">(</span><span class="n">epsilon</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">bend</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">inf</span><span class="p">,</span> <span class="n">w</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">)]</span>
    <span class="n">r</span> <span class="o">=</span> <span class="n">radius</span>
    <span class="n">cx</span><span class="p">,</span> <span class="n">cy</span> <span class="o">=</span> <span class="n">xcen</span> <span class="o">-</span> <span class="n">r</span><span class="p">,</span> <span class="n">ycen</span> <span class="o">+</span> <span class="n">r</span>                      <span class="c1"># center of the quarter ring
</span>    <span class="n">geom</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">if</span> <span class="n">r</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">big</span> <span class="o">=</span> <span class="n">r</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="mf">1.0</span>
        <span class="n">geom</span> <span class="o">+=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">r</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">),</span>
                 <span class="n">mp</span><span class="p">.</span><span class="n">Cylinder</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="n">r</span> <span class="o">-</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">air</span><span class="p">)]</span>
        <span class="c1"># keep only the lower-right quadrant (x &gt; cx, y &lt; cy)
</span>        <span class="n">geom</span> <span class="o">+=</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span> <span class="o">-</span> <span class="n">big</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">cy</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">big</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">big</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">air</span><span class="p">),</span>
                 <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">cx</span> <span class="o">+</span> <span class="n">big</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">cy</span> <span class="o">+</span> <span class="n">big</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">big</span><span class="p">,</span> <span class="n">big</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">air</span><span class="p">)]</span>
    <span class="c1"># sharp corner: the arms overlap by w x w so the outer corner is filled (official geometry);
</span>    <span class="c1"># rounded corner: the arms stop where the ring begins
</span>    <span class="n">x_end</span> <span class="o">=</span> <span class="n">xcen</span> <span class="o">+</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span> <span class="k">if</span> <span class="n">r</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="n">xcen</span> <span class="o">-</span> <span class="n">r</span>     <span class="c1"># horizontal arm: left PML -&gt; corner / ring
</span>    <span class="n">horizontal</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="o">-</span><span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">x_end</span><span class="p">),</span> <span class="n">ycen</span><span class="p">),</span>
                          <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">x_end</span><span class="p">,</span> <span class="n">w</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">)</span>
    <span class="n">y_start</span> <span class="o">=</span> <span class="n">ycen</span> <span class="o">-</span> <span class="n">w</span> <span class="o">/</span> <span class="mi">2</span> <span class="k">if</span> <span class="n">r</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="n">ycen</span> <span class="o">+</span> <span class="n">r</span>   <span class="c1"># vertical arm: corner / ring -&gt; top PML
</span>    <span class="n">vertical</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Block</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xcen</span><span class="p">,</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">y_start</span> <span class="o">+</span> <span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)),</span>
                        <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">y_start</span><span class="p">),</span> <span class="n">material</span><span class="o">=</span><span class="n">wg</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">geom</span> <span class="o">+</span> <span class="p">[</span><span class="n">horizontal</span><span class="p">,</span> <span class="n">vertical</span><span class="p">]</span>


<span class="c1"># ---------------------------------------------------------------- (3) source
</span><span class="k">def</span> <span class="nf">make_sources</span><span class="p">(</span><span class="n">dpml</span><span class="p">):</span>
    <span class="s">"""A plain Ez line source (not an eigenmode source), as in the official tutorial."""</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">positions</span><span class="p">(</span><span class="n">dpml</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">Source</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">GaussianSource</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="n">df</span><span class="p">),</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
                      <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"src_x"</span><span class="p">],</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">)]</span>


<span class="c1"># ---------------------------------------------------------------- (4) simulation &amp; boundaries
</span><span class="k">def</span> <span class="nf">make_sim</span><span class="p">(</span><span class="n">bend</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RESOLUTION</span><span class="p">,</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">mp</span><span class="p">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">cell_size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">sy</span><span class="p">),</span> <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span>
                         <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="n">PML</span><span class="p">(</span><span class="n">dpml</span><span class="p">)],</span>
                         <span class="n">geometry</span><span class="o">=</span><span class="n">make_geometry</span><span class="p">(</span><span class="n">bend</span><span class="p">,</span> <span class="n">radius</span><span class="p">),</span> <span class="n">sources</span><span class="o">=</span><span class="n">make_sources</span><span class="p">(</span><span class="n">dpml</span><span class="p">))</span>


<span class="n">_reference</span> <span class="o">=</span> <span class="p">{}</span>


<span class="k">def</span> <span class="nf">reference_run</span><span class="p">(</span><span class="n">resolution</span><span class="p">,</span> <span class="n">dpml</span><span class="p">):</span>
    <span class="s">"""RUN 1 (cached per resolution/PML): straight guide -&gt; P_in and the incident flux data."""</span>
    <span class="n">key</span> <span class="o">=</span> <span class="p">(</span><span class="n">resolution</span><span class="p">,</span> <span class="n">dpml</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">_reference</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">_reference</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">positions</span><span class="p">(</span><span class="n">dpml</span><span class="p">)</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">bend</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span> <span class="n">dpml</span><span class="o">=</span><span class="n">dpml</span><span class="p">)</span>
    <span class="c1"># ------------------------------------------------------------ (5) monitors, run 1
</span>    <span class="n">refl</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"refl_x"</span><span class="p">],</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">))</span>
    <span class="n">tran0</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"tran_straight_x"</span><span class="p">],</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">))</span>
    <span class="c1"># ------------------------------------------------------------ (6) run 1 &amp; stop condition
</span>    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span>
                <span class="mi">25</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"tran_straight_x"</span><span class="p">],</span> <span class="n">ycen</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="n">_reference</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"P_in"</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">tran0</span><span class="p">)),</span>      <span class="c1"># what actually travels down the guide
</span>                       <span class="s">"refl_data"</span><span class="p">:</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_flux_data</span><span class="p">(</span><span class="n">refl</span><span class="p">),</span>         <span class="c1"># incident fields at the reflection plane
</span>                       <span class="s">"freqs"</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_flux_freqs</span><span class="p">(</span><span class="n">tran0</span><span class="p">))}</span>
    <span class="k">return</span> <span class="n">_reference</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>


<span class="k">def</span> <span class="nf">bend_run</span><span class="p">(</span><span class="n">radius</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">RESOLUTION</span><span class="p">,</span> <span class="n">dpml</span><span class="o">=</span><span class="n">DPML</span><span class="p">,</span> <span class="n">figures</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">field_png</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="s">"""RUN 2: the bend. Returns T, R, L spectra (fractions of P_in)."""</span>
    <span class="n">ref</span> <span class="o">=</span> <span class="n">reference_run</span><span class="p">(</span><span class="n">resolution</span><span class="p">,</span> <span class="n">dpml</span><span class="p">)</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">positions</span><span class="p">(</span><span class="n">dpml</span><span class="p">)</span>
    <span class="n">sim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">bend</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">radius</span><span class="o">=</span><span class="n">radius</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span> <span class="n">dpml</span><span class="o">=</span><span class="n">dpml</span><span class="p">)</span>
    <span class="c1"># ------------------------------------------------------------ (5) monitors, run 2
</span>    <span class="n">refl</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"refl_x"</span><span class="p">],</span> <span class="n">ycen</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="n">span</span><span class="p">))</span>
    <span class="n">sim</span><span class="p">.</span><span class="n">load_minus_flux_data</span><span class="p">(</span><span class="n">refl</span><span class="p">,</span> <span class="n">ref</span><span class="p">[</span><span class="s">"refl_data"</span><span class="p">])</span>  <span class="c1"># subtract the incident part -&gt; reflection only
</span>    <span class="n">tran</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_flux</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">nfreq</span><span class="p">,</span>
                        <span class="n">mp</span><span class="p">.</span><span class="n">FluxRegion</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">xcen</span><span class="p">,</span> <span class="n">p</span><span class="p">[</span><span class="s">"tran_bend_y"</span><span class="p">]),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">w</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
    <span class="n">decay_pt</span> <span class="o">=</span> <span class="p">(</span><span class="n">xcen</span><span class="p">,</span> <span class="n">p</span><span class="p">[</span><span class="s">"tran_bend_y"</span><span class="p">])</span>
    <span class="k">if</span> <span class="n">figures</span><span class="p">:</span>
        <span class="n">annotated_layout</span><span class="p">(</span>
            <span class="n">sim</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"01_layout.png"</span><span class="p">),</span> <span class="n">dpml</span><span class="o">=</span><span class="n">dpml</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">,</span> <span class="n">axis_scale</span><span class="o">=</span><span class="n">a_um</span><span class="p">,</span> <span class="n">axis_step</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span>
            <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">7.5</span><span class="p">,</span> <span class="mf">7.2</span><span class="p">),</span> <span class="n">pml_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="o">-</span><span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">dpml</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span>
            <span class="n">params_text</span><span class="o">=</span><span class="p">(</span><span class="sa">f</span><span class="s">"a = </span><span class="si">{</span><span class="n">a_nm</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> nm  (1 Meep unit)</span><span class="se">\n</span><span class="s">"</span>
                         <span class="sa">f</span><span class="s">"eps=</span><span class="si">{</span><span class="n">eps_wg</span><span class="si">:</span><span class="n">g</span><span class="si">}</span><span class="s">  w=</span><span class="si">{</span><span class="n">w</span><span class="si">:</span><span class="n">g</span><span class="si">}</span><span class="s">a=</span><span class="si">{</span><span class="n">w</span><span class="o">*</span><span class="n">a_nm</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s">nm  dpml=</span><span class="si">{</span><span class="n">dpml</span><span class="si">:</span><span class="n">g</span><span class="si">}</span><span class="s">a</span><span class="se">\n</span><span class="s">"</span>
                         <span class="sa">f</span><span class="s">"wl=</span><span class="si">{</span><span class="mi">1</span><span class="o">/</span><span class="n">fcen</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">a=</span><span class="si">{</span><span class="n">a_nm</span><span class="o">/</span><span class="n">fcen</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s">nm  res=</span><span class="si">{</span><span class="n">resolution</span><span class="si">}</span><span class="s">/a  cell=</span><span class="si">{</span><span class="n">sx</span><span class="si">:</span><span class="n">g</span><span class="si">}</span><span class="s">a"</span><span class="p">),</span>
            <span class="n">params_xy</span><span class="o">=</span><span class="p">(</span><span class="o">-</span><span class="mf">6.6</span><span class="p">,</span> <span class="mf">6.6</span><span class="p">),</span> <span class="n">decay_point</span><span class="o">=</span><span class="n">decay_pt</span><span class="p">,</span> <span class="n">decay_text_xy</span><span class="o">=</span><span class="p">(</span><span class="mf">4.6</span><span class="p">,</span> <span class="mf">5.6</span><span class="p">),</span>
            <span class="n">title</span><span class="o">=</span><span class="s">"90-deg waveguide bend (eps = 12, w = 1): Ez line source, flux monitors, PML"</span><span class="p">,</span>
            <span class="n">labels</span><span class="o">=</span><span class="p">[</span>
                <span class="n">Label</span><span class="p">(</span><span class="s">"horizontal arm (geometry)"</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">ycen</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">3.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.8</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                <span class="n">Label</span><span class="p">(</span><span class="s">"vertical arm (geometry)"</span><span class="p">,</span> <span class="p">(</span><span class="n">xcen</span> <span class="o">-</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">2.5</span><span class="p">,</span> <span class="mf">3.5</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">),</span>
                <span class="n">Label</span><span class="p">(</span><span class="s">"Ez line source"</span><span class="p">,</span> <span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"src_x"</span><span class="p">],</span> <span class="n">ycen</span> <span class="o">-</span> <span class="mf">1.6</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">6.3</span><span class="p">,</span> <span class="o">-</span><span class="mf">6.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">),</span>
                <span class="n">Label</span><span class="p">(</span><span class="s">"flux: reflection (minus incident)"</span><span class="p">,</span> <span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"refl_x"</span><span class="p">],</span> <span class="n">ycen</span> <span class="o">+</span> <span class="mf">1.6</span><span class="p">),</span> <span class="p">(</span><span class="o">-</span><span class="mf">6.3</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">),</span>
                <span class="n">Label</span><span class="p">(</span><span class="s">"flux: transmission"</span><span class="p">,</span> <span class="p">(</span><span class="n">xcen</span> <span class="o">-</span> <span class="mf">1.5</span><span class="p">,</span> <span class="n">p</span><span class="p">[</span><span class="s">"tran_bend_y"</span><span class="p">]),</span> <span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">),</span> <span class="n">step</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"blue"</span><span class="p">),</span>
            <span class="p">])</span>
    <span class="n">want_field</span> <span class="o">=</span> <span class="n">figures</span> <span class="ow">or</span> <span class="n">field_png</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span>
    <span class="k">if</span> <span class="n">want_field</span><span class="p">:</span>
        <span class="n">nonpml</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">dpml</span><span class="p">,</span> <span class="n">sy</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">dpml</span><span class="p">))</span>
        <span class="n">dft</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">add_dft_fields</span><span class="p">([</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">],</span> <span class="n">fcen</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">where</span><span class="o">=</span><span class="n">nonpml</span><span class="p">)</span>
    <span class="c1"># ------------------------------------------------------------ (6) run 2 &amp; stop condition
</span>    <span class="n">sim</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">until_after_sources</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">stop_when_fields_decayed</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="o">*</span><span class="n">decay_pt</span><span class="p">),</span> <span class="mf">1e-6</span><span class="p">))</span>
    <span class="c1"># ------------------------------------------------------------ (7) post-processing
</span>    <span class="n">T</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">tran</span><span class="p">))</span> <span class="o">/</span> <span class="n">ref</span><span class="p">[</span><span class="s">"P_in"</span><span class="p">]</span>      <span class="c1"># transmitted fraction
</span>    <span class="n">R</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">mp</span><span class="p">.</span><span class="n">get_fluxes</span><span class="p">(</span><span class="n">refl</span><span class="p">))</span> <span class="o">/</span> <span class="n">ref</span><span class="p">[</span><span class="s">"P_in"</span><span class="p">]</span>     <span class="c1"># backward flux is negative -&gt; flip the sign
</span>    <span class="n">L</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">-</span> <span class="n">T</span> <span class="o">-</span> <span class="n">R</span>                                      <span class="c1"># what is left: radiated out at the corner
</span>    <span class="k">if</span> <span class="n">want_field</span><span class="p">:</span>
        <span class="n">ez</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_dft_array</span><span class="p">(</span><span class="n">dft</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
        <span class="n">eps</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">nonpml</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
        <span class="n">extent_um</span> <span class="o">=</span> <span class="p">[</span><span class="n">v</span> <span class="o">*</span> <span class="n">a_um</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">dpml</span><span class="p">),</span> <span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">dpml</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">dpml</span><span class="p">),</span> <span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">dpml</span><span class="p">)]</span>
        <span class="n">field_figure</span><span class="p">(</span><span class="n">ez</span><span class="p">,</span> <span class="n">extent_um</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="n">field_png</span> <span class="ow">or</span> <span class="s">"02_field.png"</span><span class="p">),</span> <span class="n">core_halfwidth</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
                     <span class="n">eps</span><span class="o">=</span><span class="n">eps</span><span class="p">,</span> <span class="n">wl</span><span class="o">=</span><span class="nb">round</span><span class="p">(</span><span class="n">a_nm</span> <span class="o">/</span> <span class="n">fcen</span><span class="p">),</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="s">"Ez"</span><span class="p">,</span>
                     <span class="n">layout</span><span class="o">=</span><span class="s">"row"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s">"equal"</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">"um"</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"T"</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span> <span class="s">"R"</span><span class="p">:</span> <span class="n">R</span><span class="p">,</span> <span class="s">"L"</span><span class="p">:</span> <span class="n">L</span><span class="p">,</span> <span class="s">"freqs"</span><span class="p">:</span> <span class="n">ref</span><span class="p">[</span><span class="s">"freqs"</span><span class="p">]}</span>


<span class="n">t_all</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">ic</span> <span class="o">=</span> <span class="n">nfreq</span> <span class="o">//</span> <span class="mi">2</span>

<span class="c1"># source waveform and spectrum; the monitor band is fcen +- df/2
</span><span class="n">src_info</span> <span class="o">=</span> <span class="n">source_figure</span><span class="p">(</span><span class="n">fcen</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"00_source.png"</span><span class="p">),</span> <span class="n">mon_fcen</span><span class="o">=</span><span class="n">fcen</span><span class="p">,</span> <span class="n">mon_df</span><span class="o">=</span><span class="n">df</span><span class="p">,</span>
                         <span class="n">wl_scale</span><span class="o">=</span><span class="n">a_nm</span><span class="p">,</span> <span class="n">wl_unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">time_unit</span><span class="o">=</span><span class="s">"a/c"</span><span class="p">)</span>

<span class="c1"># ================================================================ sharp corner (official example)
</span><span class="n">t0</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">sharp</span> <span class="o">=</span> <span class="n">bend_run</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">figures</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">wall_sharp</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t0</span>
<span class="n">wl</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">sharp</span><span class="p">[</span><span class="s">"freqs"</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"sharp: T = </span><span class="si">{</span><span class="n">sharp</span><span class="p">[</span><span class="s">'T'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, R = </span><span class="si">{</span><span class="n">sharp</span><span class="p">[</span><span class="s">'R'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">, radiation loss = </span><span class="si">{</span><span class="n">sharp</span><span class="p">[</span><span class="s">'L'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">  (</span><span class="si">{</span><span class="n">wall_sharp</span><span class="si">:</span><span class="p">.</span><span class="mi">0</span><span class="n">f</span><span class="si">}</span><span class="s"> s incl. reference)"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"T over band </span><span class="si">{</span><span class="n">wl</span><span class="p">.</span><span class="nb">min</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">-</span><span class="si">{</span><span class="n">wl</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">sharp</span><span class="p">[</span><span class="s">'T'</span><span class="p">].</span><span class="nb">min</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s"> .. </span><span class="si">{</span><span class="n">sharp</span><span class="p">[</span><span class="s">'T'</span><span class="p">].</span><span class="nb">max</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">3</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">spectrum_figure</span><span class="p">(</span><span class="n">wl</span> <span class="o">*</span> <span class="n">a_nm</span><span class="p">,</span> <span class="p">{</span><span class="s">"T (transmitted)"</span><span class="p">:</span> <span class="n">sharp</span><span class="p">[</span><span class="s">"T"</span><span class="p">],</span> <span class="s">"R (reflected)"</span><span class="p">:</span> <span class="n">sharp</span><span class="p">[</span><span class="s">"R"</span><span class="p">],</span> <span class="s">"1 - T - R (radiated)"</span><span class="p">:</span> <span class="n">sharp</span><span class="p">[</span><span class="s">"L"</span><span class="p">]},</span>
                <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"03_spectrum.png"</span><span class="p">),</span> <span class="n">unit</span><span class="o">=</span><span class="s">"nm"</span><span class="p">,</span> <span class="n">mark</span><span class="o">=</span><span class="mi">1550</span><span class="p">,</span> <span class="n">mark_label</span><span class="o">=</span><span class="s">"1550 nm (fcen)"</span><span class="p">)</span>

<span class="c1"># ================================================================ radius sweep
</span><span class="n">radii</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">]</span>
<span class="n">sweep</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">radii</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">r</span> <span class="o">==</span> <span class="mf">0.0</span><span class="p">:</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">sharp</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">bend_run</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">field_png</span><span class="o">=</span><span class="p">(</span><span class="s">"05_field_round.png"</span> <span class="k">if</span> <span class="n">r</span> <span class="o">==</span> <span class="mf">3.0</span> <span class="k">else</span> <span class="bp">None</span><span class="p">))</span>
    <span class="n">sweep</span><span class="p">.</span><span class="n">append</span><span class="p">({</span><span class="s">"radius_a"</span><span class="p">:</span> <span class="n">r</span><span class="p">,</span> <span class="s">"radius_um"</span><span class="p">:</span> <span class="n">r</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">,</span> <span class="s">"radius_over_wl"</span><span class="p">:</span> <span class="n">r</span> <span class="o">*</span> <span class="n">fcen</span><span class="p">,</span>
                  <span class="s">"T"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">res</span><span class="p">[</span><span class="s">"T"</span><span class="p">][</span><span class="n">ic</span><span class="p">]),</span> <span class="s">"R"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">res</span><span class="p">[</span><span class="s">"R"</span><span class="p">][</span><span class="n">ic</span><span class="p">]),</span> <span class="s">"L"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">res</span><span class="p">[</span><span class="s">"L"</span><span class="p">][</span><span class="n">ic</span><span class="p">])})</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"radius </span><span class="si">{</span><span class="n">r</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> a (</span><span class="si">{</span><span class="n">r</span><span class="o">*</span><span class="n">a_um</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> um): T=</span><span class="si">{</span><span class="n">res</span><span class="p">[</span><span class="s">'T'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> R=</span><span class="si">{</span><span class="n">res</span><span class="p">[</span><span class="s">'R'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> L=</span><span class="si">{</span><span class="n">res</span><span class="p">[</span><span class="s">'L'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">line_figure</span><span class="p">([</span><span class="n">s</span><span class="p">[</span><span class="s">"radius_um"</span><span class="p">]</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sweep</span><span class="p">],</span>
            <span class="p">{</span><span class="s">"T (transmitted)"</span><span class="p">:</span> <span class="p">[</span><span class="n">s</span><span class="p">[</span><span class="s">"T"</span><span class="p">]</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sweep</span><span class="p">],</span> <span class="s">"R (reflected)"</span><span class="p">:</span> <span class="p">[</span><span class="n">s</span><span class="p">[</span><span class="s">"R"</span><span class="p">]</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sweep</span><span class="p">],</span>
             <span class="s">"1 - T - R (radiated)"</span><span class="p">:</span> <span class="p">[</span><span class="n">s</span><span class="p">[</span><span class="s">"L"</span><span class="p">]</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sweep</span><span class="p">]},</span>
            <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"04_radius_sweep.png"</span><span class="p">),</span> <span class="n">xlabel</span><span class="o">=</span><span class="sa">f</span><span class="s">"bend radius [um]  (a = </span><span class="si">{</span><span class="n">a_nm</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="n">f</span><span class="si">}</span><span class="s"> nm, wl = 1550 nm)"</span><span class="p">)</span>

<span class="c1"># ================================================================ animations: sharp corner vs rounded corner (radius 3a)
# Fresh simulations with the same source; record from before the pulse peak (t0 = 5/df) until the
# pulse has gone from the source to the top monitor along the guide (distance ~ 21 a at n_eff ~ 2.5).
</span><span class="n">p</span> <span class="o">=</span> <span class="n">positions</span><span class="p">(</span><span class="n">DPML</span><span class="p">)</span>
<span class="n">nonpml</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="n">Volume</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(),</span> <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Vector3</span><span class="p">(</span><span class="n">sx</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">,</span> <span class="n">sy</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">DPML</span><span class="p">))</span>
<span class="n">extent_um</span> <span class="o">=</span> <span class="p">[</span><span class="n">v</span> <span class="o">*</span> <span class="n">a_um</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sx</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">),</span> <span class="n">sy</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">DPML</span><span class="p">)]</span>
<span class="k">for</span> <span class="n">tag</span><span class="p">,</span> <span class="n">r_anim</span> <span class="ow">in</span> <span class="p">((</span><span class="s">"sharp"</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="p">(</span><span class="s">"round"</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">)):</span>
    <span class="n">sim_anim</span> <span class="o">=</span> <span class="n">make_sim</span><span class="p">(</span><span class="n">bend</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">radius</span><span class="o">=</span><span class="n">r_anim</span><span class="p">)</span>
    <span class="n">sim_anim</span><span class="p">.</span><span class="n">init_sim</span><span class="p">()</span>
    <span class="n">eps_anim</span> <span class="o">=</span> <span class="n">sim_anim</span><span class="p">.</span><span class="n">get_array</span><span class="p">(</span><span class="n">vol</span><span class="o">=</span><span class="n">nonpml</span><span class="p">,</span> <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Dielectric</span><span class="p">)</span>
    <span class="n">frames</span><span class="p">,</span> <span class="n">times</span> <span class="o">=</span> <span class="n">record_frames</span><span class="p">(</span><span class="n">sim_anim</span><span class="p">,</span> <span class="n">nonpml</span><span class="p">,</span> <span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span> <span class="n">t_start</span><span class="o">=</span><span class="mf">5.0</span> <span class="o">/</span> <span class="n">df</span> <span class="o">-</span> <span class="mf">2.0</span> <span class="o">/</span> <span class="n">df</span><span class="p">,</span>
                                  <span class="n">t_end</span><span class="o">=</span><span class="mf">5.0</span> <span class="o">/</span> <span class="n">df</span> <span class="o">+</span> <span class="mf">21.0</span> <span class="o">*</span> <span class="mf">2.5</span> <span class="o">+</span> <span class="mf">10.0</span><span class="p">,</span> <span class="n">n_frames</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
    <span class="n">animate_fields</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">times</span><span class="p">,</span> <span class="n">extent_um</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="sa">f</span><span class="s">"06_anim_</span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="s">.gif"</span><span class="p">),</span> <span class="n">eps</span><span class="o">=</span><span class="n">eps_anim</span><span class="p">,</span>
                   <span class="n">lines</span><span class="o">=</span><span class="p">[((</span><span class="n">p</span><span class="p">[</span><span class="s">"src_x"</span><span class="p">]</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">,</span> <span class="p">(</span><span class="n">ycen</span> <span class="o">-</span> <span class="mf">1.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">),</span> <span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">"src_x"</span><span class="p">]</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">,</span> <span class="p">(</span><span class="n">ycen</span> <span class="o">+</span> <span class="mf">1.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">),</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"Ez source"</span><span class="p">),</span>
                          <span class="p">(((</span><span class="n">xcen</span> <span class="o">-</span> <span class="mf">1.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">,</span> <span class="n">p</span><span class="p">[</span><span class="s">"tran_bend_y"</span><span class="p">]</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">),</span> <span class="p">((</span><span class="n">xcen</span> <span class="o">+</span> <span class="mf">1.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">,</span> <span class="n">p</span><span class="p">[</span><span class="s">"tran_bend_y"</span><span class="p">]</span> <span class="o">*</span> <span class="n">a_um</span><span class="p">),</span> <span class="s">"blue"</span><span class="p">,</span> <span class="s">"flux: transmission"</span><span class="p">)],</span>
                   <span class="n">time_unit</span><span class="o">=</span><span class="s">"a/c"</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mf">5.4</span><span class="p">,</span> <span class="mf">4.8</span><span class="p">),</span> <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">tag</span><span class="si">}</span><span class="s"> corner"</span><span class="p">,</span> <span class="n">legend_loc</span><span class="o">=</span><span class="s">"lower right"</span><span class="p">)</span>

<span class="c1"># ================================================================ convergence (sharp corner)
</span><span class="n">convergence</span> <span class="o">=</span> <span class="p">[{</span><span class="s">"resolution"</span><span class="p">:</span> <span class="n">RESOLUTION</span><span class="p">,</span> <span class="s">"dpml"</span><span class="p">:</span> <span class="n">DPML</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="n">sweep</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">"T"</span><span class="p">],</span> <span class="s">"R"</span><span class="p">:</span> <span class="n">sweep</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">"R"</span><span class="p">],</span> <span class="s">"L"</span><span class="p">:</span> <span class="n">sweep</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">"L"</span><span class="p">]}]</span>
<span class="k">for</span> <span class="n">res_px</span><span class="p">,</span> <span class="n">dpml</span> <span class="ow">in</span> <span class="p">((</span><span class="mi">10</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="p">(</span><span class="mi">40</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">)):</span>   <span class="c1"># change one thing at a time
</span>    <span class="n">t0</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span>
    <span class="n">r</span> <span class="o">=</span> <span class="n">bend_run</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="n">res_px</span><span class="p">,</span> <span class="n">dpml</span><span class="o">=</span><span class="n">dpml</span><span class="p">)</span>
    <span class="n">convergence</span><span class="p">.</span><span class="n">append</span><span class="p">({</span><span class="s">"resolution"</span><span class="p">:</span> <span class="n">res_px</span><span class="p">,</span> <span class="s">"dpml"</span><span class="p">:</span> <span class="n">dpml</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="s">"T"</span><span class="p">][</span><span class="n">ic</span><span class="p">]),</span> <span class="s">"R"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="s">"R"</span><span class="p">][</span><span class="n">ic</span><span class="p">]),</span>
                        <span class="s">"L"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="s">"L"</span><span class="p">][</span><span class="n">ic</span><span class="p">]),</span> <span class="s">"wall_s"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t0</span><span class="p">})</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"convergence res=</span><span class="si">{</span><span class="n">res_px</span><span class="si">}</span><span class="s"> dpml=</span><span class="si">{</span><span class="n">dpml</span><span class="si">}</span><span class="s">: T=</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'T'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> R=</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'R'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s"> L=</span><span class="si">{</span><span class="n">r</span><span class="p">[</span><span class="s">'L'</span><span class="p">][</span><span class="n">ic</span><span class="p">]</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="k">if</span> <span class="n">mp</span><span class="p">.</span><span class="n">am_master</span><span class="p">():</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">OUT</span><span class="p">,</span> <span class="s">"result.json"</span><span class="p">),</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="n">dump</span><span class="p">({</span><span class="s">"T"</span><span class="p">:</span> <span class="n">sweep</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">"T"</span><span class="p">],</span> <span class="s">"R"</span><span class="p">:</span> <span class="n">sweep</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">"R"</span><span class="p">],</span> <span class="s">"loss"</span><span class="p">:</span> <span class="n">sweep</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">"L"</span><span class="p">],</span>
                   <span class="s">"a_nm"</span><span class="p">:</span> <span class="n">a_nm</span><span class="p">,</span> <span class="s">"wavelengths_a"</span><span class="p">:</span> <span class="n">wl</span><span class="p">.</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"wavelengths_nm"</span><span class="p">:</span> <span class="p">(</span><span class="n">wl</span> <span class="o">*</span> <span class="n">a_nm</span><span class="p">).</span><span class="n">tolist</span><span class="p">(),</span>
                   <span class="s">"T_spectrum"</span><span class="p">:</span> <span class="n">sharp</span><span class="p">[</span><span class="s">"T"</span><span class="p">].</span><span class="n">tolist</span><span class="p">(),</span> <span class="s">"R_spectrum"</span><span class="p">:</span> <span class="n">sharp</span><span class="p">[</span><span class="s">"R"</span><span class="p">].</span><span class="n">tolist</span><span class="p">(),</span>
                   <span class="s">"radius_sweep"</span><span class="p">:</span> <span class="n">sweep</span><span class="p">,</span> <span class="s">"convergence"</span><span class="p">:</span> <span class="n">convergence</span><span class="p">,</span> <span class="s">"source"</span><span class="p">:</span> <span class="n">src_info</span><span class="p">,</span>
                   <span class="s">"wall_s_total"</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">t_all</span><span class="p">,</span> <span class="s">"meep"</span><span class="p">:</span> <span class="n">mp</span><span class="p">.</span><span class="n">__version__</span><span class="p">},</span>
                  <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span></code></pre></figure>

</details>

<details>
  <summary>원본 실행 로그·재현 환경 보기</summary>

  <p>§4의 발췌 코드와 달리 전체 코드에는 그림 저장·result.json 기록이 들어 있다. 그림 helper <code class="language-plaintext highlighter-rouge">blogfig.py</code>(<code class="language-plaintext highlighter-rouge">annotated_layout</code>, <code class="language-plaintext highlighter-rouge">field_figure</code>, <code class="language-plaintext highlighter-rouge">spectrum_figure</code>)는 시리즈 공통이며 같은 폴더(<code class="language-plaintext highlighter-rouge">code/</code>)에 있다. 전체 코드와 helper: <a href="https://github.com/jin-castle/meep-examples/blob/main/code">https://github.com/jin-castle/meep-examples/blob/main/code</a>.</p>

  <p><strong>실행 결과 (2026-10-23 재실행)</strong>:</p>
  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sharp: T = 0.1997, R = 0.2202, radiation loss = 0.5801  (10 s incl. reference)
T over band 5.00-10.00: 0.169 .. 0.512
radius 0.0 a (0.00 um): T=0.1997 R=0.2202 L=0.5801
radius 0.5 a (0.12 um): T=0.4865 R=0.0518 L=0.4617
radius 1.0 a (0.23 um): T=0.7458 R=0.0014 L=0.2528
radius 1.5 a (0.35 um): T=0.9073 R=0.0009 L=0.0918
radius 2.0 a (0.47 um): T=0.9638 R=0.0005 L=0.0358
radius 3.0 a (0.70 um): T=0.9859 R=0.0003 L=0.0138
radius 4.0 a (0.93 um): T=1.0031 R=0.0001 L=-0.0031
radius 6.0 a (1.40 um): T=0.9995 R=0.0000 L=0.0005
convergence res=10 dpml=1.0: T=0.1983 R=0.2287 L=0.5730
convergence res=40 dpml=1.0: T=0.1894 R=0.2241 L=0.5865
convergence res=25 dpml=1.5: T=0.1703 R=0.2173 L=0.6124
</code></pre></div>  </div>

  <p><strong>재현 환경</strong>: meep 1.33.0 · Python 3.11 · <code class="language-plaintext highlighter-rouge">conda install -c conda-forge pymeep</code> · 실행 <code class="language-plaintext highlighter-rouge">python bend90.py</code> (약 12 s, 단일 코어)</p>

</details>

<details>
  <summary>응용과 다음 학습 주제 보기</summary>

  <h3 id="section-7">어디에 쓰이는가</h3>

  <p>bend 반지름은 칩 면적을 정하는 숫자다. 반지름을 두 배로 하면 고리 하나의 면적은 네 배가 되고, foundry의 설계 규칙에는 최소 반지름이 적혀 있다.</p>

  <table>
    <thead>
      <tr>
        <th>응용</th>
        <th>이 글의 어떤 것을 쓰는가</th>
        <th>그 다음에 필요한 것</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>PIC 배선과 면적(footprint)</td>
        <td>반지름–손실 곡선과 knee</td>
        <td>09편 역설계 bend</td>
      </tr>
      <tr>
        <td>ring resonator·spiral delay line</td>
        <td>작은 반지름의 곡률 손실이 Q와 FSR을 정한다</td>
        <td>12편 고리</td>
      </tr>
      <tr>
        <td>foundry PDK의 최소 bend radius 규칙</td>
        <td>knee 1.5~2a가 그 규칙의 근거</td>
        <td>—</td>
      </tr>
      <tr>
        <td>입력 대비 출력의 모든 측정</td>
        <td>2-run 정규화</td>
        <td>06편 이후 전부</td>
      </tr>
    </tbody>
  </table>

</details>

<ul>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_Tutorials/Basics/#transmittance-spectrum-of-a-waveguide-bend">공식 튜토리얼: Transmittance Spectrum of a Waveguide Bend</a></li>
  <li><a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#flux-spectra"><code class="language-plaintext highlighter-rouge">add_flux</code> / <code class="language-plaintext highlighter-rouge">load_minus_flux_data</code> 레퍼런스</a> · <a href="https://meep.readthedocs.io/en/latest/Python_User_Interface/#cylinder"><code class="language-plaintext highlighter-rouge">Cylinder</code> 레퍼런스</a></li>
  <li>이전 글: <a href="/meep-examples/straight-waveguide/">04 · Straight waveguide와 guided mode</a> · 다음 글: <a href="/meep-examples/binary-grating/">06 · Binary grating과 diffraction order</a></li>
</ul>]]></content><author><name>jin-castle</name></author><category term="meep" /><category term="fdtd" /><category term="waveguide" /><category term="bend" /><category term="flux" /><category term="normalization" /><summary type="html"><![CDATA[a dielectric waveguide (ε = 12, width 1) turns a sharp 90° corner. We measure how much power goes around the corner, how much comes back, and how much leaks out.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://jin-castle.github.io/meep-examples/assets/meep/05/02_field.png" /><media:content medium="image" url="https://jin-castle.github.io/meep-examples/assets/meep/05/02_field.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>