Coverage for wulffpack/winterbottom.py: 100%
25 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-02 08:51 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-02 08:51 +0000
1from typing import Dict
2import numpy as np
3from ase import Atoms
4from .core import BaseParticle
5from .core.form import setup_forms
6from .core.geometry import (get_symmetries,
7 break_symmetry,
8 get_angle,
9 get_rotation_matrix,
10 get_standardized_structure)
13class Winterbottom(BaseParticle):
14 """
15 A `Winterbottom` object is a Winterbottom construction, i.e.,
16 the lowest energy shape adopted by a single crystalline particle
17 in contact with an interface.
19 Parameters
20 ----------
21 surface_energies
22 A dictionary with surface energies, where keys are
23 Miller indices and values surface energies (per area)
24 in a unit of choice, such as J/m^2.
25 interface_direction
26 Miller indices for the interface facet.
27 interface_energy
28 Energy per area for twin boundaries.
29 primtive_structure
30 primitive structure to implicitly define the point group as
31 well as the atomic structure used if an atomic structure
32 is requested. By default, an Au FCC structure is used.
33 natoms
34 Together with `primitive_structure`, this parameter
35 defines the volume of the particle. If an atomic structure
36 is requested, the number of atoms will as closely as possible
37 match this value.
38 symprec
39 Numerical tolerance for symmetry analysis, forwarded to spglib.
40 tol
41 Numerical tolerance parameter.
43 Example
44 -------
45 The following example illustrates some possible uses of a
46 `Winterbottom` object::
48 >>> from wulffpack import Winterbottom
49 >>> from ase.build import bulk
50 >>> from ase.io import write
51 >>> surface_energies = {(1, 1, 0): 1.0, (1, 0, 0): 1.08}
52 >>> prim = bulk('Fe', a=4.1, crystalstructure='bcc')
53 >>> particle = Winterbottom(surface_energies=surface_energies,
54 ... interface_direction=(3, 2, 1),
55 ... interface_energy=0.4,
56 ... primitive_structure=prim)
57 >>> particle.view()
58 >>> write('winterbottom.xyz', particle.atoms) # Writes atomic structure to file
60 """
62 def __init__(self,
63 surface_energies: Dict[tuple, float],
64 interface_direction: tuple,
65 interface_energy: float,
66 primitive_structure: Atoms = None,
67 natoms: int = 1000,
68 symprec: float = 1e-5,
69 tol: float = 1e-5):
70 standardized_structure = get_standardized_structure(primitive_structure, symprec=symprec)
71 full_symmetries = get_symmetries(standardized_structure, symprec=symprec)
72 broken_symmetries = break_symmetry(full_symmetries,
73 [interface_direction])
75 if interface_energy > min(surface_energies.values()):
76 raise ValueError('The construction expects an interface energy '
77 'that is smaller than than the smallest '
78 'surface energy.')
79 surface_energies = surface_energies.copy()
80 surface_energies['interface'] = interface_energy
81 forms = setup_forms(surface_energies,
82 standardized_structure.cell.T,
83 broken_symmetries,
84 full_symmetries,
85 interface=interface_direction)
87 super().__init__(forms=forms,
88 standardized_structure=standardized_structure,
89 natoms=natoms,
90 tol=tol)
92 # Rotate particle such that the interface aligns with the plane z=0
93 target = (0, 0, -1)
94 rotation_axis = np.cross(interface_direction, target)
95 angle = get_angle(interface_direction, target)
96 R = get_rotation_matrix(angle, rotation_axis.astype(float))
97 self.rotate_particle(R)
99 @property
100 def atoms(self):
101 """
102 Returns an ASE Atoms object
103 """
104 return self._get_atoms()