Tools

Mapping structures

icet.tools.map_structure_to_reference(structure: ase.atoms.Atoms, reference: ase.atoms.Atoms, inert_species: List[str] = None, tol_positions: float = 0.0001, suppress_warnings: bool = False, assume_no_cell_relaxation: bool = False) → Tuple[ase.atoms.Atoms, dict][source]

Maps a structure onto a reference structure. This is often desirable when, for example, a structure has been relaxed using DFT, and one wants to use it as a training structure in a cluster expansion.

The function returns a tuple comprising the ideal supercell most closely matching the input structure and a dictionary with supplementary information concerning the mapping. The latter includes for example the largest deviation of any position in the input structure from its reference position (drmax), the average deviation of the positions in the input structure from the reference positions (dravg), and the strain tensor for the input structure relative to the reference structure (strain_tensor).

The Atoms object that provide further supplemental information via custom per-atom arrays including the atomic displacements (Displacement, Displacement_Magnitude) as well as the distances to the three closest sites (Minimum_Distances).

Parameters
  • structure – input structure, typically a relaxed structure

  • reference – reference structure, which can but need not be the primitive structure

  • inert_species – 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 input structure to match the reference structure.

  • tol_positions – tolerance factor applied when scanning for overlapping positions in Angstrom (forwarded to ase.build.make_supercell())

  • suppress_warnings – if True, print no warnings of large strain or relaxation distances

  • assume_no_cell_relaxation

    if False volume and cell metric of the input 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 input 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)

Structure enumeration

icet.tools.enumerate_structures(structure: ase.atoms.Atoms, sizes: Union[List[int], range], chemical_symbols: list, concentration_restrictions: dict = None, niggli_reduce: bool = None, symprec: float = 1e-05, position_tolerance: float = None) → ase.atoms.Atoms[source]

Yields a sequence of enumerated structures. The function generates all inequivalent structures that are permissible given a certain lattice. Using the chemical_symbols and concentration_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 – primitive structure from which derivative superstructures should be generated

  • sizes – number of sites (included in enumeration)

  • chemical_symbols – chemical species with which to decorate the structure, e.g., ['Au', 'Ag']; see below for more examples

  • concentration_restrictions – 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 if structure is periodic in all directions, False otherwise.

  • symprec – tolerance imposed when analyzing the symmetry using spglib

  • position_tolerance – 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(1-x)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
icet.tools.enumerate_supercells(structure: ase.atoms.Atoms, sizes: Union[List[int], range], niggli_reduce: bool = None, symprec: float = 1e-05, position_tolerance: float = None) → ase.atoms.Atoms[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 – primitive structure from which supercells should be generated

  • sizes – number of sites (included in enumeration)

  • niggli_reduction – if True perform a Niggli reduction with spglib for each supercell; the default is True if structure is periodic in all directions, False otherwise.

  • symprec – tolerance imposed when analyzing the symmetry using spglib

  • position_tolerance – 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

Generation of special structures

icet.tools.structure_generation.generate_sqs(cluster_space: icet.core.cluster_space.ClusterSpace, max_size: int, target_concentrations: dict, include_smaller_cells: bool = True, pbc: Union[Tuple[bool, bool, bool], Tuple[int, int, int]] = None, T_start: float = 5.0, T_stop: float = 0.001, n_steps: int = None, optimality_weight: float = 1.0, random_seed: int = None, tol: float = 1e-05) → ase.atoms.Atoms[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, 13-18 (2013) [WalTiwJon13] (for more information, see mchammer.calculators.TargetVectorCalculator).

Parameters
  • cluster_space – a cluster space defining the lattice to be occupated

  • max_size – maximum supercell size

  • target_concentrations – concentration of each species in the target structure, per sublattice (for example {'Au': 0.5, 'Pd': 0.5} for a single sublattice Au-Pd structure, or {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'H': 0.25, 'X': 0.75}} for a system with two sublattices. The symbols defining sublattices (‘A’, ‘B’ etc) can be found by printing the cluster_space

  • include_smaller_cells – if True, search among all supercell sizes including max_size, else search only among those exactly matching max_size

  • pbc – Periodic boundary conditions for each direction, e.g., (True, True, False). The axes are defined by the cell of cluster_space.primitive_structure. Default is periodic boundary in all directions.

  • T_start – artificial temperature at which the simulated annealing starts

  • T_stop – artifical temperature at which the simulated annealing stops

  • n_steps – total number of Monte Carlo steps in the simulation

  • optimality_weight – controls weighting \(L\) of perfect correlations, see mchammer.calculators.TargetVectorCalculator

  • random_seed – seed for the random number generator used in the Monte Carlo simulation

  • tol – Numerical tolerance

icet.tools.structure_generation.generate_sqs_by_enumeration(cluster_space: icet.core.cluster_space.ClusterSpace, max_size: int, target_concentrations: dict, include_smaller_cells: bool = True, pbc: Union[Tuple[bool, bool, bool], Tuple[int, int, int]] = None, optimality_weight: float = 1.0, tol: float = 1e-05) → ase.atoms.Atoms[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, 13-18 (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 – a cluster space defining the lattice to be occupied

  • max_size – maximum supercell size

  • target_concentrations – concentration of each species in the target structure, per sublattice (for example {'Au': 0.5, 'Pd': 0.5} for a single sublattice Au-Pd structure, or {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'H': 0.25, 'X': 0.75}} for a system with two sublattices. The symbols defining sublattices (‘A’, ‘B’ etc) can be found by printing the cluster_space

  • include_smaller_cells – if True, search among all supercell sizes including max_size, else search only among those exactly matching max_size

  • pbc – Periodic boundary conditions for each direction, e.g., (True, True, False). The axes are defined by the cell of cluster_space.primitive_structure. Default is periodic boundary in all directions.

  • optimality_weight – controls weighting \(L\) of perfect correlations, see mchammer.calculators.TargetVectorCalculator

  • tol – Numerical tolerance

icet.tools.structure_generation.generate_sqs_from_supercells(cluster_space: icet.core.cluster_space.ClusterSpace, supercells: List[ase.atoms.Atoms], target_concentrations: dict, T_start: float = 5.0, T_stop: float = 0.001, n_steps: int = None, optimality_weight: float = 1.0, random_seed: int = None, tol: float = 1e-05) → ase.atoms.Atoms[source]

Given a cluster_space and one or more supercells, generate a special quasirandom structure (SQS), i.e., a structure that for the provided supercells 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, 13-18 (2013) [WalTiwJon13] (for more information, see mchammer.calculators.TargetVectorCalculator).

Parameters
  • cluster_space – a cluster space defining the lattice to be occupated

  • supercells – list of one or more supercells among which an optimal structure will be searched for

  • target_concentrations – concentration of each species in the target structure, per sublattice (for example {'Au': 0.5, 'Pd': 0.5} for a single sublattice Au-Pd structure, or {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'H': 0.25, 'X': 0.75}} for a system with two sublattices. The symbols defining sublattices (‘A’, ‘B’ etc) can be found by printing the cluster_space

  • T_start – artificial temperature at which the simulated annealing starts

  • T_stop – artifical temperature at which the simulated annealing stops

  • n_steps – total number of Monte Carlo steps in the simulation

  • optimality_weight – controls weighting \(L\) of perfect correlations, see mchammer.calculators.TargetVectorCalculator

  • random_seed – seed for the random number generator used in the Monte Carlo simulation

  • tol – Numerical tolerance

icet.tools.structure_generation.generate_target_structure(cluster_space: icet.core.cluster_space.ClusterSpace, max_size: int, target_concentrations: dict, target_cluster_vector: List[float], include_smaller_cells: bool = True, pbc: Union[Tuple[bool, bool, bool], Tuple[int, int, int]] = None, T_start: float = 5.0, T_stop: float = 0.001, n_steps: int = None, optimality_weight: float = 1.0, random_seed: int = None, tol: float = 1e-05) → ase.atoms.Atoms[source]

Given a cluster_space and a target_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, 13-18 (2013) [WalTiwJon13] (for more information, see mchammer.calculators.TargetVectorCalculator).

Parameters
  • cluster_space – a cluster space defining the lattice to be occupied

  • max_size – maximum supercell size

  • target_concentrations – concentration of each species in the target structure, per sublattice (for example {'Au': 0.5, 'Pd': 0.5} for a single sublattice Au-Pd structure, or {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'H': 0.25, 'X': 0.75}} for a system with two sublattices. The symbols defining sublattices (‘A’, ‘B’ etc) can be found by printing the cluster_space

  • target_cluster_vector – cluster vector that the generated structure should match as closely as possible

  • include_smaller_cells – if True, search among all supercell sizes including max_size, else search only among those exactly matching max_size

  • pbc – Periodic boundary conditions for each direction, e.g., (True, True, False). The axes are defined by the cell of cluster_space.primitive_structure. Default is periodic boundary in all directions.

  • T_start – artificial temperature at which the simulated annealing starts

  • T_stop – artifical temperature at which the simulated annealing stops

  • n_steps – total number of Monte Carlo steps in the simulation

  • optimality_weight – controls weighting \(L\) of perfect correlations, see mchammer.calculators.TargetVectorCalculator

  • random_seed – seed for the random number generator used in the Monte Carlo simulation

  • tol – Numerical tolerance

icet.tools.structure_generation.generate_target_structure_from_supercells(cluster_space: icet.core.cluster_space.ClusterSpace, supercells: List[ase.atoms.Atoms], target_concentrations: dict, target_cluster_vector: List[float], T_start: float = 5.0, T_stop: float = 0.001, n_steps: int = None, optimality_weight: float = 1.0, random_seed: int = None, tol: float = 1e-05) → ase.atoms.Atoms[source]

Given a cluster_space and a target_cluster_vector and one or more supercells, generate a structure that as closely as possible matches that cluster vector.

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, 13-18 (2013) [WalTiwJon13] (for more information, see mchammer.calculators.TargetVectorCalculator).

Parameters
  • cluster_space – a cluster space defining the lattice to be occupied

  • supercells – list of one or more supercells among which an optimal structure will be searched for

  • target_concentrations – concentration of each species in the target structure, per sublattice (for example {'Au': 0.5, 'Pd': 0.5} for a single sublattice Au-Pd structure, or {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'H': 0.25, 'X': 0.75}} for a system with two sublattices. The symbols defining sublattices (‘A’, ‘B’ etc) can be found by printing the cluster_space

  • target_cluster_vector – cluster vector that the generated structure should match as closely as possible

  • T_start – artificial temperature at which the simulated annealing starts

  • T_stop – artifical temperature at which the simulated annealing stops

  • n_steps – total number of Monte Carlo steps in the simulation

  • optimality_weight – controls weighting \(L\) of perfect correlations, see mchammer.calculators.TargetVectorCalculator

  • random_seed – seed for the random number generator used in the Monte Carlo simulation

  • tol – Numerical tolerance

icet.tools.structure_generation.occupy_structure_randomly(structure: ase.atoms.Atoms, cluster_space: icet.core.cluster_space.ClusterSpace, target_concentrations: dict) → None[source]

Occupy a structure with quasirandom order but fulfilling target_concentrations.

Parameters
  • structure – ASE Atoms object that will be occupied randomly

  • cluster_space – cluster space (needed as it carries information about sublattices)

  • target_concentrations – concentration of each species in the target structure, per sublattice (for example {'Au': 0.5, 'Pd': 0.5} for a single sublattice Au-Pd structure, or {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'H': 0.25, 'X': 0.75}} for a system with two sublattices. The symbols defining sublattices (‘A’, ‘B’ etc) can be found by printing the cluster_space

Ground state finder

class icet.tools.ground_state_finder.GroundStateFinder(cluster_expansion: icet.core.cluster_expansion.ClusterExpansion, structure: ase.atoms.Atoms, solver_name: str = None, verbose: bool = 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 developed by Larsen et al. in Phys. Rev. Lett. 120, 256101 (2018).

This class relies on the Python-MIP package. Python-MIP 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 python-mip 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 Au-Ag 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 nearest-neighbor (NN) Ising model
>>> # (zerolet and singlet parameters 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: Dict[str, int] = None, max_seconds: float = inf, threads: int = 0) → ase.atoms.Atoms[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 – dictionary with count for one of the species on each active sublattice. If no count is provided for a sublattice, the concentration is allowed to vary.

  • max_seconds – maximum runtime in seconds (default: inf)

  • threads – 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.

property model

Python-MIP model

property optimization_status

Optimization status

Convex hull construction

This module collects a number of different tools, e.g., for structure generation and analysis.

class icet.tools.ConvexHull(concentrations: Union[List[float], List[List[float]]], energies: List[float])[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: Union[List[float], List[List[float]]], energies: List[float], energy_tolerance: float) → List[int][source]

Returns the indices of energies that lie within a certain tolerance of the convex hull.

Parameters
  • concentrations

    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 – energies of candidate structures

  • energy_tolerance – include structures with an energy that is at most this far from the convex hull

get_energy_at_convex_hull(target_concentrations: Union[List[float], List[List[float]]])numpy.ndarray[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

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], ...].

Fitting with constraints

class icet.tools.constraints.Constraints(n_params: int)[source]

Class for handling linear constraints with right hand side equal to zero.

Parameters

n_params – number of parameters in model

Example

The following example demonstrates fitting of a cluster expansion under the constraint that parameter 2 and parameter 4 should be equal:

>>> from icet.tools import Constraints
>>> from icet.fitting import Optimizer
>>> import numpy as np

>>> # Set up random sensing matrix and target "energies"
>>> n_params = 10
>>> A = np.random.random((10, n_params))
>>> y = np.random.random(10)

>>> # Define constraints
>>> c = Constraints(n_params=n_params)
>>> M = np.zeros((1, n_params))
>>> M[0, [2, 4]] = 1
>>> c.add_constraint(M)

>>> # Do the actual fit and finally extract parameters
>>> A_constrained = c.transform(A)
>>> opt = Optimizer((A_constrained, y), fit_method='ridge')
>>> opt.train()
>>> parameters = c.inverse_transform(opt.parameters)
add_constraint(M: numpy.ndarray) → None[source]

Add a constraint matrix and resolve for the constraint space

Parameters

M – Constraint matrix with each constraint as a row. Can (but need not be) cluster vectors.

inverse_transform(A: numpy.ndarray)numpy.ndarray[source]

Inverse transform array from constrained parameter space to unconstrained space

Parameters

A – array to be inversed transformed

transform(A: numpy.ndarray)numpy.ndarray[source]

Transform array to constrained parameter space

Parameters

A – array to be transformed

icet.tools.constraints.get_mixing_energy_constraints(cluster_space)icet.tools.constraints.Constraints[source]

A cluster expansion of mixing energy should ideally predict zero energy for concentration 0 and 1. This function constructs a Constraints object that enforces that condition during fitting.

Parameters

cluster_space (ClusterSpace) – Cluster space corresponding to cluster expansion for which constraints should be imposed

Example

This example demonstrates how to constrain the mixing energy to zero at the pure phases in a toy example with random cluster vectors and random target energies:

>>> from icet.tools import get_mixing_energy_constraints
>>> from icet.fitting import Optimizer
>>> from icet import ClusterSpace
>>> from ase.build import bulk
>>> import numpy as np

>>> # Set up cluster space along with random sensing matrix and target "energies"
>>> prim = bulk('Au')
>>> cs = ClusterSpace(prim, cutoffs=[6.0, 5.0], chemical_symbols=['Au', 'Ag'])
>>> n_params = len(cs)
>>> A = np.random.random((10, len(cs)))
>>> y = np.random.random(10)

>>> # Define constraints
>>> c = get_mixing_energy_constraints(cs)

>>> # Do the actual fit and finally extract parameters
>>> A_constrained = c.transform(A)
>>> opt = Optimizer((A_constrained, y), fit_method='ridge')
>>> opt.train()
>>> parameters = c.inverse_transform(opt.parameters)

Warning

Constraining the energy of one structure is always done at the expense of the fit quality of the others. Always expect that your CV scores will increase somewhat when using this function.

Other structure tools

icet.tools.get_primitive_structure(structure: ase.atoms.Atoms, no_idealize: bool = True, to_primitive: bool = True, symprec: float = 1e-05) → ase.atoms.Atoms[source]

Returns the primitive structure using spglib.

Parameters
  • structure – input atomic structure

  • no_idealize – if True lengths and angles are not idealized

  • to_primitive – convert to primitive structure

  • symprec – tolerance imposed when analyzing the symmetry using spglib

icet.tools.get_wyckoff_sites(structure: ase.atoms.Atoms, map_occupations: List[List[str]] = None, symprec: float = 1e-05) → List[str][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 – input structure, note that the occupation of the sites is included in the symmetry analysis

  • map_occupations – each sublist in this list specifies a group of chemical species that shall be treated as indistinguishable for the purpose of the symmetry analysis

  • symprec – tolerance imposed when analyzing the symmetry using spglib

Examples

Wyckoff sites of a hexagonal-close 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']