Skip to content

Setting up a Single Point Calculation

As mentioned on the welcome page, FHI-aims and AiiDA interact through the aiida-ase plugin. This has the advantage that existing Python scripts, which already exploit the benefits of using FHI-aims with ASE, can easily be extended for interoperability with AiiDA.

This tutorials assumes a basic understanding of how to interact with AiiDA. Make sure to check out the official AiiDA documentation which features many examples on setting up first calculations in AiiDA, tracking their provenance, and inspecting the results.

That being said, let us take a look at a simple python script which performs a single point calculation for silicon under periodic boundary conditions. All AiiDA calculations follow a similar scheme:

  1. Load the relevant AiiDA and ASE modules: As is customary in Python, all required modules are imported at the beginning of the script.

    from aiida.orm import load_code
    from aiida.plugins import DataFactory, CalculationFactory
    from aiida.engine import submit
    
    # We will create the structure from scratch using ASE's build features.
    from ase.build import bulk
    
  2. Instantiate AiiDA classes: Aiida provides convenient classes to store different types of data in its repository or database infrastructure. For example, the Dict data class wraps Python dictionaries and is typically used to store calculation parameters. Moreover, AiiDA comes with specialized data types to store chemical structure information (structure) and kpoints (array.kpoints). The DataFactory method is used here to instantiate the classes.

    Dict = DataFactory('dict')
    StructureData = DataFactory('structure')
    KpointsData = DataFactory('array.kpoints')
    

    Similarily, the CalculationFactory method makes it easy to load a calculation plugin:

    AseCalculation = CalculationFactory('ase.ase')
    
  3. Define the structure: In this case, we are using the bulk module provided by ASE to generate a simple bulk silicon unit cell with periodic boundary conditions.

    atoms = bulk('Si')
    
  4. Set calculation parameters. Just like the ASE interface to FHI-aims, aiida-ase understands all FHI-aims keywords which are documented in the manual. In AiiDA, these parameters are usually summarized in a nested dictionary. Here, we are loading the aims.Aims calculator (which is how the FHI-aims calculator module in ASE is internally called) and providing it with several arguments. Most importantly, one has to specify the name of the compiled FHI-aims executable (as it stands in the $PATH), the desired name of the output file, the path to the species directory, and the exchange-correlation functional. Furthermore, we are here setting custom values for the convergence criteria.

    parameters = {
       'calculator': {
           'name': 'aims.Aims',
           'args': {
               'aims_command': 'AIMS_EXECUTABLE',
               'outfilename': 'aims.out',
               'species_dir': 'PATH/TO/SPECIES/DIRECTORY',
               'xc': 'PBE',
               'sc_accuracy_etot': 1e-4,
               'sc_accuracy_eev': 1e-2,
               'sc_accuracy_rho': 1e-5,
               'sc_accuracy_forces': 1e-4
           }
       }
    }
    

    Apart from that, we are declaring an instance of the AiiDA KPointsData class and constructing a 2x2x2 uniformily spaced kpoint grid in the Brillouin zone.

    kpoints = KpointsData()
    kpoints.set_kpoints_mesh([2, 2, 2])
    
  5. Set calculation metadata: Metadata in AiiDA has two major jobs: First, it allows the user to give a label and description to every calculation, ensuring it may easily be retrieved from the database in the future. Second, metadata is also used to inform the scheduling system on the worker machine about the desired resources for this job. In our case, we are requesting a single MPI process without distribution, and setting a (way too large) wallclock time.

    metadata = {
       'label': 'Si with FHIAims',
       'description': 'Test calculation of FHI-aims using `aiida-ase`.',
       'options': {
           'resources': {
               'num_machines': 1,
               'num_mpiprocs_per_machine': 1
           },
           'max_wallclock_seconds': 30 * 60,  # 30 minutes                    
       }
    }
    
  6. Putting the pieces together: All calculation details have to be combined into one calculation object. This can either be achieved by constructing a large dictionary containing all the information, or by using the AiiDA builder object which will create such a dictionary automatically.

    codes = load_code('ASECODELABEL@COMPUTER')
    builder = codes.get_builder()
    builder.structure = StructureData(ase=atoms)
    builder.kpoints = kpoints
    builder.parameters = Dict(dict=parameters)
    builder.metadata = metadata
    
  7. Submit the calculation to the AiiDA queue.

    submit(builder)
    

After the calculation has been submitted, the AiiDA daemon will take care of sending it to a possible remote server, checking the calculation status, retrieving the desired results and handling errors, if any occurred.

Below you can find a complete version of the submission script.

"""FHI-aims-driven SPC on bulk silicon using AiiDA."""

from aiida.engine import submit
from aiida.orm import load_code
from aiida.plugins import DataFactory, CalculationFactory

# ASE imports for structure building.                   
from ase.build import bulk

# Load AiiDA factory classes. 
Dict = DataFactory('dict')
StructureData = DataFactory('structure')
KpointsData = DataFactory('array.kpoints')
AseCalculation = CalculationFactory('ase.ase')

# Change the following value to the ASE code configured under the name 
# ASECODELABEL on machine COMPUTERLABEL.
code = 'ASECODELABEL@COMPUTERLABEL'

# Set calculation details.
parameters = {
    'calculator': {
        'name': 'aims.Aims',
        'args': {
            'aims_command': 'AIMS_EXECUTABLE',
            'outfilename': 'aims.out',
            'species_dir': 'PATH/TO/SPECIES/DIRECTORY',
            'xc': 'PBE',
            'sc_accuracy_etot': 1e-4,
            'sc_accuracy_eev': 1e-2,
            'sc_accuracy_rho': 1e-4,
            'sc_accuracy_forces': 1e-3
        }
    }
}

# Set AiiDA storage metadata.
metadata = {
    'label': 'Si with FHIAims',
    'description': 'Test calculation of FHI-aims using `aiida-ase`.',
    'options': {
        'resources': {
            'num_machines': 1,
            'num_mpiprocs_per_machine': 1
        },
        'max_wallclock_seconds': 30 * 60,  # 30 minutes                    
    }
}

# Arrange 2x2x2 k-point grid.
kpoints = KpointsData()
kpoints.set_kpoints_mesh([2, 2, 2])

# Use the `builder` object to string together all calculation details.
codes = load_code(code)
builder = codes.get_builder()
builder.structure = StructureData(ase=bulk('Si'))
builder.kpoints = kpoints
builder.parameters = Dict(dict=parameters)
builder.metadata = metadata

# Submit the calculation to the AiiDA queue.
submit(builder)