Skip to content

Introduction

In the macromagnetic simulations we distinguish between the following contributions that constitute the \(\mathbf{H}_\textrm{eff}\):

\[ \mathbf{H}_\textrm{eff} = \mathbf{H}_\textrm{ext} + \mathbf{H}_\textrm{IEC} + \mathbf{H}_\textrm{Oe} + \mathbf{H}_\textrm{K} + \mathbf{H}_\textrm{demag} + \mathbf{H}_\textrm{dipole} + \mathbf{H}_\textrm{th}^* + \mathbf{H}_\textrm{1/f}^* \]

where each component corresponds, respectively, to the applied external field, interlayer exchange coupling (IEC), Oersted field, anisotropy field, demagnetising, dipole, thermal, and \(1/f\) noise field. The \(^*\) superscripts denote the stochastic contributions (those require a stochastic solver, more on that in the Macromagnetic models section).

In-API classification

We will go through the contributions step by step. However, before we do that, it is useful to mention that the contributions can be divided into 3 categories with respect to their relationship with a Driver system:

  1. ScalarDriver driven contributions: \(\mathbf{H}_\textrm{K}\), \(\mathbf{H}_\textrm{th}\), and \(\mathbf{H}_\textrm{IEC}\) Those contributions have their magnitude changed only. The exception is \(\mathbf{H}_\textrm{K}\) which has a constant axis passed in the constructor of a Layer object. Other than that, only the magnitude of those effect may be controlled, their direction is computed internally, as it depends on the \(\mathbf{m}\) vectors.
  2. AxialDriver driven contributions: \(\mathbf{H}_\textrm{ext}\), \(\mathbf{H}_\textrm{Oe}\). Axial contributions can have magntidue controllers in any of the 3 directions, along x, y and z axis. Since AxialDriver consists of 3 ScalarDrivers (one for each axis), it is easy to manipulate each axis independently, magnitudewise.
  3. static contributions \({H}_\textrm{dipole}\), and \(\mathbf{H}_\textrm{demag}\). Static contributions are not driven by any Driver system, they are simply added to the \(\mathbf{H}_\textrm{eff}\) field. This may be subject to change in future API versions.

Note

Almost every contribution may be set either using Layer api or Junction api. They both have the same set of arguments, and the naming convention is such that if e.g. Layer has a method setContribution, then Junction has a method setLayerContribution and requires one additional argument specyfing the layer id (or all if it is to be set for all layers in the Junction). There are some exceptions to this, e.g. setLayerIEC, which is only defined for two or more layers, therefore it cannot be set from a Layer object.

External field

The external field is the simplest contribution to the effective field. It is the sum of the applied fields.

Name Unit Description
\(H_\textrm{x}\) A/m Value of field in x direction
\(H_\textrm{y}\) A/m Value of field in y direction
\(H_\textrm{z}\) A/m Value of field in y direction
layer.setExternalFieldDriver(
    AxialDriver(
        ScalarDriver.getConstantDriver(100),
        ScalarDriver.getConstantDriver(0),
        ScalarDriver.getSineDriver(0, 300, 20e39, 0)
    )
)

or for the Junctions api:

device.setLayerExternalFieldDriver(
    "free", # this value of course depends on the layer id
    AxialDriver(
        ScalarDriver.getConstantDriver(100),
        ScalarDriver.getConstantDriver(0),
        ScalarDriver.getSineDriver(0, 300, 20e39, 0)
    )
)

Oersted field

The Oersted field is the field generated by the flow of current. Currently it is separated from the external field, but it is set the same way, irrespective of the actual current setting in the API. This may be subject to change.

Name Unit Description
\(H_\textrm{x}\) A/m Value of field in x direction
\(H_\textrm{y}\) A/m Value of field in y direction
\(H_\textrm{z}\) A/m Value of field in y direction
layer.setOerstedFieldDriver(
    AxialDriver(
        ScalarDriver.getConstantDriver(100),
        ScalarDriver.getConstantDriver(0),
        ScalarDriver.getSineDriver(0, 300, 20e39, 0)
    )
)

or for the Junctions api:

device.setLayerOerstedFieldDriver(
    "free", # this value of course depends on the layer id
    AxialDriver(
        ScalarDriver.getConstantDriver(100),
        ScalarDriver.getConstantDriver(0),
        ScalarDriver.getSineDriver(0, 300, 20e39, 0)
    )
)

Exchange field -- IEC

Interlayer exchange coupling is a scalar driven field contribution. It governs the RKKY-like interaction between magnetic layers.

Name Unit Description
\(J_\textrm{linear}\) \(J/m^2\) Linear value of the IEC contribution
\(J_\textrm{quad}\) \(J/m^2\) Linear value of the IEC contribution
layerA str Layer id of a participating layer
layerB str Layer id of other participating layer

Linear layer is being set with:

device.setIECDriver(
    "free" # this value of course depends on the layer id
    "bottom", # this value of course depends on the layer id
    ScalarDriver.getConstantDriver(1e-4)
)

and quadratic:

device.setQuadIECDriver(
    "free" # this value of course depends on the layer id
    "bottom", # this value of course depends on the layer id
    ScalarDriver.getConstantDriver(1e-6)
)

The resulting interaction field for layer 1 \(\mathbf{m}_1\) is computed as:

\[ \mathbf{H}_{IEC,1} = -\frac{1}{t_{FM} M_s}\frac{\partial E_{d, int}}{\partial \mathbf{m}_1} = \frac{1}{t_{FM} M_s}[J_\textrm{linear}\mathbf{m}_2 + 2J_\textrm{quad} (\mathbf{m}_1 \cdot \mathbf{m}_1)\mathbf{m}_2] \]

Dipole and demag

Those two contributions have different origins, but in CMTJ they share a similar api and way of computation. Both are given by tensors, and may be computed externally.

\[ \mathbf{H}_\textrm{dipole} = -\frac{M_\textrm{s}}{\mu_0}\mathbf{N}_\textrm{dipole}\mathbf{m} \]

where \(\mathbf{N}_\textrm{dipole}\) is the dipole tensor of the layer. The demag field is the same way, but with the tensor \(\mathbf{N}_\textrm{demag}\) of the layer. Since demag tensor is inherent to the geometry (shape) of the system, it is passed in the Layer object.

Name Unit Description
\(\mathbf{N}_{inter}\) - Tensor of the interaction for dipole or demag

The dipole depends on the external interaction and may be due any magnetic interaction a device or layer has with any other magnetic object. Therefore, it is passed in the Layer API as:

layer.setTopDipoleTensor(
    [
        CVector(0, 5e-8, 1e-24),
        CVector(5e-8, -2e-6, 0),
        CVector(1e-23, 0, 1e-23),
    ]
)
layer.setBottomDipoleTensor(
    [
        CVector(0, 5e-8, 1e-24),
        CVector(5e-8, -2e-6, 0),
        CVector(1e-23, 0, 1e-23),
    ]
)

Under the hood we simply sum the contributions from both:

\[ \mathbf{H}_\textrm{dipole} = \mathbf{H}_\textrm{dipole, top} + \mathbf{H}_\textrm{dipole, bottom} \]

We set for top and bottom separately since it may come for instance from top and bottom layer and thus top or bottom may be different. Effectively, you can just pass either, where you sum the dipole tensors and it'll have the same effect. However, API makes this convenient separation to logically separate those contributions.

Note

Dipole tensor for now is only set from the Layer API. We may add a function for adding it in the Junction API as well in near future.

Anisotropy

Anisotropy computation has two components -- axis \(\mathbf{a}\) which is in CMTJ a vector, and value \(K_\textrm{u}\) which is a scalar. The axis is passed in the Layer constructor under anis parameter. The scalar value, however, is driven with a ScalarDriver object and can be dynamically operated from either Layer or Junction API.

Name Unit Description
\(\mathbf{K}_\textrm{u}\) \(J/m^3\) Value of the anisotropy constant
layer.setAnisotropyDriver(
    ScalarDriver.getConstantDriver(1e6)
)

or Junction API:

device.setLayerAnisotropyDriver(
    "free", # this value of course depends on the layer id
    ScalarDriver.getConstantDriver(1e6)
)

The resulting anisotropy field is computed as:

\[ \mathbf{H}_{\textrm{anis}} = \frac{2K_\textrm{u}}{M_s}(\mathbf{m}\cdot\mathbf{a})\mathbf{a} \]