File: test_faraday_rotation.py

package info (click to toggle)
meep-openmpi 1.25.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 64,556 kB
  • sloc: cpp: 32,214; python: 27,958; lisp: 1,225; makefile: 505; sh: 249; ansic: 131; javascript: 5
file content (131 lines) | stat: -rw-r--r-- 4,934 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import unittest

import numpy as np

import meep as mp


## Farady rotation rate for gyrotropic Lorentzian medium
def kgyro_lorentzian(freq, epsn, f0, gamma, sigma, b0):
    dfsq = f0**2 - 1j * freq * gamma - freq**2
    eperp = epsn + sigma * f0**2 * dfsq / (dfsq**2 - (freq * b0) ** 2)
    eta = sigma * f0**2 * freq * b0 / (dfsq**2 - (freq * b0) ** 2)
    return 2 * np.pi * freq * np.sqrt(0.5 * (eperp - np.sqrt(eperp**2 - eta**2)))


## Farady rotation rate for gyrotropic Drude medium
def kgyro_drude(freq, epsn, f0, gamma, sigma, b0):
    dfsq = -1j * freq * gamma - freq**2
    eperp = epsn + sigma * f0**2 * dfsq / (dfsq**2 - (freq * b0) ** 2)
    eta = sigma * f0**2 * freq * b0 / (dfsq**2 - (freq * b0) ** 2)
    return 2 * np.pi * freq * np.sqrt(0.5 * (eperp - np.sqrt(eperp**2 - eta**2)))


## Farady rotation rate for Landau-Lifshitz-Gilbert medium
def kgyro_llg(freq, epsn, f0, gamma, sigma, alpha):
    df1 = f0 - 1j * freq * alpha
    df2 = freq + 1j * gamma
    eperp = epsn + sigma * df1 / (df1**2 - df2**2)
    eta = sigma * df2 / (df1**2 - df2**2)
    return 2 * np.pi * freq * np.sqrt(0.5 * (eperp - np.sqrt(eperp**2 - eta**2)))


class TestFaradayRotation(unittest.TestCase):
    ## Simulate a linearly polarized plane wave traveling along the gyrotropy axis.
    ## Extract Faraday rotation angle by comparing the Ex and Ey amplitudes, and
    ## compare to a theoretical result corresponding to rotation rate KPRED.
    ## The default acceptable tolerance TOL is 1.5 degrees.
    def check_rotation(
        self, mat, L, fsrc, zsrc, resolution, tmax, zout, kpred, tol=1.5
    ):
        cell = mp.Vector3(0, 0, L)
        pml_layers = [mp.PML(thickness=1.0, direction=mp.Z)]
        sources = [
            mp.Source(
                mp.ContinuousSource(frequency=fsrc),
                component=mp.Ex,
                center=mp.Vector3(0, 0, zsrc),
            )
        ]

        self.sim = mp.Simulation(
            cell_size=cell,
            geometry=[],
            sources=sources,
            boundary_layers=pml_layers,
            default_material=mat,
            resolution=resolution,
        )

        record_Ex, record_Ey, record_t = [], [], []

        def record_ex_ey(sim):
            record_Ex.append(sim.get_field_point(mp.Ex, mp.Vector3(0, 0, zout)))
            record_Ey.append(sim.get_field_point(mp.Ey, mp.Vector3(0, 0, zout)))
            record_t.append(sim.meep_time())

        self.sim.run(
            mp.after_time(0.5 * tmax, mp.at_every(1e-6, record_ex_ey)), until=tmax
        )

        ex_rel = np.amax(abs(np.fft.fft(record_Ex)))
        ey_rel = np.amax(abs(np.fft.fft(record_Ey)))
        result = np.arctan2(ey_rel, ex_rel) * 180 / np.pi

        Ex_theory = np.abs(np.cos(kpred * (zout - zsrc)).real)
        Ey_theory = np.abs(np.sin(kpred * (zout - zsrc)).real)
        expected = np.arctan2(Ey_theory, Ex_theory) * 180 / np.pi

        print(f"Rotation angle (in degrees): {result}, expected {expected}\n")
        np.testing.assert_allclose(expected, result, atol=tol)

    def test_faraday_rotation(self):
        L, zsrc, zout = 12.0, -4.5, 4.0
        freq, tmax = 0.8, 100.0
        resolution = 24

        ## Test gyrotropic Lorentzian medium
        epsn, f0, gamma, sn, b0 = 1.5, 1.0, 1e-3, 0.1, 0.15
        susc = [
            mp.GyrotropicLorentzianSusceptibility(
                frequency=f0, gamma=gamma, sigma=sn, bias=mp.Vector3(0, 0, b0)
            )
        ]
        mat = mp.Medium(epsilon=epsn, mu=1, E_susceptibilities=susc)
        k = kgyro_lorentzian(freq, epsn, f0, gamma, sn, b0)
        print("=" * 24)
        print("Testing Faraday rotation for gyrotropic Lorentzian model...")
        self.check_rotation(mat, L, freq, zsrc, resolution, tmax, zout, k)

        ## Test gyrotropic Drude medium
        susc = [
            mp.GyrotropicDrudeSusceptibility(
                frequency=f0, gamma=gamma, sigma=sn, bias=mp.Vector3(0, 0, b0)
            )
        ]
        mat = mp.Medium(epsilon=epsn, mu=1, E_susceptibilities=susc)
        k = kgyro_drude(freq, epsn, f0, gamma, sn, b0)
        print("=" * 24)
        print("Testing Faraday rotation for gyrotropic Drude model...")
        self.check_rotation(mat, L, freq, zsrc, resolution, tmax, zout, k)

        ## Test Landau-Lifshitz-Gilbert medium
        alpha = 1e-5
        susc = [
            mp.GyrotropicSaturatedSusceptibility(
                frequency=f0,
                gamma=gamma,
                sigma=sn,
                alpha=alpha,
                bias=mp.Vector3(0, 0, 1.0),
            )
        ]
        mat = mp.Medium(epsilon=epsn, mu=1, E_susceptibilities=susc)
        k = kgyro_llg(freq, epsn, f0, gamma, sn, alpha)
        print("=" * 24)
        print("Testing Faraday rotation for Landau-Lifshitz-Gilbert model...")
        self.check_rotation(mat, L, freq, zsrc, resolution, tmax, zout, k)


if __name__ == "__main__":
    unittest.main()