ParallelEnergyAndForces(configurations, processes_per_configuration, filenames=None, master_only=True)

Evaluates the energy and forces for a list of configurations in parallel.

  • configurations (list of configurations (MoleculeConfiguration | BulkConfiguration | SurfaceConfiguration | DeviceConfiguration)) – A list of configurations with attached calculators.
  • processes_per_configuration (int) – The number of MPI processes to use for calculating the energy and forces on each configuration.
  • log_filenames (list of strings) – A list of filenames to log each calculation to. It must be the same length as the configurations argument. If None is given, then logging will be performed to stdout.
    Default: All calculations are logged to stdout
  • master_only (bool) – Controls if the master process should be the only rank allowed to write to the log.
    Default: True

A tuple of energies and forces as PhysicalQuantity arrays.

Return type:


Usage Examples

Calculate the potential energy curve and forces for a hydrogen molecule in parallel. At the end of the script, a table of internuclear distances, energies, and the force is printed to the screen.

# Make a list to hold the configurations.
configurations = []

# Loop over a list of distances between 0.3 and 5.0 Angstrom.
distances = numpy.linspace(0.3, 5.0, 20)
for distance in distances:
    # Define elements
    elements = [Hydrogen, Hydrogen]

    # Define coordinates
    cartesian_coordinates = [[ 0.0, 0.0, 0.0 ],
                             [ distance, 0.0, 0.0 ]]*Angstrom

    # Set up configuration
    molecule_configuration = MoleculeConfiguration(

    # Define a calculator

    # Add the configuration to the list of configurations.

def task_function(configuration, index):
    # Compute the total energy.
    total_energy = TotalEnergy(configuration)
    # Save the result to a file.
    nlsave('total_energy_%i.hdf5'%index, configuration)
    # Return the calculated total energy.
    return total_energy.evaluate()

# Define a list of filenames to save the logging output from each calculation to.
filenames = [ 'total_energy_%i.log' % i for i in range(len(configurations)) ]

# Calculate the energy of each configuration. Each calculation will use 2 MPI processes.
energies = ParallelMapConfigurations(

# Only print on the master process. This prevents the table from being printed multiple times.
if processIsMaster():
    print('%10s %12s' % ('distance', 'energy'))
    for i in range(len(configurations)):
        print('%10.4f %12.3e' % (distances[i], energies[i].inUnitsOf(eV)))


It is important to properly coordinate the total number of MPI processes, the processes_per_configuration argument, and the number of configurations. When ParallelEnergyAndForces is called, the MPI processes are divided up into NLEngine.numberOfProcesses()/processes_per_configuration sized groups. For example, if there are 8 MPI processes and processes_per_configuration=2, then 4 groups will be made. However, if there are only 2 configurations in the configurations list then 2 of those groups will be idle.

Ideally, one would pick processes_per_configuration to be the largest number of processes that a single DFT calculation runs efficiently on. This generally depends on a number of variables including the number of atoms, basis set size, computer hardware, etc. Then, the total number of MPI processes should be an integer multiple of processes_per_configuration.

This function can be used with ATK-ForceFiled calculators as well. However, ATK-ForceField does not currently make use of MPI. This means that processes_per_configuration should always be set to 1 in order not to have idle processes.

See also, Notes.