|
| 1 | +""" |
| 2 | +Current-Induced Magnetization Switching (CIMS) Hysteresis Simulation |
| 3 | +
|
| 4 | +GOAL: |
| 5 | +This simulation studies current-induced magnetization switching in spin-orbit torque (SOT) |
| 6 | +devices by analyzing hysteresis loops under varying current densities and Oersted field |
| 7 | +contributions. The simulation maps the stable magnetization states as a function of |
| 8 | +applied current, revealing switching thresholds and stability regions. |
| 9 | +
|
| 10 | +CRITICAL SIMULATION MECHANISMS: |
| 11 | +1. Spin-Orbit Torque (SOT): Models both damping-like and field-like torque components |
| 12 | + arising from spin-orbit coupling in heavy metal/ferromagnet bilayers |
| 13 | +2. Current Sweep Protocol: Applies bidirectional current sweeps with step drivers to |
| 14 | + map complete hysteresis loops and identify switching thresholds |
| 15 | +3. Oersted Field Effects: Includes current-induced Oersted fields that provide additional |
| 16 | + torque contributions and can assist or oppose SOT switching |
| 17 | +4. Magnetization Dynamics: Solves extended LLG equation including SOT terms using |
| 18 | + adaptive time stepping for accurate switching dynamics |
| 19 | +5. Stability Analysis: Monitors final magnetization states after current pulses to |
| 20 | + determine stable configurations and switching probability |
| 21 | +6. Resistance Readout: Uses GMR (Giant Magnetoresistance) model to convert magnetization |
| 22 | + states to resistance values for experimental comparison |
| 23 | +7. Multi-parameter Sweep: Varies Oersted field scaling to study the interplay between |
| 24 | + SOT and Oersted field contributions |
| 25 | +
|
| 26 | +The simulation generates current-resistance hysteresis loops that reveal switching |
| 27 | +thresholds, coercive currents, and the influence of Oersted fields on switching |
| 28 | +efficiency, providing insights for optimizing SOT-based memory devices. |
| 29 | +""" |
| 30 | + |
| 31 | +from collections import defaultdict |
| 32 | +from cmtj import * |
| 33 | +from cmtj.utils import compute_gmr |
| 34 | +import numpy as np |
| 35 | +import matplotlib.pyplot as plt |
| 36 | +from cmtj.utils import TtoAm |
| 37 | +from tqdm import tqdm |
| 38 | + |
| 39 | +try: |
| 40 | + import scienceplots |
| 41 | +except ImportError: |
| 42 | + pass |
| 43 | + |
| 44 | + |
| 45 | +demagTensor = [CVector(0.0, 0.0, 0.0), CVector(0.0, 0.0, 0.0), CVector(0.0, 0.0, 1)] |
| 46 | +""" |
| 47 | +Compute the current scan. |
| 48 | +The facing area is thickness x width |
| 49 | +
|
| 50 | +Below, you can change the torque signs! |
| 51 | +Depending on the Hfl sign the Oersted field will assist or oppose the SOT switching. |
| 52 | +If sign is changed, or one of the torques is removed, adjust the current density accordingly. |
| 53 | +""" |
| 54 | +sgnHdl = 1 |
| 55 | +sgnHfl = -1 |
| 56 | + |
| 57 | +Hdl = sgnHdl * 0.000371 * TtoAm |
| 58 | +Hfl = sgnHfl * 0.000433 * TtoAm |
| 59 | +jden1 = 6e10 |
| 60 | +HDL = Hdl / jden1 |
| 61 | +HFL = Hfl / jden1 |
| 62 | + |
| 63 | +last_N = 100 |
| 64 | +dt = 6e-9 |
| 65 | +tstart = 1e-9 |
| 66 | + |
| 67 | +tstep = 5e-13 |
| 68 | +sim_time = 15e-9 |
| 69 | + |
| 70 | + |
| 71 | +t_hm = 6e-9 |
| 72 | +t_fm = 1.7e-9 |
| 73 | +Kdir1 = CVector(0, 0, 1.0) |
| 74 | +pdir1 = CVector(0.0, 1.0, 0.0) |
| 75 | +Ku1 = 0.3e6 |
| 76 | +Ms = 1.45 |
| 77 | +alpha = 0.0064 |
| 78 | +layer_free = Layer.createSOTLayer( |
| 79 | + id="free", |
| 80 | + mag=CVector(1, 0, 0), |
| 81 | + anis=Kdir1, |
| 82 | + Ms=Ms, |
| 83 | + thickness=t_fm, |
| 84 | + cellSurface=0.0, |
| 85 | + demagTensor=demagTensor, |
| 86 | + damping=alpha, |
| 87 | + dampingLikeTorque=HDL, |
| 88 | + fieldLikeTorque=HFL, |
| 89 | +) |
| 90 | + |
| 91 | +j = Junction([layer_free]) |
| 92 | +j.setLayerAnisotropyDriver("free", ScalarDriver.getConstantDriver(Ku1)) |
| 93 | +j.setLayerReferenceLayer("free", pdir1) |
| 94 | + |
| 95 | + |
| 96 | +j.clearLog() |
| 97 | +j.runSimulation(14e-9, tstep, tstep) |
| 98 | +m_components = defaultdict(list) |
| 99 | +hysteresis_scales = [] |
| 100 | +Hoescales = np.linspace(0, 2500, 3) |
| 101 | +Hoescales = np.concatenate((-Hoescales, Hoescales[1:])) |
| 102 | + |
| 103 | +Hoescales = np.asarray([-1000, -500, -100, 0, 100, 500, 1000]) |
| 104 | +Hoescales = [1, 0.5, 1e-1, 1e-2, 0, -1e-1, -1] |
| 105 | +Hoescales = [1, 0, -1] |
| 106 | + |
| 107 | +""" |
| 108 | +Below uncomment for specific cases depending on which, damping-like or field-like, torque is used. |
| 109 | +""" |
| 110 | +if abs(HDL) and abs(HFL): |
| 111 | + i_max = [0.1e12 for _ in range(len(Hoescales))] # both Hdl and Hfl only |
| 112 | +elif not abs(HFL) and not abs(HDL): |
| 113 | + i_max = [1.0e12 for _ in range(len(Hoescales))] # Hoe only |
| 114 | +elif abs(HDL) and not abs(HFL): |
| 115 | + i_max = [3e11, 3e11, 1e12, 3e13, 3e13, 3e13, 3e11] # Hdl only |
| 116 | +elif abs(HFL) and not abs(HDL): |
| 117 | + i_max = [2.0e11 for _ in range(len(Hoescales))] # Hfl only |
| 118 | +else: |
| 119 | + raise ValueError("Invalid torque configuration") |
| 120 | + |
| 121 | +jscans = [] |
| 122 | +for i, Hoescale in tqdm(enumerate(Hoescales), total=len(Hoescales)): |
| 123 | + v = CVector(0.001, 0.99, 0) |
| 124 | + v.normalize() |
| 125 | + j.setLayerMagnetisation("free", v) |
| 126 | + jscan = np.linspace(-i_max[i], i_max[i], 130) |
| 127 | + jscan = np.concatenate([jscan, jscan[::-1][1:]]) |
| 128 | + |
| 129 | + jscans.append(jscan) |
| 130 | + hysteresis = [] |
| 131 | + for current in jscan: |
| 132 | + j.clearLog() |
| 133 | + j.setLayerCurrentDriver("all", stepDriver(0, current, tstart, tstart + dt)) |
| 134 | + j.setLayerOerstedFieldDriver( |
| 135 | + "all", |
| 136 | + AxialDriver( |
| 137 | + constantDriver(0), |
| 138 | + stepDriver(0, Hoescale * current * t_hm / 2, tstart, tstart + dt), |
| 139 | + constantDriver(0), |
| 140 | + ), |
| 141 | + ) |
| 142 | + j.runSimulation(sim_time, tstep, tstep) |
| 143 | + log = j.getLog() |
| 144 | + m = np.asarray( |
| 145 | + [ |
| 146 | + [log[f"{str_}_mx"], log[f"{str_}_my"], log[f"{str_}_mz"]] |
| 147 | + for str_ in ("free",) |
| 148 | + ] |
| 149 | + ) |
| 150 | + |
| 151 | + Rstable = compute_gmr( |
| 152 | + Rp=100, |
| 153 | + Rap=200, |
| 154 | + m1=m.squeeze()[:, -last_N:], |
| 155 | + m2=np.asarray([[0, 1, 0] for _ in range(last_N)]).transpose(), |
| 156 | + ).mean() |
| 157 | + str_ = "free" |
| 158 | + m_x_stable = np.mean(log[f"{str_}_mx"][-last_N:]) |
| 159 | + m_y_stable = np.mean(log[f"{str_}_my"][-last_N:]) |
| 160 | + m_z_stable = np.mean(log[f"{str_}_mz"][-last_N:]) |
| 161 | + m_components["x"].append(m_x_stable) |
| 162 | + m_components["y"].append(m_y_stable) |
| 163 | + m_components["z"].append(m_z_stable) |
| 164 | + hysteresis.append(Rstable) |
| 165 | + |
| 166 | + hysteresis = np.asarray(hysteresis) |
| 167 | + |
| 168 | + hysteresis_scales.append(hysteresis) |
| 169 | + |
| 170 | + |
| 171 | +with plt.style.context(["nature"]): |
| 172 | + fig, ax = plt.subplots(1, 1, dpi=250) |
| 173 | + # Set white background |
| 174 | + fig.patch.set_facecolor("white") |
| 175 | + ax.set_facecolor("white") |
| 176 | + # get a color scale |
| 177 | + colors = plt.cm.viridis(np.linspace(0, 1, len(hysteresis_scales))) |
| 178 | + for i, hysteresis in enumerate(hysteresis_scales): |
| 179 | + ax.plot( |
| 180 | + jscans[i] * 1e-12, |
| 181 | + hysteresis, |
| 182 | + label=f"Hoe = {Hoescales[i]}", |
| 183 | + color=colors[i], |
| 184 | + ) |
| 185 | + ax.set_xlabel(r"$\mathrm{j}$ ($\mathrm{TA/m^2}$)") |
| 186 | + ax.set_ylabel(r"$\mathrm{R}_\mathrm{stable}$ ($\Omega$)") |
| 187 | + cbar = plt.colorbar( |
| 188 | + plt.cm.ScalarMappable( |
| 189 | + norm=plt.Normalize(min(Hoescales), max(Hoescales)), cmap=plt.cm.viridis |
| 190 | + ), |
| 191 | + ax=ax, |
| 192 | + label="Hoe", |
| 193 | + ) |
| 194 | + cbar.set_ticks(Hoescales) |
| 195 | + ax.set_title( |
| 196 | + rf"$H_\mathrm{{ext}} = 0, \alpha = {alpha}, \mu_0 M_\mathrm{{s}} = {Ms} \, \mathrm{{T}}$" |
| 197 | + "\n" |
| 198 | + rf"$H_\mathrm{{dl}} = {Hdl:.2f} \, \mathrm{{A/m}}, H_\mathrm{{fl}} = {Hfl:.2f} \, \mathrm{{A/m}}$" |
| 199 | + "\n" |
| 200 | + rf"$t_\mathrm{{fm}} = {t_fm*1e9:.0f}\, \mathrm{{nm}}, j_\mathrm{{den}} = {jden1/1e12:.2f} \, \mathrm{{TA/m^2}}$" |
| 201 | + ) |
| 202 | + fig.savefig( |
| 203 | + "./curated-examples/figures/cims-hysteresis.png", |
| 204 | + dpi=350, |
| 205 | + bbox_inches="tight", |
| 206 | + ) |
0 commit comments