The constructor of InitialSpin.
The initial scaled spin for each atom should be given as a number between -1 and 1 corresponding to the net spin-polarization in fractions of the atomic polarization according to Hund's rule.
Type: A sequence of numbers with the same length as the number of atoms in the system; or a list of tuples with atom indices and corresponding scaled spin values; or a list of tuples with element and scaled spin value; or a combination of the latter two. For noncollinear spin systems the tuple has four numbers, atom index, scaled spin, theta, phi, where the latter are physical spherical coordinates in units of Degree or Radians.
Default:
1.0 for each atom.
There are two basic ways to specify the initial spins of the atoms.
Using a simple list. In this case, scaled_spins is a list
containing the initial scaled spin for each atom, i.e. the number of entries in the list must be
equal to the number of atoms in the system (in the central region for
DeviceConfigurations).
Example: Set initial spin 1, -0.5, 1 on the first three atoms, 0 for the rest (the configuration contains 50 atoms).
bulk_configuration.setCalculator(
calculator = LCAOCalculator(),
initial_spin = InitialSpin(scaled_spins=[1.,-0.5,1.]+[0.,]*47)
)
Identify atoms, or groups of atoms, and set their initial spin individually.
In this case, scaled_spins is a list of tuples, each with two elements.
The first entry in the tuple can be an integer, to select an individual atom, or
an element (like Carbon), to select all atoms of a certain element.
The second entry is the initial scaled spin to set for the selected atoms.
Example: The previous example may be specified the following way:
bulk_configuration.setCalculator(
calculator = LCAOCalculator(),
initial_spin = InitialSpin(scaled_spins=[(0,1.),(1,-0.5),(2,1.)])
)
Set the spin 1 on Iron atoms, except for atoms with index 3 and 7.
bulk_configuration.setCalculator(
calculator = LCAOCalculator(),
initial_spin = InitialSpin(scaled_spins=[(Iron,1.),(3,-1), (7,-1)])
)
For noncollinear spin you may specify the spin direction in physical spherical
coordinates
, where
is the angle with
the z axis, and
the polar angle in the x-y plane relative to the
x-axis. The collinear case is
Radians or
Radians.
bulk_configuration.setCalculator(
calculator = LCAOCalculator(),
initial_spin = InitialSpin(scaled_spins=[(Iron, 1.0, 0.5*numpy.pi*Radians, 0.4*numpy.pi*Radians),
(3, 0.8,270*Degrees, 216*Degrees)])
)
Also see RandomSpin for an alternative way to set the initial spin.
The simplest way to obtain a spin-polarized calculation is to use
InitialSpin(), i.e. without any parameters, which means
that the initial scaled spin is set to 1.0 for all atoms.
This is usually the safest way to obtain good
convergence in spin-polarized molecular and bulk systems. In spin-polarized
two-probe systems, however, a more careful analysis is often needed in order to
obtain reliable convergence. This will be discussed below.
The initial scaled spin for each atom specifies the degree of polarization for unpaired electrons (either spin-up or spin-down) within a given valence electron shell. To understand this properly, it is best to consider a specific example.
The initial spins for the different atoms in a configuration are independent of each other,
so without loss of generality we can limit the discussion to one atom.
Let us introduce the symbol
to denote the
initial scaled spin for that atom.
For definiteness, let us look at bulk iron, which has a total of 8 valence electrons (4s23d6).
How should these electrons be distributed with respect to spin in a spin-polarized calculation? In the simplest picture, we start by filling all the available spin-up states, and when they have been filled we add the remaining electrons into spin-down states. The resulting occupations are shown in Table 24 (note that the 4s orbitals (both up and down) are filled before the 3d orbitals).
This configuration corresponds to an initial scaled spin of
(or
-1, if we reverse the roles of spin-up and spin-down). For
obvious reasons, we will refer to this configuration as the maximum
spin configuration.
Let us define some symbols for reference. Let
be the
total population of shell
(4s and 3d, for iron) in the maximum
spin configuration, where
denotes the spin. We also define
the maximum spin polarization for each shell,
which thus is 4 for 3d in the case of iron. For 4s the maximum spin polarization is zero, which means that this shell cannot be initially polarized in the calculations. A spin polarization of the 4s shell can still occur as a result of the self-consistent calculation, but it requires that the total population of the 4s shell is lower than two, and this cannot be used as an initial condition, since the total population of each shell
is fixed and constant in the process of assigning the initial populations.
Now, the initial scaled spin
determines the initial spin
occupations
of the states in shell
through the following expression:
As mentioned, the total number of valence electrons in each shell
must always be conserved, and this poses a constraint on the
initial spin configurations that can be constructed in this way. It can
easily be verified, that
gives exactly
.
Let us see what happens with iron if we set
. As mentioned
above, only the 3d shell can be polarized initially, and we find
Combined with the constraint
, we find
These populations are equally distributed among the five 3d states for each respective spin.
As a further example, had we instead specified
we would have obtained a
spin-polarized configuration with 4.5 spin-up and 1.5 spin-down electrons on
average per unit-cell in the 3d shell.
Now, the parameter initial_spin only affects the initial
spin polarization. The converged spin-polarization could very well be
different. Let us again study iron as an example.
The script below calculates and prints the converged Mulliken population of a
spin-polarized bulk bcc iron system. Since we do not know what value to use
for the initial scaled spin, we use 1.0.
bulk_configuration = BulkConfiguration(
bravais_lattice=BodyCenteredCubic(2.8665*Angstrom),
elements=[Iron],
cartesian_coordinates=[[ 0., 0., 0.]]*Angstrom
)
numerical_accuracy_parameters = NumericalAccuracyParameters(
k_point_sampling=(10, 10, 10),
)
calculator = LCAOCalculator(
exchange_correlation=LSDA.PZ,
numerical_accuracy_parameters=numerical_accuracy_parameters,
)
initial_spin = InitialSpin(scaled_spins=[1.0])
bulk_configuration.setCalculator(
calculator,
initial_spin=initial_spin,
)
mulliken_population = MullikenPopulation(bulk_configuration)
nlprint(mulliken_population)
If you run the script, it will report the following occupations:
+------------------------------------------------------------------------------+ | | | Mulliken Population Report | | | | ---------------------------------------------------------------------------- | | | | | Element Total Shell | Orbitals | | | | | | xy zy zz-rr zx xx-yy | | 0 Fe 5.108 0.704 | 0.140 0.140 0.142 0.140 0.142 | | 2.892 0.497 | 0.111 0.111 0.081 0.111 0.081 | | | s | | -0.025 | -0.025 | | -0.032 | -0.032 | | | xy zy zz-rr zx xx-yy | | 3.641 | 0.694 0.694 0.779 0.694 0.779 | | 1.530 | 0.370 0.370 0.210 0.370 0.210 | | | s | | 0.317 | 0.317 | | 0.335 | 0.335 | | | y z x | | 0.471 | 0.157 0.157 0.157 | | 0.562 | 0.187 0.187 0.187 | +------------------------------------------------------------------------------+
The number show the Mulliken population of each orbital, for each spin (for each shell, the spin-up populations are listed on the first line, spin-down on the second one).
If you kept an eye on the calculation, you would have noticed that it converged in 18 iterations. The question is now, could we have improved the convergence rate by choosing a different initial spin polarization?
The converged total Mulliken populations (on average per unit cell)
for the spin-up and spin-down states are 5.11 and 2.89, respectively.
Now these numbers also
include the 4s and some 5p electrons (since a
DoubleZetaPolarized basis set was used), but the detailed output
shows that the spin polarization of these shells is small.
Hence, as a reasonable approximation we can use
.
Thus, the converged result corresponds to a value of
.
It can therefore be expected that if we had used
this value in the calculation from the beginning, it would have converged
faster. This is indeed the case; rerunning the script with the new value of
scaled_spins=[0.56], the self-consistent iteration reaches
convergence in 10 steps, i.e. we have almost gained a factor 2 in speed!
|
|
Note |
|---|---|
|
Note how the resulting populations in the two calculations are identical; we are only setting the initial spin; the self-consistent calculation will find the proper solution anyway, provided the initial value is not too far off. In bulk systems this is, as mentioned above, not very critical, but for transport calculations it can sometimes be very hard to reach convergence unless a good initial value is provided. And, under any circumstance, with a good initial we can save a lot of calculation time. |
Finally, let us show how to determine the value that should be assigned to
in order to generate a given, initial,
spin-configuration.
Suppose we wanted to perform a spin-polarized calculation for manganese (7 valence electrons, (4s23d5)) with an initial spin occupation as the one shown in Table 25.
Table 25: Manganese in an electronic configuration with a majority of spin-down electrons.
| 4s | 3d | ||||||
|---|---|---|---|---|---|---|---|
| Spin-up |
|
|
|
||||
| Spin-down |
|
|
|
|
|||
We can see that
, as we
have one unpaired spin-down electron. The number of unpaired electrons in the
maximum spin configuration for manganese is 5 (all 3d electrons in the spin-up
state), and thus we need to set
to obtain the desired initial configuration.