Tools¶
Mapping structures¶

icet.tools.
map_structure_to_reference
(relaxed, reference, inert_species=None, tol_positions=0.0001, suppress_warnings=False, assume_no_cell_relaxation=False)[source]¶ Maps a relaxed structure onto a reference structure. The function returns a tuple comprising the ideal supercell most closely matching the relaxed structure and a dictionary with supplementary information concerning the mapping. The latter includes for example the largest deviation of any position in the relaxed structure from its reference position (drmax), the average deviation of the positions in the relaxed structure from the reference positions (dravg), and the strain tensor for the relaxed structure relative to the reference structure (strain_tensor).
The Atoms object that provide further supplemental information via custom peratom arrays including the atomic displacements (Displacement, Displacement_Magnitude) as well as the distances to the three closest sites (Minimum_Distances).
 Parameters
relaxed (
Atoms
) – relaxed input structurereference (
Atoms
) – reference structure, which can but need not be the primitive structureinert_species (
Optional
[List
[str
]]) – list of chemical symbols (e.g.,['Au', 'Pd']
) that are never substituted for a vacancy; the number of inert sites is used to rescale the volume of the relaxed structure to match the reference structure.tol_positions (
float
) – tolerance factor applied when scanning for overlapping positions in Angstrom (forwarded toase.build.make_supercell()
)suppress_warnings (
bool
) – if True, print no warnings of large strain or relaxation distancesassume_no_cell_relaxation (
bool
) –if False volume and cell metric of the relaxed structure are rescaled to match the reference structure; this can be unnecessary (and counterproductive) for some structures, e.g., with many vacancies
Note: When setting this parameter to False the reference cell metric must be obtainable via an integer transformation matrix from the reference cell metric. In other words the relaxed structure should not involve relaxations of the volume or the cell metric.
Example
The following code snippet illustrates the general usage. It first creates a primitive FCC cell, which is latter used as reference structure. To emulate a relaxed structure obtained from, e.g., a density functional theory calculation, the code then creates a 4x4x4 conventional FCC supercell, which is populated with two different atom types, has distorted cell vectors, and random displacements to the atoms. Finally, the present function is used to map the structure back the ideal lattice:
>>> from ase.build import bulk >>> reference = bulk('Au', a=4.09) >>> structure = bulk('Au', cubic=True, a=4.09).repeat(4) >>> structure.set_chemical_symbols(10 * ['Ag'] + (len(structure)  10) * ['Au']) >>> structure.set_cell(structure.cell * 1.02, scale_atoms=True) >>> structure.rattle(0.1) >>> mapped_structure, info = map_structure_to_reference(structure, reference)
 Return type
Tuple
[Atoms
,dict
]
Structure enumeration¶

icet.tools.
enumerate_structures
(structure, sizes, chemical_symbols, concentration_restrictions=None, niggli_reduce=None, symprec=1e05, position_tolerance=None)[source]¶ Yields a sequence of enumerated structures. The function generates all inequivalent structures that are permissible given a certain lattice. Using the
chemical_symbols
andconcentration_restrictions
keyword arguments it is possible to specify which chemical_symbols are to be included on which site and in which concentration range.The function is sensitive to the boundary conditions of the input structure. An enumeration of, for example, a surface can thus be performed by setting
structure.pbc = [True, True, False]
.The algorithm implemented here was developed by Gus L. W. Hart and Rodney W. Forcade in Phys. Rev. B 77, 224115 (2008) [HarFor08] and Phys. Rev. B 80, 014120 (2009) [HarFor09].
 Parameters
structure (
Atoms
) – primitive structure from which derivative superstructures should be generatedsizes (
List
[int
]) – number of sites (included in enumeration)chemical_symbols (
list
) – chemical species with which to decorate the structure, e.g.,['Au', 'Ag']
; see below for more examplesconcentration_restrictions (
Optional
[dict
]) – allowed concentration range for one or more element in chemical_symbols, e.g.,{'Au': (0, 0.2)}
will only enumerate structures in which the Au content is between 0 and 20 %; here, concentration is always defined as the number of atoms of the specified kind divided by the number of all atoms.niggli_reduction – if True perform a Niggli reduction with spglib for each structure; the default is
True
ifstructure
is periodic in all directions,False
otherwise.symprec (
float
) – tolerance imposed when analyzing the symmetry using spglibposition_tolerance (
Optional
[float
]) – tolerance applied when comparing positions in Cartesian coordinates; by default this value is set equal to symprec
Examples
The following code snippet illustrates how to enumerate structures with up to 6 atoms in the unit cell for a binary alloy without any constraints:
>>> from ase.build import bulk >>> prim = bulk('Ag') >>> for structure in enumerate_structures(structure=prim, ... sizes=range(1, 5), ... chemical_symbols=['Ag', 'Au']): ... pass # Do something with the structure
To limit the concentration range to 10 to 40% Au the code should be modified as follows:
>>> conc_restr = {'Au': (0.1, 0.4)} >>> for structure in enumerate_structures(structure=prim, ... sizes=range(1, 5), ... chemical_symbols=['Ag', 'Au'], ... concentration_restrictions=conc_restr): ... pass # Do something with the structure
Often one would like to consider mixing on only one sublattice. This can be achieved as illustrated for a Ga(1x)Al(x)As alloy as follows:
>>> prim = bulk('GaAs', crystalstructure='zincblende', a=5.65) >>> for structure in enumerate_structures(structure=prim, ... sizes=range(1, 9), ... chemical_symbols=[['Ga', 'Al'], ['As']]): ... pass # Do something with the structure
 Return type
Atoms

icet.tools.
enumerate_supercells
(structure, sizes, niggli_reduce=None, symprec=1e05, position_tolerance=None)[source]¶ Yields a sequence of enumerated supercells. The function generates all inequivalent supercells that are permissible given a certain lattice. Any supercell can be reduced to one of the supercells generated.
The function is sensitive to the boundary conditions of the input structure. An enumeration of, for example, a surface can thus be performed by setting
structure.pbc = [True, True, False]
.The algorithm is based on Gus L. W. Hart and Rodney W. Forcade in Phys. Rev. B 77, 224115 (2008) [HarFor08] and Phys. Rev. B 80, 014120 (2009) [HarFor09].
 Parameters
structure (
Atoms
) – primitive structure from which supercells should be generatedsizes (
List
[int
]) – number of sites (included in enumeration)niggli_reduction – if True perform a Niggli reduction with spglib for each supercell; the default is
True
ifstructure
is periodic in all directions,False
otherwise.symprec (
float
) – tolerance imposed when analyzing the symmetry using spglibposition_tolerance (
Optional
[float
]) – tolerance applied when comparing positions in Cartesian coordinates; by default this value is set equal to symprec
Examples
The following code snippet illustrates how to enumerate supercells with up to 6 atoms in the unit cell:
>>> from ase.build import bulk >>> prim = bulk('Ag') >>> for supercell in enumerate_supercells(structure=prim, sizes=range(1, 7)): ... pass # Do something with the supercell
 Return type
Atoms
Generation of special structures¶

icet.tools.structure_generation.
generate_sqs
(cluster_space, max_size, target_concentrations, include_smaller_cells=True, T_start=5.0, T_stop=0.001, n_steps=None, optimality_weight=1.0, random_seed=None, tol=1e05)[source]¶ Given a
cluster_space
, generate a special quasirandom structure (SQS), i.e., a structure that for a given supercell size provides the best possible approximation to a random alloy [ZunWeiFer90].In the present case, this means that the generated structure will have a cluster vector that as closely as possible matches the cluster vector of an infintely large randomly occupated supercell. Internally the function uses a simulated annealing algorithm and the difference between two cluster vectors is calculated with the measure suggested by A. van de Walle et al. in Calphad 42, 1318 (2013) [WalTiwJon13] (for more information, see
mchammer.calculators.TargetVectorCalculator
). Parameters
cluster_space (
ClusterSpace
) – a cluster space defining the lattice to be occupatedmax_size (
int
) – maximum supercell sizetarget_concentrations (
dict
) –concentration of each species in the target structure (for example
{'Ag': 0.5, 'Pd': 0.5}
Concentrations are always expressed with respect to all atoms in the supercell, which implies that the sum of all concentrations should always be 1. In the case of multiple sublattices, a valid specification would thus be
{'Au': 0.25, 'Pd': 0.25, 'H': 0.1, 'V': 0.4}
.include_smaller_cells (
bool
) – if True, search among all supercell sizes includingmax_size
, else search only among those exactly matchingmax_size
T_start (
float
) – artificial temperature at which the simulated annealing startsT_stop (
float
) – artifical temperature at which the simulated annealing stopsn_steps (
Optional
[float
]) – total number of Monte Carlo steps in the simulationoptimality_weight (
float
) – controls weighting \(L\) of perfect correlations, seemchammer.calculators.TargetVectorCalculator
random_seed (
Optional
[int
]) – seed for the random number generator used in the Monte Carlo simulationtol (
float
) – Numerical tolerance
 Return type
Atoms

icet.tools.structure_generation.
generate_sqs_by_enumeration
(cluster_space, max_size, target_concentrations, include_smaller_cells=True, optimality_weight=1.0, tol=1e05)[source]¶ Given a
cluster_space
, generate a special quasirandom structure (SQS), i.e., a structure that for a given supercell size provides the best possible approximation to a random alloy [ZunWeiFer90].In the present case, this means that the generated structure will have a cluster vector that as closely as possible matches the cluster vector of an infintely large randomly occupied supercell. Internally the function uses a simulated annealing algorithm and the difference between two cluster vectors is calculated with the measure suggested by A. van de Walle et al. in Calphad 42, 1318 (2013) [WalTiwJon13] (for more information, see
mchammer.calculators.TargetVectorCalculator
).This functions generates SQS cells by exhaustive enumeration, which means that the generated SQS cell is guaranteed to be optimal with regard to the specified measure and cell size.
 Parameters
cluster_space (
ClusterSpace
) – a cluster space defining the lattice to be occupiedmax_size (
int
) – maximum supercell sizetarget_concentrations (
dict
) –concentration of each species in the target structure (for example
{'Ag': 0.5, 'Pd': 0.5}
Concentrations are always expressed with respect to all atoms in the supercell, which implies that the sum of all concentrations should always be 1. In the case of multiple sublattices, a valid specification would thus be
{'Au': 0.25, 'Pd': 0.25, 'H': 0.1, 'V': 0.4}
.include_smaller_cells (
bool
) – if True, search among all supercell sizes includingmax_size
, else search only among those exactly matchingmax_size
optimality_weight (
float
) – controls weighting \(L\) of perfect correlations, seemchammer.calculators.TargetVectorCalculator
tol (
float
) – Numerical tolerance
 Return type
Atoms

icet.tools.structure_generation.
generate_target_structure
(cluster_space, max_size, target_concentrations, target_cluster_vector, include_smaller_cells=True, T_start=5.0, T_stop=0.001, n_steps=None, optimality_weight=1.0, random_seed=None, tol=1e05)[source]¶ Given a
cluster_space
and atarget_cluster_vector
, generate a structure that as closely as possible matches that cluster vector. The search is performed among all inequivalent supercells shapes up to a certain size.Internally the function uses a simulated annealing algorithm and the difference between two cluster vectors is calculated with the measure suggested by A. van de Walle et al. in Calphad 42, 1318 (2013) [WalTiwJon13] (for more information, see
mchammer.calculators.TargetVectorCalculator
). Parameters
cluster_space (
ClusterSpace
) – a cluster space defining the lattice to be occupiedmax_size (
int
) – maximum supercell sizetarget_concentrations (
dict
) –concentration of each species in the target structure (for example
{'Ag': 0.5, 'Pd': 0.5}
Concentrations are always expressed with respect to all atoms in the supercell, which implies that the sum of all concentrations should always be 1. In the case of multiple sublattices, a valid specification would thus be
{'Au': 0.25, 'Pd': 0.25, 'H': 0.1, 'V': 0.4}
.target_cluster_vector (
List
[float
]) – cluster vector that the generated structure should match as closely as possibleinclude_smaller_cells (
bool
) – if True, search among all supercell sizes includingmax_size
, else search only among those exactly matchingmax_size
T_start (
float
) – artificial temperature at which the simulated annealing startsT_stop (
float
) – artifical temperature at which the simulated annealing stopsn_steps (
Optional
[float
]) – total number of Monte Carlo steps in the simulationoptimality_weight (
float
) – controls weighting \(L\) of perfect correlations, seemchammer.calculators.TargetVectorCalculator
random_seed (
Optional
[int
]) – seed for the random number generator used in the Monte Carlo simulationtol (
float
) – Numerical tolerance
 Return type
Atoms

icet.tools.structure_generation.
occupy_structure_randomly
(structure, cluster_space, target_concentrations)[source]¶ Occupy a structure with quasirandom order but fulfilling
target_concentrations
. Parameters
structure (
Atoms
) – ASE Atoms object that will be occupied randomlycluster_space (
ClusterSpace
) – cluster space (needed as it carries information about sublattices)target_concentrations (
dict
) –concentration of each species in the target structure (for example
{'Ag': 0.5, 'Pd': 0.5}
Concentrations are always expressed with respect to all atoms in the supercell, which implies that the sum of all concentrations should always be 1. In the case of multiple sublattices, a valid specification would thus be
{'Au': 0.25, 'Pd': 0.25, 'H': 0.1, 'V': 0.4}
.
Ground state finder¶

class
icet.tools.ground_state_finder.
GroundStateFinder
(cluster_expansion, structure, solver_name=None, verbose=True)[source]¶ This class provides functionality for determining the ground states using a binary cluster expansion. This is efficiently achieved through the use of mixed integer programming (MIP) as shown by Larsen et al. in Phys. Rev. Lett. 120, 256101 (2018).
This class relies on the PythonMIP package. PythonMIP can be used together with Gurobi, which is not open source but issues academic licenses free of charge. Pleaase note that Gurobi needs to be installed separately. The GroundStateFinder works also without Gurobi, but if performance is critical, Gurobi is highly recommended.
Warning
In order to be able to use Gurobi with pythonmip one must ensure that GUROBI_HOME should point to the installation directory (
<installdir>
):export GUROBI_HOME=<installdir>
Note
The current implementation only works for binary systems.
 Parameters
cluster_expansion (ClusterExpansion) – cluster expansion for which to find ground states
structure (Atoms) – atomic configuration
solver_name (str, optional) – ‘gurobi’, alternatively ‘grb’, or ‘cbc’, searches for available solvers if not informed
verbose (bool, optional) – whether to display solver messages on the screen (default: True)
Example
The following snippet illustrates how to determine the ground state for a AuAg alloy. Here, the parameters of the cluster expansion are set to emulate a simple Ising model in order to obtain an example that can be run without modification. In practice, one should of course use a proper cluster expansion:
>>> from ase.build import bulk >>> from icet import ClusterExpansion, ClusterSpace >>> # prepare cluster expansion >>> # the setup emulates a second nearestneighbor (NN) Ising model >>> # (zerolet and singlet ECIs are zero; only first and second neighbor >>> # pairs are included) >>> prim = bulk('Au') >>> chemical_symbols = ['Ag', 'Au'] >>> cs = ClusterSpace(prim, cutoffs=[4.3], chemical_symbols=chemical_symbols) >>> ce = ClusterExpansion(cs, [0, 0, 0.1, 0.02]) >>> # prepare initial configuration >>> structure = prim.repeat(3) >>> # set up the ground state finder and calculate the ground state energy >>> gsf = GroundStateFinder(ce, structure) >>> ground_state = gsf.get_ground_state({'Ag': 5}) >>> print('Ground state energy:', ce.predict(ground_state))

get_ground_state
(species_count, max_seconds=inf, threads=0)[source]¶ Finds the ground state for a given structure and species count, which refers to the count_species, if provided when initializing the instance of this class, or the first species in the list of chemical symbols for the active sublattice.
 Parameters
species_count (
Dict
[str
,int
]) – dictionary with count for one of the species on each active sublatticemax_seconds (
float
) – maximum runtime in seconds (default: inf)threads (
int
) – number of threads to be used when solving the problem, given that a positive integer has been provided. If set to 0 the solver default configuration is used while 1 corresponds to all available processing cores.
 Return type
Atoms

property
model
¶ PythonMIP model
 Return type
Model

property
optimization_status
¶ Optimization status
 Return type
OptimizationStatus
Convex hull construction¶
This module collects a number of different tools, e.g., for structure generation and analysis.

class
icet.tools.
ConvexHull
(concentrations, energies)[source]¶ This class provides functionality for extracting the convex hull of the (free) energy of mixing. It is based on the convex hull calculator in SciPy.
 Parameters
concentrations (list(float) or list(list(float))) – concentrations for each structure listed as
[[c1, c2], [c1, c2], ...]
; for binaries, in which case there is only one independent concentration, the format[c1, c2, c3, ...]
works as well.energies (list(float)) – energy (or energy of mixing) for each structure

concentrations
¶ concentrations of the N structures on the convex hull
 Type
np.ndarray

energies
¶ energies of the N structures on the convex hull
 Type
np.ndarray

dimensions
¶ number of independent concentrations needed to specify a point in concentration space (1 for binaries, 2 for ternaries etc.)
 Type
int

structures
¶ indices of structures that constitute the convex hull (indices are defined by the order of their concentrations and energies are fed when initializing the ConvexHull object)
 Type
list(int)
Examples
A ConvexHull object is easily initialized by providing lists of concentrations and energies:
>>> data = {'concentration': [0, 0.2, 0.2, 0.3, 0.4, 0.5, 0.8, 1.0], ... 'mixing_energy': [0.1, 0.2, 0.1, 0.2, 0.2, 0.4, 0.2, 0.1]} >>> hull = ConvexHull(data['concentration'], data['mixing_energy'])
Now one can for example access the points along the convex hull directly:
>>> for c, e in zip(hull.concentrations, hull.energies): ... print(c, e) 0.0 0.1 0.2 0.2 0.5 0.4 1.0 0.1
or plot the convex hull along with the original data using e.g., matplotlib:
>>> import matplotlib.pyplot as plt >>> plt.scatter(data['concentration'], data['mixing_energy'], color='darkred') >>> plt.plot(hull.concentrations, hull.energies) >>> plt.show()
It is also possible to extract structures at or close to the convex hull:
>>> low_energy_structures = hull.extract_low_energy_structures( ... data['concentration'], data['mixing_energy'], ... energy_tolerance=0.005)
A complete example can be found in the basic tutorial.

extract_low_energy_structures
(concentrations, energies, energy_tolerance)[source]¶ Returns the indices of energies that lie within a certain tolerance of the convex hull.
 Parameters
concentrations (
Union
[List
[float
],List
[List
[float
]]]) –concentrations of candidate structures
If there is one independent concentration, a list of floats is sufficient. Otherwise, the concentrations must be provided as a list of lists, such as
[[0.1, 0.2], [0.3, 0.1], ...]
.energies (
List
[float
]) – energies of candidate structuresenergy_tolerance (
float
) – include structures with an energy that is at most this far from the convex hull
 Return type
List
[int
]

get_energy_at_convex_hull
(target_concentrations)[source]¶ Returns the energy of the convex hull at specified concentrations. If any concentration is outside the allowed range, NaN is returned.
 Parameters
target_concentrations (
Union
[List
[float
],List
[List
[float
]]]) –concentrations at target points
If there is one independent concentration, a list of floats is sufficient. Otherwise, the concentrations ought to be provided as a list of lists, such as
[[0.1, 0.2], [0.3, 0.1], ...]
. Return type
Other structure tools¶

icet.tools.
get_primitive_structure
(structure, no_idealize=True, to_primitive=True, symprec=1e05)[source]¶ Returns the primitive structure using spglib.
 Parameters
structure (
Atoms
) – input atomic structureno_idealize (
bool
) – if True lengths and angles are not idealizedto_primitive (
bool
) – convert to primitive structuresymprec (
float
) – tolerance imposed when analyzing the symmetry using spglib
 Return type
Atoms

icet.tools.
get_wyckoff_sites
(structure, map_occupations=None, symprec=1e05)[source]¶ Returns the Wyckoff symbols of the input structure. The Wyckoff sites are of general interest for symmetry analysis but can be especially useful when setting up, e.g., a
SiteOccupancyObserver
. The Wyckoff labels can be conveniently attached as an array to the structure object as demonstrated in the examples section below.By default the occupation of the sites is part of the symmetry analysis. If a chemically disordered structure is provided this will usually reduce the symmetry substantially. If one is interested in the symmetry of the underlying structure one can control how occupations are handled. To this end, one can provide the
map_occupations
keyword argument. The latter must be a list, each entry of which is a list of species that should be treated as indistinguishable. As a shortcut, if all species should be treated as indistinguishable one can provide an empty list. Examples that illustrate the usage of the keyword are given below. Parameters
structure (
Atoms
) – input structure, note that the occupation of the sites is included in the symmetry analysismap_occupations (
Optional
[List
[List
[str
]]]) – each sublist in this list specifies a group of chemical species that shall be treated as indistinguishable for the purpose of the symmetry analysissymprec (
float
) – tolerance imposed when analyzing the symmetry using spglib
Examples
Wyckoff sites of a hexagonalclose packed structure:
>>> from ase.build import bulk >>> structure = bulk('Ti') >>> wyckoff_sites = get_wyckoff_sites(structure) >>> print(wyckoff_sites) ['2d', '2d']
The Wyckoff labels can also be attached as an array to the structure, in which case the information is also included when storing the Atoms object:
>>> from ase.io import write >>> structure.new_array('wyckoff_sites', wyckoff_sites, str) >>> write('structure.xyz', structure)
The function can also be applied to supercells:
>>> structure = bulk('GaAs', crystalstructure='zincblende', a=3.0).repeat(2) >>> wyckoff_sites = get_wyckoff_sites(structure) >>> print(wyckoff_sites) ['4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c']
Now assume that one is given a supercell of a (Ga,Al)As alloy. Applying the function directly yields much lower symmetry since the symmetry of the original structure is broken:
>>> structure.set_chemical_symbols( ... ['Ga', 'As', 'Al', 'As', 'Ga', 'As', 'Al', 'As', ... 'Ga', 'As', 'Ga', 'As', 'Al', 'As', 'Ga', 'As']) >>> print(get_wyckoff_sites(structure)) ['8g', '8i', '4e', '8i', '8g', '8i', '2c', '8i', '2d', '8i', '8g', '8i', '4e', '8i', '8g', '8i']
Since Ga and Al occupy the same sublattice, they should, however, be treated as indistinguishable for the purpose of the symmetry analysis, which can be achieved via the
map_occupations
keyword:>>> print(get_wyckoff_sites(structure, map_occupations=[['Ga', 'Al'], ['As']])) ['4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c', '4a', '4c']
If occupations are to ignored entirely, one can simply provide an empty list. In the present case, this turns the zincblende lattice into a diamond lattice, on which case there is only one Wyckoff site:
>>> print(get_wyckoff_sites(structure, map_occupations=[])) ['8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a', '8a']
 Return type
List
[str
]