# The model object#

In this chapter we will get familiar with the flatspin model object, which implements the theoretical model. We will cover how to create a model object, setting parameters, and different model attributes.

The main object in flatspin is the model (flatspin.model). Each model class defines a spin ice geometry, which specifies the positions and angles of the spins. The SquareSpinIceClosed class, for instance, creates a square spin ice geometry (with “closed” edges):

from flatspin.model import SquareSpinIceClosed

model = SquareSpinIceClosed()
model.plot();


flatspin comes with model classes for some common geometries, shown in the gallery below:

import flatspin.model

class_names = ['SquareSpinIceClosed', 'SquareSpinIceOpen',
'KagomeSpinIce', 'KagomeSpinIceRotated',
'PinwheelSpinIceDiamond', 'PinwheelSpinIceLuckyKnot',
]

n_cols = 3
n_rows = int(np.ceil(len(class_names) / n_cols))
plt.figure(figsize=(2*n_cols, 2*n_rows))
for i, name in enumerate(class_names):
cls = getattr(flatspin.model, name)
plt.subplot(n_rows, n_cols, i+1)
plt.title(name)
model = cls()
model.plot()
plt.axis(False)


If you would like to add your own geometries, see Extending flatspin.

## Model parameters#

Properties of the model can be changed through parameters, which are passed as keyword arguments to the model class. Note that the model only accepts keyword arguments (and no positional arguments).

For example, we may change the size parameter to create a larger spin ice:

model = SquareSpinIceClosed(size=(10,5))
print(f"10x5 square ASI has", model.spin_count, "spins")
model.plot();

10x5 square ASI has 115 spins


Note that size is geometry-specific: for SquareSpinIceClosed, the size specifies the number of columns (rows) of horizontal (vertical) magnets. For KagomeSpinIce, the size denotes the number of hexagonal units:

from flatspin.model import KagomeSpinIce
model = KagomeSpinIce(size=(10,5))
print(f"10x5 kagome ASI has", model.spin_count, "spins")
model.plot();

10x5 kagome ASI has 179 spins


Other important parameters include alpha (the coupling strength), hc (the coercive field), disorder (random variations in the coercive fields) and temperature (absolute temperature in Kelvin). For a list of available parameters, see SpinIce.

## Dealing with spins#

The state of all the spins is stored in the spin array. Spin values are either 1 or -1, and are all initialized to 1 at model instantiation.

model = SquareSpinIceClosed()
model.spin

array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int8)


You may access elements of this array directly to read or modify the state of spins. Alternatively, use flip() to flip a single spin, set_spin() to set the state of all spins, or polarize() to reset all spins to 1 or -1.

model.spin[0] = -1
model.spin[-1] = -1
model.flip(4)
model.plot();


The spin array has a flat index, where spins are ordered sequentially. Sometimes it can be easier to work in a different coordinate system, which is where spin labels come in. The left plot below shows the index of each spin. The right plot shows the corresponding labels, for SquareSpinIceClosed, which uses a (row, col) labeling scheme.

plt.figure(figsize=(8,4))
plt.subplot(121)
plt.title("Spin indices")
model.plot()
for i in model.indices():
plt.text(model.pos[i,0], model.pos[i,1], str(i), ha='center', va='center')

plt.subplot(122)
plt.title("Spin labels")
model.plot()
for i, l in enumerate(model.labels):
plt.text(model.pos[i,0], model.pos[i,1], tuple(l), ha='center', va='center')


You can use the L object to look up the spin index of a label, or a label range:

L = model.L
print("(4,2):", L[4,2])
print("Row 3:", L[3])
print("Column 4:", L[:,4])
print("Rows 1-3:", L[1:4])
print("Odd rows:", L[1::2])

(4,2): 20
Row 3: [13 14 15 16 17]
Column 4: [ 8 17 26 35]
Rows 1-3: [ 4  5  6  7  8  9 10 11 12 13 14 15 16 17]
Odd rows: [ 4  5  6  7  8 13 14 15 16 17 22 23 24 25 26 31 32 33 34 35]


## Geometry#

Spin ice geometry is defined by the positions and angles of all the spins, and are stored in the pos and angle attributes. Positions are in reduced units, defined by alpha (see Theory). The angles are in radians and define the rotation for the spins assuming a positive spin value of 1.

Please note that these attributes are considered read-only and cannot be changed after model initialization.

print(f"Spin 0 has position {model.pos[0]} and angle {np.rad2deg(model.angle[0])}")
print(f"Spin 4 has position {model.pos[4]} and angle {np.rad2deg(model.angle[4])}")

Spin 0 has position [0.5 0. ] and angle 0.0
Spin 4 has position [0.  0.5] and angle 90.0


As an alternative to tuning the coupling strength alpha, the distance between spins may be adjusted by the lattice_spacing parameter. This affects the positions of the spins directly, as opposed to indirectly through alpha (see Theory).

model2 = SquareSpinIceClosed(lattice_spacing=10)
# Notice change in x/y labels when we plot()
model2.plot();


## Magnetization vectors#

As mentioned above, angle is independent of the current spin state. To obtain the magnetization direction, use vectors.

print(f"Spin 0 has magnetization {model.vectors[0]}")
print(f"Spin 1 has magnetization {model.vectors[1]}")
print(f"Spin 4 has magnetization {model.vectors[4]}")

Spin 0 has magnetization [-1. -0.]
Spin 1 has magnetization [1. 0.]
Spin 4 has magnetization [-6.123234e-17 -1.000000e+00]


## Coercive fields and disorder#

The coercive field defines the critical field strength required to flip a spin (see also Switching). The coercive fields for all spins are stored in the threshold array of the model object. By default, the coercive fields are uniformly set to the parameter hc. We can introduce small variations in the coercive fields by setting the disorder parameter, in which case the thresholds are sampled from a normal distribution with mean hc and standard deviation disorder * hc.

Below we plot a histogram of the coercive fields with 1% and 5% disorder.

model1 = SquareSpinIceClosed(size=(25,25), hc=0.1, disorder=0.01)
model5 = SquareSpinIceClosed(size=(25,25), hc=0.1, disorder=0.05)
bins = np.linspace(0.08, 0.12, 21) - 0.001
plt.hist(model1.threshold, bins=bins, label='1% disorder', alpha=0.5)
plt.hist(model5.threshold, bins=bins, label='5% disorder', alpha=0.5)
plt.legend()
plt.xlabel("hc");


## GPU acceleration#

flatspin provides GPU acceleration to speed up calculations on the GPU, but note that this must be explicitly enabled by setting the parameter use_opencl=True. It is primarily the calculations of the magnetic fields that benefit from running on the GPU.