This page was generated from docs/source/user_guide/calc_gulp.ipynb, with configuration: sphinx_ipypublish_all.ext.noexec

GULP Calculations

The gulp.single (for single point energy calculations) and gulp.optimize (for geometry optimisation calculations) plugins will run the General Utility Lattice Program (GULP). They are designed to create the input .gin file, from a set of AiiDA Data nodes.

Note

It is likely that these calculations will eventually be moved to a separate repository.

Initial Setup

To run a computation, first ensure AiiDA is running:

In:
!verdi status
profile:     On profile test_profile
repository:  /var/folders/dm/b2qnkb_n3r72slmpxlfmcjvm00lbnd/T/tmpg8oec6ni/test_repo
postgres:    Connected as aiida@localhost:63708
rabbitmq:    Connected to amqp://127.0.0.1?heartbeat=600
daemon:      Daemon is running as PID 50009 since 2019-08-12 12:06:45

See also

AiiDA documentation: Quick installation

If aiida-gulp is installed, the gulp.single and gulp.optimize computations should be available:

In:
!verdi plugin list aiida.calculations gulp.single
-/|\-/Inputs
           code:  required  Code                The Code to use for this job.
      potential:  required  EmpiricalPotential  parameters to create the potential section of the .gin file content.
      structure:  required  StructureData       atomic structure used to create the geometry section of .gin file content.
       metadata:  optional
     parameters:  optional  Dict                additional input parameters to create the .gin file content.
Outputs
  remote_folder:  required  RemoteData          Input files necessary to run the process will be stored in this folder node ...
        results:  required  Dict                the data extracted from the main output file
      retrieved:  required  FolderData          Files that are retrieved by the daemon will be stored in this node. By defa ...
Exit codes
              1:  The process has failed with an unspecified error.
              2:  The process failed with legacy failure mode.
             10:  The process returned an invalid output.
             11:  The process did not register a required output.
            200:  The retrieved folder data node could not be accessed.
            210:  The main output file was not found
            300:  An error was flagged trying to parse the main gulp output file
            301:  The stdout file is empty
            400:  The main gulp output file flagged an error not handled elsewhere
            410:  The main gulp output file did not signal that an expected optimisation completed
            411:  The main gulp output file did not signal that an expected optimisation completed
            412:  The main gulp output file did not signal that an expected optimisation completed
In:
!verdi plugin list aiida.calculations gulp.optimize
-/|\-/Inputs
           code:  required  Code                The Code to use for this job.
      potential:  required  EmpiricalPotential  parameters to create the potential section of the .gin file content.
      structure:  required  StructureData       atomic structure used to create the geometry section of .gin file content.
       metadata:  optional
     parameters:  optional  Dict                additional input parameters to create the .gin file content.
       symmetry:  optional  SymmetryData        parameters to create the symmetry section of the .gin file content (for con ...
Outputs
  remote_folder:  required  RemoteData          Input files necessary to run the process will be stored in this folder node ...
        results:  required  Dict                the data extracted from the main output file
      retrieved:  required  FolderData          Files that are retrieved by the daemon will be stored in this node. By defa ...
      structure:  required  StructureData       the optimized structure output from the calculation
Exit codes
              1:  The process has failed with an unspecified error.
              2:  The process failed with legacy failure mode.
             10:  The process returned an invalid output.
             11:  The process did not register a required output.
            200:  The retrieved folder data node could not be accessed.
            210:  The main output file was not found
            250:  The output cif file was not found
            251:  An input structure is required to create the output structure of an optimisation
            252:  The output cif file was not consistent with the input structure
            253:  The final structure coordinates were not parsed from the output file
            300:  An error was flagged trying to parse the main gulp output file
            301:  The stdout file is empty
            400:  The main gulp output file flagged an error not handled elsewhere
            410:  The main gulp output file did not signal that an expected optimisation completed
            411:  The main gulp output file did not signal that an expected optimisation completed
            412:  The main gulp output file did not signal that an expected optimisation completed

To use the python interface, first ensure a profile is loaded in the python kernel, and import the required modules:

In:
from aiida import load_profile
profile = load_profile()
profile.name
Out:
'test_gulp'
In:
import os
from aiida.orm import Code
from aiida.plugins import (
    DataFactory, WorkflowFactory, CalculationFactory)
from aiida.engine import run_get_node
from aiida_gulp.common import display_json
from aiida.tools.visualization import Graph
from jsonextended import edict

Input Node Creation

See also

GULP Help File

Code

See also

AiiDA documentation: Setup a code

An :py:class:aiida.orm.nodes.data.code.Code node should be set up in advance, to use the gulp calculation plugin, and call the gulp executable (or gulp_mock used here for test purposes).

In:
from aiida_gulp.tests.utils import get_or_create_local_computer, get_or_create_code
computer = get_or_create_local_computer('work_directory', 'localhost')
code_single = get_or_create_code('gulp.single', computer, 'gulp_mock')
code_opt = get_or_create_code('gulp.optimize', computer, 'gulp_mock')
code_opt.get_full_text_info()
Out:
[['PK', 2],
 ['UUID', 'ef6cbd4d-c088-4948-b0a4-5e9235ca990a'],
 ['Label', 'gulp.optimize-gulp_mock@localhost'],
 ['Description', ''],
 ['Default plugin', 'gulp.optimize'],
 ['Type', 'remote'],
 ['Remote machine', 'localhost'],
 ['Remote absolute path', '//anaconda/envs/aiida_gulp/bin/gulp_mock'],
 ['Prepend text', 'No prepend text'],
 ['Append text', 'No append text']]

Note

The calculations are tested against GULP v4.5.3

Atomic Structure

The structure refers to a standard StructureData node, and is used to create the main.gui.

Structures consist of:

  • A cell with a basis vectors and whether it is periodic, for each dimension

  • Site with a cartesian coordinate and reference to a kind

  • Kind which details the species and composition at one or more sites

The simplest way to create a structure is via ase:

In:
from ase.spacegroup import crystal
atoms = crystal(
    symbols=[12, 8],
    basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
    spacegroup=225,
    cellpar=[4.21, 4.21, 4.21, 90, 90, 90])
struct_cls = DataFactory('structure')
structure = struct_cls(ase=atoms)
structure
Out:
<StructureData: uuid: 760eaf3d-0336-49d1-b1db-5b665615c85f (unstored)>

These structures can be visualised using standard ASE methods.

In:
%matplotlib inline
import matplotlib.pyplot as plt
from ase.visualize.plot import plot_atoms
atoms = structure.get_ase()
fig, ax = plt.subplots()
plot_atoms(atoms.repeat((2,2,2)),
           ax, radii=0.8, show_unit_cell=True,
           rotation=('45x,0y,0z'));
output_24_0

Code Cell Output

As default, one kind is created per atomic species (named as the atomic symbol):

In:
structure.get_site_kindnames()
Out:
['Mg', 'Mg', 'Mg', 'Mg', 'O1', 'O1', 'O1', 'O1']

However, we may want to specify more than one kind per species (for example to setup anti-ferromagnetic spin). We can achieve this by tagging the atoms:

In:
atoms_afm = atoms.copy()
atoms_afm.set_tags([1, 1, 2, 2, 0, 0, 0, 0])
structure_afm = struct_cls(ase=atoms_afm)
structure_afm.get_site_kindnames()
Out:
['Mg1', 'Mg1', 'Mg2', 'Mg2', 'O', 'O', 'O', 'O']

Inter-Atomic Potential

Inter-atomic potentials are supplied in the form of a py:class:~aiida.orm.nodes.data.dict.Dict node with keys pair_style and data, with the form of the data dictated by the pair_style. Pair styles are created by sub-classing PotentialWriterAbstract and adding an entry point to gulp.potentials. Available pair styles and data schema can be found by:

In:
!verdi data gulp.potentials list
Registered entry points for gulp.potentials:
* lj
* reaxff

Info: Pass the entry point as an argument to display detailed information
In:
!verdi data gulp.potentials list lj -d 8
Lennard-Jones potential, of the form; E = A/r**m - B/r**n
Data Schema:
$id: potential.base.schema
$schema: http://json-schema.org/draft-07/schema
description: a schema for storing an empirical potential
properties:
  2body:
    additionalProperties: False
    description: parameters that depend on two species
    patternProperties:
      [0-9]+\-[0-9]+:
        description: mapping of '<idx1>-<idx2>' to properties
        properties:
          lj_A:
            description: fist coefficient (in ev*Angs**m)
            type: number
          lj_B:
            description: second coefficient (in ev*Angs**m)
            type: number
          lj_m:
            default: 12
            description: first exponent
            exclusiveMinimum: 0
            type:    integer
          lj_n:
            default: 6
            description: second exponent
            exclusiveMinimum: 0
            type:    integer
          lj_rmax:
            description: maximum radius cut-off (Angs)
            exclusiveMinimum: 0
            type:    number
          lj_rmin:
            default: 0
            description: minimum radius cut-off (Angs)
            minimum: 0
            type: number
        required: [lj_A, lj_B, lj_rmax]
        type: object
    type:        object
  description:
    type: string
  species:
    description: the list of species
    items:
      pattern: ^[a-zA-Z]+ (core|shell)$
      type: string
    type: array
    uniqueItems: True
required: [species, 2body]
type: object
In:
from aiida.plugins import load_entry_point
writer = load_entry_point('gulp.potentials', 'lj')()
data = {
    "species": ["H core", "He core"],
    "2body": {
        "0-1": {
            "lj_A": 1.0,
            "lj_B": 2.0,
            "lj_rmax": 12.0
        }
    }
}
content = writer.create_content(data)
print("Number of fitted parameters:", content.number_of_flags)
print(content.content)
Number of fitted parameters: 2
lennard 12 6
H core  He core 1.00000000E+00 2.00000000E+00 12.00000

ReaxFF data can be created from the standard LAMMPS style potential file, using

In:
from aiida_gulp.tests import read_resource_text
from aiida_gulp.potentials.raw_reaxff import read_lammps_format
from aiida_gulp.potentials.common import filter_by_species

data = read_lammps_format(read_resource_text('gulp', 'potentials', 'FeCrOSCH.reaxff').splitlines())
data = filter_by_species(data, ["Fe core", "S core"])

edict.pprint(data, depth=2, keycolor='blue')
1body:
  0: {...}
  1: {...}
2body:
  0-0: {...}
  0-1: {...}
  1-1: {...}
3body:
  0-0-1: {...}
  0-1-0: {...}
  0-1-1: {...}
  1-0-1: {...}
  1-1-1: {...}
4body:
  1-1-1-1: {...}
description: Reactive MD-force field: Cr/O/Fe/S/C/H force field 2014
global:
  C2-correction:           60.485
  Lower Taper-radius:      0.0
  Not used 2:              6.1431
  Not used 3:              -2.4837
  Not used 4:              -1.2327
  Not used 5:              0.5
  Not used 6:              20.0
  Not used 7:              5.0
  Not used 8:              0.0
  Triple bond stabilisation: 4.6
  Triple bond stabilisation 1: 1.7224
  Triple bond stabilisation 2: 6.8702
  Triple bond stabilization energy: -70.5044
  Upper Taper-radius:      10.0
  bond order cutoff:       0.1
  reaxff0_boc1:            50.0
  reaxff0_boc2:            9.5469
  reaxff0_cot2:            2.1645
  reaxff0_lp1:             6.0891
  reaxff0_ovun3:           50.0
  reaxff0_ovun4:           0.6991
  reaxff0_ovun6:           1.0588
  reaxff0_ovun7:           12.1176
  reaxff0_ovun8:           13.3056
  reaxff0_pen2:            6.929
  reaxff0_pen3:            0.3989
  reaxff0_pen4:            3.9954
  reaxff0_tor2:            5.7796
  reaxff0_tor3:            10.0
  reaxff0_tor4:            1.9487
  reaxff0_val7:            33.8667
  reaxff0_val8:            1.8512
  reaxff0_val9:            1.0563
  reaxff0_val10:           2.0384
  reaxff0_vdw1:            1.5591
  reaxff2_pen2:            2.8793
  reaxff2_pen3:            1.0
  reaxff3_coa2:            26.5405
  reaxff3_coa3:            2.6962
  reaxff3_coa4:            2.1365
species: [Fe core, S core]

Setting Up and Running the Calculations

See also

AiiDA documentation: Application

In:
from aiida_gulp.symmetry import convert_structure
structure_data = {
    "lattice": [[5.38, 0.000000, 0.000000],
                [0.000000, 5.38, 0.000000],
                [0.000000, 0.000000, 5.38]],
    "fcoords": [[0.0, 0.0, 0.0], [0.5, 0.0, 0.5], [0.0, 0.5, 0.5],
                [0.5, 0.5, 0.0], [0.338, 0.338, 0.338],
                [0.662, 0.662, 0.662], [0.162, 0.662, 0.838],
                [0.838, 0.338, 0.162], [0.662, 0.838, 0.162],
                [0.338, 0.162, 0.838], [0.838, 0.162, 0.662],
                [0.162, 0.838, 0.338]],
    "symbols": ['Fe'] * 4 + ['S'] * 8,
    "pbc": [True, True, True]
}
structure = convert_structure(structure_data, "aiida")
structure
Out:
<StructureData: uuid: c1bfe430-3fed-4a13-90e9-50595cfb0230 (unstored)>
In:
potential_data = {
    "species": ["Fe core", "S core"],
    "2body": {
        "0-0": {
            "lj_A": 1.0,
            "lj_B": 1.0,
            "lj_rmax": 12.0
        },
        "0-1": {
            "lj_A": 1.0,
            "lj_B": 1.0,
            "lj_rmax": 12.0
        },
        "1-1": {
            "lj_A": 1.0,
            "lj_B": 1.0,
            "lj_rmax": 12.0
        }
    }
}
potential_lj = DataFactory('gulp.potential')(
    pair_style="lj", potential_data=potential_data)
potential_lj.attributes
Out:
{'pair_style': 'lj',
 'description': 'Lennard-Jones potential, of the form; E = A/r**m - B/r**n',
 'species': ['Fe core', 'S core'],
 'input_lines_md5': '35449283e18a3393ba70f925a16ba6a5',
 'fitting_flags': False,
 'total_flags': 6,
 'number_flagged': 0,
 'potential_filename': 'potential.pot',
 'potential_json': 'potential.json',
 'fitting_json': 'fitting.json'}

gulp.single

In:
code_single = Code.objects.get(
    label="gulp.single-gulp_mock@localhost")
builder = code_single.get_builder()
builder.metadata.options = {
    "resources": {
        "num_machines": 1,
        "num_mpiprocs_per_machine": 1}}
builder.structure = structure
builder.potential = potential_lj
In:
result, calcnode = run_get_node(builder)
calcnode
Out:
<CalcJobNode: uuid: dd55a58a-f4cc-4596-8db8-f5e2404046d0 (pk: 5) (aiida.calculations:gulp.single)>
In:
print(calcnode.is_finished_ok)
print(calcnode.process_state)
print(calcnode.exit_status)
True
ProcessState.FINISHED
0
In:
graph = Graph(graph_attr={'size': "6,8!", "rankdir": "LR"})
graph.add_node(calcnode)
graph.add_incoming(calcnode, annotate_links="both")
graph.add_outgoing(calcnode, annotate_links="both")
graph.graphviz
Out:
output_44_0

gulp.single calculation provenance graph.

gulp.optimize

In:
opt_dict={
    "minimize": {"style": "cg", "max_iterations": 100},
    "relax": {"type": "conp"}}
opt_params = DataFactory('dict')(dict=opt_dict)
opt_params
Out:
<Dict: uuid: 72dad977-2bbb-462c-89f2-dfe3ef075aa8 (unstored)>
In:
code_opt = Code.objects.get(
    label="gulp.optimize-gulp_mock@localhost")
builder_opt = code_opt.get_builder()
builder_opt.metadata.options = {
    "resources": {
        "num_machines": 1,
        "num_mpiprocs_per_machine": 1}}
builder_opt.structure = structure
builder_opt.potential = potential_lj
builder_opt.parameters = opt_params
In:
result, calcnode_opt = run_get_node(builder_opt)
calcnode_opt
Out:
<CalcJobNode: uuid: 1d2c3a42-f732-494d-8e01-1f4ed9b59bfb (pk: 10) (aiida.calculations:gulp.optimize)>
In:
print(calcnode_opt.is_finished_ok)
print(calcnode_opt.process_state)
print(calcnode_opt.exit_status)
True
ProcessState.FINISHED
0
In:
graph = Graph(graph_attr={'size': "6,8!", "rankdir": "LR"})
graph.add_node(calcnode_opt)
graph.add_incoming(calcnode_opt, annotate_links="both")
graph.add_outgoing(calcnode_opt, annotate_links="both")
graph.graphviz
Out:
output_50_0

gulp.optimize calculation provenance graph.

In:
display_json(calcnode_opt.outputs.results.attributes)
{
  "errors": [],
  "opt_type": "bulk",
  "warnings": [],
  "energy_units": "eV",
  "final_energy": -17.47113113,
  "gulp_version": "4.5.3",
  "parser_class": "GulpOptParser",
  "opt_succeeded": true,
  "parser_errors": [],
  "initial_energy": -0.32809466,
  "parser_version": "0.10.0b5",
  "opt_time_second": 0.3676,
  "parser_warnings": [],
  "total_time_second": 0.3677,
  "final_primitive_energy": -17.47113113,
  "peak_dynamic_memory_mb": 0.54,
  "initial_primitive_energy": -0.32809466
}