from aiida import load_profile
load_profile()
# we also load some classes from the AiiDA package
from aiida.orm import StructureData, Dict, ArrayData, Code, load_node
# numpy for arrays
import numpy as np
# matplotlib for plotting
from matplotlib import pyplot as plt
# initialize the structure with the Bravais matrix (unit are in Angstroem!)
structure = StructureData(cell=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
# add an atom (cartesian coordinates in Angstroem units)
# we need to put a symbol, although this is not needed used by the AiiDA-Spirit plugin
structure.append_atom(position = [0., 0., 0.], symbols='Fe')
# prepare list of the couplings (usually this is done when parsing an output of an ab initio calculation)
jijs = np.array([
# i, j, da, db, dc, Jij [, Dijx, Dijy, Dijz]
[0, 0, 1, 0, 0, 1.0, 0.0, 0.0, 0.0],
[0, 0, 0, 1, 0, 1.0, 0.0, 0.0, 0.0],
[0, 0, 0, 0, 1, 1.0, 0.0, 0.0, 0.0],
])
# to work with the couplings this needs to be an AiiDA datatype
# so far the AiiDA-Spirit plugin expects and array of the name 'Jij_expanded'
jij_data = ArrayData()
jij_data.set_array('Jij_expanded', jijs)
This can be used to control the spirit run (external field, number of unit cells in spirit simulation, perdiodic boundary conditions, ...).
Most parameters from the spirit documentation can be set except for some parameters that are automatically set.
# parameters that go into the spirit configuration file
input_para = {
### Hamiltonian
# impurity spin moments in mu_Bohr
'mu_s': [2.2], # list of spin moments, needed to apply an external field
# Spirit supercell
'n_basis_cells': [10, 10, 10],
# external magnetic field in T (point in +z direction)
'external_field_magnitude': 0.0,
'external_field_normal': [0.0, 0.0, 1.0],
# single-ion anisotropy in meV
'anisotropy_magnitude': 0.,
'anisotropy_normal': [0.0, 0.0, 1.0],
### LLG settings
'llg_n_iterations': 50000,
'llg_n_iterations_log': 1000,
'llg_temperature': 4, # temperature noise (K)
'llg_dt': 1.0E-3, # LLG time step (ps)
'llg_force_convergence': 1e-7,
}
parameters = Dict(dict=input_para)
# run modes of spirit that go into the run_spirit.py script
run_opts = Dict(
dict={
'simulation_method': 'mc',
'mc_configuration' : {'n_thermalisation' : 5000, 'n_decorrelation' : 2,
'n_samples' : 25000, 'n_temperatures' : 40,
'T_start' : 25, 'T_end' : 5 },
'solver': 'vp',
'configuration': {'plus_z': True},
})
#set up a spirit calculations
from aiida.engine import submit
from aiida.plugins import CalculationFactory
builder = CalculationFactory('spirit').get_builder()
builder.structure = structure
builder.jij_data = jij_data
builder.parameters = parameters
builder.run_options = run_opts
# code and computer options (queue name etc.)
builder.code = Code.get_from_string('spirit@iffslurm')
builder.metadata.options = {
'withmpi': False, # Spirit does not have MPI
'resources': {'num_machines': 1, 'tot_num_mpiprocs': 1},
'queue_name': 'th1-2020-64', # use AMD partition
'max_wallclock_seconds': 3600*10 # 10 h max runtime
}
builder.metadata.label = 'spirit-mc'
# spirit_calc10 = submit(builder)
spirit_calc10 = load_node('d907d3b8-1528-405a-bd99-ead151032b73')
input_para20 = input_para.copy()
input_para20['n_basis_cells'] = [20, 20, 20]
parameters20 = Dict(dict=input_para20)
builder.parameters = parameters20
builder.metadata.label = 'spirit-mc-20'
# spirit_calc20 = submit(builder)
spirit_calc20 = load_node('f8e440c3-14f0-4148-b552-524881e9ad42')
input_para30 = input_para.copy()
input_para30['n_basis_cells'] = [30, 30, 30]
parameters30 = Dict(dict=input_para30)
builder.parameters = parameters30
builder.metadata.label = 'spirit-mc-30'
builder.metadata.options = {
'withmpi': False, # Spirit does not have MPI
'resources': {'num_machines': 1, 'tot_num_mpiprocs': 1},
'queue_name': 'th1-2020-64', # use AMD partition
'max_wallclock_seconds': 3600*20 # 10 h max runtime
}
# spirit_calc30 = submit(builder)
# spirit_calc30 = load_node('50f41c70-b52e-4e96-911c-3943c00ef79c')
spirit_calc30 = load_node('f93eaeda-b585-4cff-9adf-eaa359e72892')
input_para40 = input_para.copy()
input_para40['n_basis_cells'] = [40, 40, 40]
parameters40 = Dict(dict=input_para40)
builder.parameters = parameters40
builder.metadata.label = 'spirit-mc-40'
builder.metadata.options = {
'withmpi': False, # Spirit does not have MPI
'resources': {'num_machines': 1, 'tot_num_mpiprocs': 1},
'queue_name': 'th1-2020-64', # use AMD partition
'max_wallclock_seconds': 3600*40 # 10 h max runtime
}
# spirit_calc40 = submit(builder)
# spirit_calc40 = load_node('577cd4d1-ce8a-4482-a24b-87f9af00b41c')
spirit_calc40 = load_node('ea2511f1-c400-41b9-aee4-1d1d088bebc9')
plt.figure(figsize=(6,4))
names = '($10^3$) ($20^3$) ($30^3$) ($40^3$)'.split()
for i, spirit_calc in enumerate([spirit_calc10, spirit_calc20]):
mc_data = spirit_calc.outputs.monte_carlo
t = mc_data.get_array("temperature")
m = mc_data.get_array("magnetization")
plt.plot(t, (m-m.min())/(m.max()-m.min()), label="$M$ "+names[i], lw=3)
for i, spirit_calc in enumerate([spirit_calc10, spirit_calc20]):
mc_data = spirit_calc.outputs.monte_carlo
t = mc_data.get_array("temperature")
chi = mc_data.get_array("susceptibility")
plt.plot(t, (chi-chi.min())/(chi.max()-chi.min()), label="$\chi$", lw=3, color=f'C{i}', ls='--')
for i, spirit_calc in enumerate([spirit_calc30, spirit_calc40]):
mc_data = spirit_calc.outputs.monte_carlo
t = mc_data.get_array("temperature")
m = mc_data.get_array("magnetization")
plt.plot(t, (m-m.min())/(m.max()-m.min()), label="$M$ "+names[i+2], lw=3)
for i, spirit_calc in enumerate([spirit_calc30, spirit_calc40]):
mc_data = spirit_calc.outputs.monte_carlo
t = mc_data.get_array("temperature")
chi = mc_data.get_array("susceptibility")
plt.plot(t, (chi-chi.min())/(chi.max()-chi.min()), label="$\chi$", lw=3, color=f'C{i+2}', ls='--')
Tc_expected = 16.71 # K
plt.axvline(Tc_expected, ls=':', color='grey', lw=2)
plt.ylabel("normalized value", fontsize='large')
plt.xlabel("Temperature (K)", fontsize='large')
plt.legend(fontsize='large', ncol=4, loc=9)
plt.xlim(5,25)
plt.ylim(0, 1.45)
plt.show()