Chapter 1: PIMM & VSD Procedures
Welcome to the first chapter! Here we learn how to automate two common micromagnetic experiments—PIMM (Pulse‑Induced Microwave Magnetometry) and VSD (Voltage Spin Diode)—using high‑level “recipes” in cmtj
. These procedures orchestrate many low‑level steps (setting fields, running simulations, computing resistances, doing FFTs) so you can focus on “what” you want to measure, not “how” to do every detail.
1. Motivation & Central Use Case
Imagine you have a magnetic junction and you want to:
- Apply a short magnetic pulse.
- Record how the magnetization rings down (that’s PIMM).
- Sweep frequencies of a sinusoidal drive and measure the spin‑diode voltage (that’s VSD).
Writing all the boilerplate to set fields, run the solver, extract logs, do FFTs, combine layers… is tedious. PIMM_procedure and VSD_procedure let you do this in one call.
Use case in code:
from cmtj.utils.procedures import PIMM_procedure, VSD_procedure, ResistanceParameters
import numpy as np
# 1. Define a small field scan:
Hvecs = np.array([[0,0,1e5], [0,0,1.2e5]])
# 2. Define resistance parameters per layer (length, width, base resistances…)
res_params = [ResistanceParameters(Rxx0=100, Rxy0=5, Rahe=1, Ramr=0.5, w=50e-9, l=100e-9)]
# 3. Call PIMM:
spectrum, freqs, data = PIMM_procedure(junction, Hvecs, 1e-12, res_params)
# 4. Call VSD at some frequencies:
freqs_to_test = np.linspace(1e9, 10e9, 50)
vsd_map = VSD_procedure(junction, Hvecs, freqs_to_test, 1e-12, res_params)
After that you get:
spectrum
: PIMM amplitudes vs frequencyfreqs
: the frequency axisdata["Rx"]
,data["Ry"]
,data["m_avg"]
… for further analysisvsd_map
: a 2D array of spin‑diode voltages vs field & frequency
2. Key Concepts
- Junction Your magnetic system (see Magnetic Layer Models).
- Drivers
- External field: constant Hext
- Oersted field: pulse (PIMM) or sine (VSD) via
ScalarDriver
+AxialDriver
- ResistanceParameters Holds geometry + magnetoresistance coefficients for each layer.
- FFT & Spectrum
We take the time‑series of magnetization projection, run an FFT, and keep frequencies ≤
max_frequency
.
3. How to Run PIMM & VSD
3.1 PIMM Procedure (High‑Level)
spectrum, freqs, other = PIMM_procedure(
junction=your_junction,
Hvecs=Hvecs,
int_step=1e-12,
resistance_params=res_params,
Hoe_duration=5, # pulse length in #steps
simulation_duration=5e-9,
take_last_n=200 # how many last time‑points to FFT
)
- Inputs:
junction
: your initializedJunction
Hvecs
: array of external fieldsint_step
: time‑step in secondsresistance_params
: list ofResistanceParameters
per layer- Outputs:
spectrum[h, f]
: FFT amplitude for each H and frequency binfreqs[f]
: array of frequenciesother
: dict with static Rx, Ry, average magnetization, raw trajectories iffull_output=True
3.2 VSD Procedure (High‑Level)
vsd_map = VSD_procedure(
junction=your_junction,
Hvecs=Hvecs,
frequencies=np.linspace(1e9,5e9,30),
int_step=1e-12,
resistance_params=res_params,
Hoe_excitation=40
)
- Inputs:
frequencies
: drive frequencies for the sine Oersted fieldRtype
: choose"Rx"
,"Ry"
or"Rz"
- Output:
vsd_map[h, f]
: DC mixing voltage vs H and drive frequency
4. Inside PIMM_procedure: Step‑by‑Step
Before diving into code, here is what happens:
sequenceDiagram
participant U as User code
participant P as PIMM_procedure
participant J as Junction
participant F as FFT routine
participant R as Resistance calculator
U->>P: call PIMM_procedure(...)
P->>J: clear logs, set Hext & Oe
P->>J: optionally add disturbance
P->>J: runSimulation(duration, step)
P->>J: getLog()
P->>R: compute Rx, Ry from m(t)
P->>F: FFT average m component
P-->>U: return spectrum, freqs, data
5. Peek at the Code
File: cmtj/utils/procedures.py
5.1 Building the Oersted Pulse
# decide which axis gets the pulse
if Hoe_direction == Axis.zaxis:
oedriver = AxialDriver(
NullDriver(), NullDriver(),
ScalarDriver.getStepDriver(0, amplitude, 0, step * duration_steps)
)
# similar for x and y...
We wrap a step‑function in a 3‑component AxialDriver
.
5.2 Main Loop over H Fields
for H in Hvecs:
junction.clearLog()
# 1) set static field
junction.setLayerExternalFieldDriver(
"all",
AxialDriver(
ScalarDriver.getConstantDriver(H[0]),
ScalarDriver.getConstantDriver(H[1]),
ScalarDriver.getConstantDriver(H[2]),
),
)
# 2) set Oe pulse/sine
junction.setLayerOerstedFieldDriver("all", oedriver)
# 3) apply small random disturbance
# 4) junction.runSimulation(sim_dur, int_step, int_step)
# 5) extract log, compute Rx,Ry, FFT
Each iteration collects:
- Static resistances (
Rx
,Ry
) viacalculate_resistance_series
- Spectrum of the magnetization ring‑down
6. VSD_procedure Internals
Very similar—except:
- Uses a sine Oersted driver at each
frequency
- Computes the time‑series of R(t), multiplies by Idrive(t) and integrates to get the mixing voltage via
compute_sd
.
Under the hood:
dynamicI = np.sin(2 * math.pi * f * np.asarray(log["time"]))
vmix = compute_sd(R, dynamicI, int_step)
7. Conclusion & Next Steps
You’ve learned how PIMM_procedure and VSD_procedure hide all the low‑level plumbing required to run typical magnetization‑dynamics experiments. Next, we’ll look at how to generate the field lists (Hvecs
) using convenient scans.
On to FieldScan Utilities!
Generated by AI Codebase Knowledge Builder