Line scans and magnetization-graded waveguides#

In this example, we will model a magnetization-graded waveguide like in Ref. 1. A graduation of saturation magnetization can induce a channeling of certain modes. Different quantities, such as magnetization and mode profiles are investigated using the line scan feature of TetraX.

Sample definition as a waveguide with graded saturation magnetization#

First we create a rectangular waveguide with 200 nm width and 1 nm thickness. The exchange stiffness and gyromagnetic ratio are set to typical values of permalloy.

[1]:
import tetrax as tx

T = 1 # nm
W = 200 # nm
res_W = 1


sample = tx.Sample(
    tx.geometries.waveguide.rectangular(
        width = W,
        thickness = T,
        cell_size_width = res_W
    ),
    name="rect_waveguide_graded"
)

sample.material["gamma"] = 185.66e9
sample.material["Aex"] = 9.9e-12

We set a graded magnetization to mimic an ion irradiation of a permalloy waveguide with the highest fluence in the middle. In order to model a graduation of the saturation magnetization, we use the following windowing function which ensures a smooth variation of Msat in space.

[2]:
import numpy as np

def smooth_window(t0, T, tau, A, t):
    """Windowing function with smooth edges.

    See, e.g., https://zenodo.org/doi/10.5281/zenodo.4493251
    on page 53 for a sketch of the role of the parameters.

    Parameters
    ----------
    t0 : float
        Shift in time.
    T : float
        Total width of the window (from zero to zero).
    tau : float
        Rise/fall time of the window.
    A : float
        Amplitude.
    t : float
        Time.
    """

    def R(u):
        """
        Auxiliary R function that appears in the windowing function c_inf_window.
        """
        return np.piecewise(u,[u<=0, u>0],[0,  lambda u : np.exp(-1/u)])

    def S(u):
        """
        Auxiliary S function that appears in the windowing function c_inf_window.
        """
        return R(u)/(R(u)+R(1-u))


    u = (t - t0)/tau
    y = A*S(u)*S(T/tau-u)

    return y


Msat_Py = 800e3
Msat_Pyirrad = 400e3

zeta = 100
rise = 25

sample.material["Msat"] = Msat_Py - smooth_window(-zeta/2,zeta,rise,Msat_Pyirrad,sample.xyz.x)

Using the scan_along_curve() method of the sample we can show the magnetization across the width of the waveguide. Note that material["Msat"] itself is a container object, while the array holding the local values is contained in material["Msat"].value. Here, the curve is defined by providing a start and end point.

[3]:
Msat_along_line, line_coords = sample.scan_along_curve(
                                                       sample.material["Msat"].value,
                                                       curve = ((-W/2,0,0), (W/2,0,0)),
                                                       num_points=int(W/res_W),
                                                       return_curve=True
                                                      )

Setting return_curve=True also returns the coordinates on the curve as a MeshVector. Using this, we can easily plot the scanned saturation as a function of the \(x\) coordinates stored in line_coords.x.

[4]:
from plotly import graph_objects as go

fig = go.Figure()



fig.add_trace(
                go.Scatter(
                    x=line_coords.x,
                    y=Msat_along_line*1e-3,
                    mode="lines"
                )
            )


fig.update_xaxes(title_text="<i>x</i> (nm)", range=(-W/2,W/2))
fig.update_yaxes(title_text="<i>M</i><sub>s</sub> (kA/m)", range=(0,900))

fig.update_layout(
        template="simple_white",
        height=300,
        width=600,
        hoverlabel={"bordercolor": "rgba(255,255,255,1)"},
    )

fig.show(renderer="notebook") # remove this line when running on your computer

Equilibrium under applied external field#

Let us now apply a transversal field and calculate the equilibrium state.

[5]:
sample.mag = tx.vectorfields.homogeneous(sample.xyz,90,10)
sample.Bext = (300e-3,0,0)  # same as sample.external_field

relaxation = tx.experiments.relax(sample,tolerance=1e-11)
Minimizing energy in using 'L-BFGS-B' (tolerance 1e-11) ...
energy length density: -3.828206970046140e-11 J/m, <mag.x> = 1.00, <mag.y> = 0.02, <mag.z> = 0.00
Success!

It is best to visualize the equilibrium again by taking line scans along the transversal direction. Since the length of the magnetization vector changes in space, we will do a scan of both the unitary direction \(\mathbf{m}\) (mag) and the full magnetization \(\mathbf{M}\) (mag_full). To bring them both to the same unit and order of magnitude, we will divide the full magnetization by the average saturation \(\langle M_\mathrm{s}\rangle\) (material["Msat"].average). We can perform the line scan along the same curve as by before by simply providing the line_coords from above as the curve argument of the scan_along_curve() method.

[6]:
mag_dir_along_line = sample.scan_along_curve(
                                               sample.mag,
                                               curve = line_coords,
                                               num_points=int(W/res_W),
                                              )

mag_full_along_line = sample.scan_along_curve(
                                               sample.mag_full/sample.material["Msat"].average,
                                               curve = line_coords,
                                               num_points=int(W/res_W),
                                              )

We plot the different componets of the two vectors together. We can loop over the components of the MeshVectors mag_full_along_line and mag_dir_along_line by looping over their component_names and component attritubes.

[7]:
fig2 = go.Figure()


colors = [
    "#86337A",
    "#D16F6B",
    "#EAB44F"
    ]


# Looping over the components of the full (rescaled) magnetization.
for color, comp_name, component in zip(colors,
                                       mag_full_along_line.component_names,
                                       mag_full_along_line.components
                                      ):
    fig2.add_trace(
                    go.Scatter(
                        x=line_coords.x,
                        y=component,
                        mode="lines",
                        name=comp_name,
                        legendgroup="0",
                        line=dict(color=color),
                        legendgrouptitle_text="scaled mag. <b><i>M</i></b>/<<i>M</i><sub>s</sub>>",
                    )
                )

# Looping over the components of the magnetization direction.
for color, comp_name, component in zip(colors,
                                       mag_dir_along_line.component_names,
                                       mag_dir_along_line.components
                                      ):
    fig2.add_trace(
                    go.Scatter(
                        x=line_coords.x,
                        y=component,
                        mode="lines",
                        line=dict(color=color, width=1, dash='dash'),
                        name=comp_name,
                        legendgroup="1",
                        legendgrouptitle_text="direction <b><i>m</i></b>",
                    )
                )

fig2.update_xaxes(title_text="<i>x</i> (nm)", range=(-W/2,W/2))

fig2.update_layout(
        template="simple_white",
        height=600,
        width=600,
        hoverlabel={"bordercolor": "rgba(255,255,255,1)"},
    )

fig2.show(renderer="notebook") # remove this line when running on your computer