please execute the cell below before starting the tutorial by selecting the cell and pressing Ctrl+Enter

%load_ext autoreload
%autoreload 2
from aiida import load_profile

from aiida.orm import Dict, load_node, load_code
from aiida.engine import submit
from IPython.display import IFrame
from pprint import pprint
from import plot_fleur
from aiida_fleur.workflows.base_relax import FleurBaseRelaxWorkChain
from aiida_fleur.workflows.eos import FleurEosWorkChain
from aiida_fleur.workflows.mae import FleurMaeWorkChain
from aiida_fleur.workflows.ssdisp import FleurSSDispWorkChain
from aiida_fleur.workflows.create_magnetic_film import FleurCreateMagneticWorkChain
from aiida_fleur.workflows.corehole import fleur_corehole_wc
from aiida_fleur.workflows.initial_cls import fleur_initial_cls_wc
# First we will import a prepared dataset for this tutorial with some structures and simulations
# If this was already executed, it will add nothing to the database
!verdi archive import ~/Day3/files/fleur_tutorial_data.aiida

Higher-level workchains

Disclaimer: This tutorial includes multiple higher level workchains, which will launch multiple fleur jobs, be careful not to run multiple of the higher workchains and not with expensive inputs (large cutoffs etc.) at once to not overload the docker container

Now - finally - we will see the real power of the workchains. We are going to launch a relaxation workchain relaxing a the atoms in a given crystal structure. An equation of state workchain calculating the bulk modulus. And in the end we are going to use two higher-level workchains for Magnetic Anisotropy Energy (MAE) and Spin Spiral Dispersion (SSDisp) calculations. There are two types of MAE and SSDisp workchains: force-theorem and convergence workchains. In this tutorial we will use force-theorem workchains only that first submits a single SCF workchain to obtain the reference charge density and later submits a single FleurCalculation task to run the force theorem step.

fleur_code = load_code('fleur@localhost')
inpgen_code = load_code('inpgen@localhost')
options = Dict(dict={'resources' : {"num_machines": 1, "num_mpiprocs_per_machine" : 2},
                     'queue_name' : '',
                     'withmpi' : True,
                     'max_wallclock_seconds' : 600})

The Relax workchain

The FleurRelaxWorkChain relaxes the atomic positions of a crystal structure. It is called by the FleurBaseRelaxWorkChain, which handles some errors of the FleurRelaxWorkChain. Therefore, you usually want to run the FleurBaseRelaxWorkChain. For more information see the Documentation on the relaxation workchains

structure = load_node(Struc_PK)
inputs = {'scf': {
                  #'wf_parameters': wf_para_scf,   # use defaults
                  #'calc_parameters': parameters,  # use fleur defaults
                  'options': options,
                  'inpgen': inpgen_code,
                  'fleur': fleur_code,
                  'structure': structure
          #'final_scf': {                          # We do not run one
                        #'calc_parameters': parameters,
          #'wf_parameters': wf_para,               # use defaults
Relax_workchain = submit(FleurBaseRelaxWorkChain, **inputs)
print('Submitted Relax workchain pk={}'.format(

Check on the workchain, and if it is finished you can continue

relax = load_node(
# To view the provenance graph of the workchain
!verdi node graph generate $
IFrame('./' + str( + '.dot.pdf', width=800, height=500)

Equation of states WorkChain

The FleurEosWorkChain calculation an equation of state by scaling the cell and running an SCF workchain on all scalings, while keeping the flapw parameters the same. In the end it performs a Birch–Murnaghan equation of state fit, and returns the results which contains among other quantities the bulk modulus. So far this is only correct for cubic systems, which are relaxed. Also see the documentation on the EOS workchain

The 'right' way to do this would be to run a full constant volume cell and atoms relaxation for each scaled volume.

structure = load_node(Struc_PK)
inputs = {'scf': {
                  #'wf_parameters': wf_para_scf,   # use defaults
                  #'calc_parameters': parameters,  # fleur defaults of lowest scaling
                  'options': options,
                  'inpgen': inpgen_code,
                  'fleur': fleur_code
          #'wf_parameters': wf_para,               # default is 9 points
          'structure': structure
EOS_workchain = submit(FleurEosWorkChain, **inputs)
print('Submitted EOS workchain pk={}'.format(

Check on the workchain, and if it is finished you can continue

eos = load_node(
a = plot_fleur(

If the above does not look well, it means it is not converged, and you should better rerun with more kpoints and maybe specifing FLAPW parameters (calc_parameters) yourself instead of relying on the fleur defaults.

# To view the provenance graph of the workchain
!verdi node graph generate $
IFrame('./' + str( + '.dot.pdf', width=800, height=500)

Magnetic anisotropy workchain

A table of possible inputs looks the same as for SCF:

name type description required
fleur Code Fleur code yes
inpgen Code Inpgen code no
wf_parameters Dict Settings of the workchain no
structure StructureData Structure data node no
calc_parameters Dict FLAPW parameters, used by inpgen no
fleurinp FleurinpData FLEUR input files no
remote_data RemoteData Remote folder to find cdn1 no
options Dict AiiDA options (computational resources) no

Again, there are a lot of optional inputs - however you must follow one of the supported input configurations. They are similar to the SCF workchain and I will not cover all of them here, let us just use the fleur + inpgen + structure mode. Let us also specify workchain parameters and computational resources.

wf_para = Dict(dict={'sqa_ref': [0.7, 0.7],                    # theta and phi for reference calculation
                     'use_soc_ref': False,                     # True if switch on SOC terms for reference
                     'sqas_theta': [0.0, 1.57079, 1.57079],    # a list of theta values to calculate via the FT
                     'sqas_phi': [0.0, 0.0, 1.57079],          # a list of phi values to calculate via the FT
                     'inpxml_changes': []                      # a list of inpxml changes to be done before submission

wf_para_scf = Dict(dict={'fleur_runmax': 10,                       # passed to SCF workchain
                     'density_converged': 0.02,                # passed to SCF workchain
                     'serial': False,                          # passed to SCF workchain
                     'itmax_per_run': 30,                       # passed to SCF workchain)
calc_parameters = Dict(dict={
    'kpt': {
        'div1': 4,
        'div2' : 4,
        'div3' : 1

In this section we want to be even more productive - let us define not a single structure but three of them! Import Fe, Co and Ni film structures that we created in tutorial 4:

fe_structure = load_node(xxx)
co_structure = load_node(xxx)
ni_structure = load_node(xxx)

input_structures = [fe_structure, co_structure, ni_structure]

And calculate magnetic anisotropy energy for all of them:

for structure in input_structures:
    MAE_workchain = submit(FleurMaeWorkChain,
                           scf={'fleur': fleur_code,
                                'inpgen': inpgen_code,
                                'calc_parameters': calc_parameters,
                                'structure': structure,
                                'wf_parameters': wf_para_scf},
    print('Submitted Mae workchain pk={} for {} structure'.format(, structure.get_formula()))

Again, you can check if it is finished via:

# you need to modify this - replace MAE_PK
!verdi process status MAE_PK
# or
#!verdi process list -a -p 1

Using you experience, can you access the output dictionaries and extract values of MAEs for all the structures?

Now let us proceed to the final task - Spin spiral dispersion workchain.

Scripting tasks

Spin-spiral dispersion workchain

Spin spiral dispersion workchain has the same input nodes as MAE workchain. wf_para dictionary contains a different set of control keys:

wf_para = Dict(dict={'beta' : {'all' : 1.57079},            # sets beta angle for all atoms
                     'q_vectors': [[0.0, 0.0, 0.0],         # set q-vectors to calculate
                                   [0.125, 0.125, 0.0],     
                                   [0.250, 0.250, 0.0],     
                                   [0.375, 0.375, 0.0],     
                                   [0.500, 0.500, 0.0]],     
                     'ref_qss' : [0.0, 0.0, 0.0],            # sets a q-vector of the reference calc
                     'inpxml_changes': []

wf_para_scf = Dict(dict={'fleur_runmax' : 3,                    # passed to SCF workchain
                         'itmax_per_run' : 30,                  # passed to SCF workchain
                         'density_converged' : 0.002,           # passed to SCF workchain
                         'serial' : False,                      # passed to SCF workchain)

To import SSDisp workchain, run:

    from aiida_fleur.workflows.ssdisp import FleurSSDispWorkChain

This time we will cover another input configuration: fleur + fleurinp. We will use FleurinpData objects generated in section 4.

In the final task, load three FleurinpData objects and run a FleurSSDispWorkChain for each of them. Use wf_para and wf_para_scf given above in the same way as in the FleurMAEWorkchain. Do you need to pass calc_parameters this time?

Explore the outputs, extract spin spiral dispersion. Plot energy of a spin spiral as a function of a q-vector.