Astroid clocking#
This example shows how to simulate astroid clocking in flatspin, as described in [Jensen et al., 2024]:
“Clocked Dynamics in Artificial Spin Ice.” Nature Communications 15, no. 1 (2024): 1.
Astroid clocking exploits the shape of the switching astroids in an ASI to selectively switch a subset of the magnets. Fig. 1a shows pinwheel ASI, with its two interleaved sublattices \(L_a\) (solid outline) and \(L_b\) (dashed outline). There are four possible magnet states, indicated by their color: orange/blue for \(L_a\) and pink/green for \(L_b\).
Fig. 1b shows the two switching astroids for the magnets in sublattice \(L_a\) (solid lines) and \(L_b\) (dashed lines). Four clock fields are defined in the figure: \(H_A\), \(H_B\), \(H_a\) and \(H_b\). We refer to fields in uppercase as the positive fields, and lowercase as the negative fields. Applying \(H_A\) will only switch magnets within \(L_a\), since it only crosses the astroid boundary of \(L_a\) (and not \(L_b\)). Furthermore, since \(H_A\) is aligned with the orange state, it will only switch blue magnets to the orange state. The same goes for the other fields.
Fig. 1 Astroid clocking#
A key principle of astroid clocking is to tune the strengths of the clock fields to be close, but still inside the astroid boundary. Then it is up to the dipolar fields from neighbor magnets to push a magnet past the astroid boundary, and cause preferential switching. It is also possible to use field strengths that are just outside the boundary, in which case the dipolar fields may pull magnets back into the astroid, and preferentially prevent switching. In pinwheel ASI, astroid clocking can be used to preferentially switch magnets along domain walls.
Here we demonstrate how to use flatspin for astroid clocking. First we create a model of a 30x30 pinwheel ASI.
# Create the model
from flatspin.model import PinwheelSpinIceDiamond
params = dict(
size=(30, 30),
use_opencl=1,
spin_angle=-45,
spin_axis=0,
alpha=0.0013,
hc=0.2,
sw_b=0.38,
sw_c=1,
sw_beta=1.3,
sw_gamma=3.6,
)
model = PinwheelSpinIceDiamond(**params)
Then we set up an initial octagonal domain in the center of the ASI:
from skimage import morphology
# Utility function to initialize an octagon-shaped domain
def init_octagon(model, m, n, center, polarize=-1):
G = model.grid()
init = np.ones(G.size)
oct = morphology.octagon(m, n)
oct = 2*oct.astype(int)-1
oct *= -1
rows, cols = init.shape
cy, cx = center
oy, ox = oct.shape
y0, x0 = cy - oy//2, cx - ox//2
init[y0:y0+oy, x0:x0+ox] = oct
model.set_grid('spin', init * polarize)
# Initial state: octagon
cx, cy = model.size
init_octagon(model, 9, 5, (cy, cx-1), -1)
init = model.spin.copy()
snapshot = dict(style="stadium", width=.25, scale=1.3)
model.plot(**snapshot);
Next we define the four clock fields, and create a PulseTrain
encoder which will allow us to map lists of field names ("ABABAB"
) to sequences of external fields:
# Set up clock fields and encoder
from flatspin.encoder import PulseTrain
H = 0.0765
pulses={
"A": (H, 22), # (field strength, angle)
"a": (H, 180+22),
"B": (H, -22),
"b": (H, 180-22)
}
encoder = PulseTrain(pulses=pulses)
Unipolar clocking#
A clock protocol is a sequence of clock fields applied in a repeated fashion. Unipolar clocking only employs the positive (or negative) clock fields.
Fig. 2 Unipolar clocking#
This example shows AB clocking, where the field \(H_A\) and \(H_B\) are applied in an alternate fashion to gradually grow the center domain. After four clock cycles of AB, we switch to ab clocking and use the negative fields \(H_a\) and \(H_b\) to gradually reverse the domain.
from flatspin.plotting import animate_spins
sequence = "AB"*4 + "ab"*4
h_ext = encoder(list(sequence))
model.set_spin(init)
spins = [model.spin.copy()]
for h_ext_i in h_ext:
model.set_h_ext(h_ext_i)
model.relax()
spins.append(model.spin.copy())
labels = ["init"] + list(sequence)
anim = animate_spins(model, spins, labels, highlight_flips=True, fps=5, **snapshot)
plt.close() # Only show the animation
HTML(anim.to_jshtml())
/builds/flatspin/flatspin/.tox/docs/lib/python3.10/site-packages/pyopencl/__init__.py:570: CompilerWarning: Non-empty compiler output encountered. Set the environment variable PYOPENCL_COMPILER_OUTPUT=1 to see more.
lambda: self._prg.build(options_bytes, devices),
Bipolar clocking#
Bipolar clocking uses both the positive and negative fields in each clock cycle.
Fig. 3 Bipolar clocking#
Below we demonstrate aAbB clocking, which results in more complex dynamics as domains can both grow and shrink within each clock cycle.
sequence = "aAbB"*10
h_ext = encoder(list(sequence))
model.set_spin(init)
spins = [model.spin.copy()]
for h_ext_i in h_ext:
model.set_h_ext(h_ext_i)
model.relax()
spins.append(model.spin.copy())
labels = ["init"] + list(sequence)
anim = animate_spins(model, spins, labels, highlight_flips=True, **snapshot)
plt.close() # Only show the animation
HTML(anim.to_jshtml())