• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

materialsproject / pymatgen / 4075885785

pending completion
4075885785

push

github

Shyue Ping Ong
Merge branch 'master' of github.com:materialsproject/pymatgen

96 of 96 new or added lines in 27 files covered. (100.0%)

81013 of 102710 relevant lines covered (78.88%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.74
/pymatgen/analysis/dimensionality.py
1
"""
2
This module provides functions to get the dimensionality of a structure.
3

4
A number of different algorithms are implemented. These are based on the
5
following publications:
6

7
get_dimensionality_larsen:
8
  - P. M. Larsen, M. Pandey, M. Strange, K. W. Jacobsen. Definition of a
9
    scoring parameter to identify low-dimensional materials components.
10
    Phys. Rev. Materials 3, 034003 (2019).
11

12
get_dimensionality_cheon:
13
  - Cheon, G.; Duerloo, K.-A. N.; Sendek, A. D.; Porter, C.; Chen, Y.; Reed,
14
    E. J. Data Mining for New Two- and One-Dimensional Weakly Bonded Solids
15
    and Lattice-Commensurate Heterostructures. Nano Lett. 2017.
16

17
get_dimensionality_gorai:
18
  - Gorai, P., Toberer, E. & Stevanovic, V. Computational Identification of
19
    Promising Thermoelectric Materials Among Known Quasi-2D Binary Compounds.
20
    J. Mater. Chem. A 2, 4136 (2016).
21
"""
22

23
from __future__ import annotations
1✔
24

25
import copy
1✔
26
import itertools
1✔
27
from collections import defaultdict
1✔
28

29
import numpy as np
1✔
30
from networkx.readwrite import json_graph
1✔
31

32
from pymatgen.analysis.graphs import MoleculeGraph, StructureGraph
1✔
33
from pymatgen.analysis.local_env import JmolNN
1✔
34
from pymatgen.analysis.structure_analyzer import get_max_bond_lengths
1✔
35
from pymatgen.core.lattice import get_integer_index
1✔
36
from pymatgen.core.periodic_table import Species
1✔
37
from pymatgen.core.structure import Molecule, Structure
1✔
38
from pymatgen.core.surface import SlabGenerator
1✔
39
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
1✔
40

41
__author__ = "Alex Ganose, Gowoon Cheon, Prashun Gorai"
1✔
42

43

44
def get_dimensionality_larsen(bonded_structure):
1✔
45
    """
46
    Gets the dimensionality of a bonded structure.
47

48
    The dimensionality of the structure is the highest dimensionality of all
49
    structure components. This method is very robust and can handle
50
    many tricky structures, regardless of structure type or improper connections
51
    due to periodic boundary conditions.
52

53
    Requires a StructureGraph object as input. This can be generated using one
54
    of the NearNeighbor classes. For example, using the CrystalNN class::
55

56
        bonded_structure = CrystalNN().get_bonded_structure(structure)
57

58
    Based on the modified breadth-first-search algorithm described in:
59

60
    P. M. Larsen, M. Pandey, M. Strange, K. W. Jacobsen. Definition of a
61
    scoring parameter to identify low-dimensional materials components.
62
    Phys. Rev. Materials 3, 034003 (2019).
63

64
    Args:
65
        bonded_structure (StructureGraph): A structure with bonds, represented
66
            as a pymatgen structure graph. For example, generated using the
67
            CrystalNN.get_bonded_structure() method.
68

69
    Returns:
70
        (int): The dimensionality of the structure.
71
    """
72
    return max(c["dimensionality"] for c in get_structure_components(bonded_structure))
1✔
73

74

75
def get_structure_components(
1✔
76
    bonded_structure,
77
    inc_orientation=False,
78
    inc_site_ids=False,
79
    inc_molecule_graph=False,
80
):
81
    """
82
    Gets information on the components in a bonded structure.
83

84
    Correctly determines the dimensionality of all structures, regardless of
85
    structure type or improper connections due to periodic boundary conditions.
86

87
    Requires a StructureGraph object as input. This can be generated using one
88
    of the NearNeighbor classes. For example, using the CrystalNN class::
89

90
        bonded_structure = CrystalNN().get_bonded_structure(structure)
91

92
    Based on the modified breadth-first-search algorithm described in:
93

94
    P. M. Larsen, M. Pandey, M. Strange, K. W. Jacobsen. Definition of a
95
    scoring parameter to identify low-dimensional materials components.
96
    Phys. Rev. Materials 3, 034003 (2019).
97

98
    Args:
99
        bonded_structure (StructureGraph): A structure with bonds, represented
100
            as a pymatgen structure graph. For example, generated using the
101
            CrystalNN.get_bonded_structure() method.
102
        inc_orientation (bool, optional): Whether to include the orientation
103
            of the structure component. For surfaces, the miller index is given,
104
            for one-dimensional structures, the direction of the chain is given.
105
        inc_site_ids (bool, optional): Whether to include the site indices
106
            of the sites in the structure component.
107
        inc_molecule_graph (bool, optional): Whether to include MoleculeGraph
108
            objects for zero-dimensional components.
109

110
    Returns:
111
        (list of dict): Information on the components in a structure as a list
112
        of dictionaries with the keys:
113

114
        - "structure_graph": A pymatgen StructureGraph object for the
115
            component.
116
        - "dimensionality": The dimensionality of the structure component as an
117
            int.
118
        - "orientation": If inc_orientation is `True`, the orientation of the
119
            component as a tuple. E.g. (1, 1, 1)
120
        - "site_ids": If inc_site_ids is `True`, the site indices of the
121
            sites in the component as a tuple.
122
        - "molecule_graph": If inc_molecule_graph is `True`, the site a
123
            MoleculeGraph object for zero-dimensional components.
124
    """
125
    import networkx as nx  # optional dependency therefore not top level import
1✔
126

127
    comp_graphs = (bonded_structure.graph.subgraph(c) for c in nx.weakly_connected_components(bonded_structure.graph))
1✔
128

129
    components = []
1✔
130
    for graph in comp_graphs:
1✔
131
        dimensionality, vertices = calculate_dimensionality_of_site(
1✔
132
            bonded_structure, list(graph.nodes())[0], inc_vertices=True
133
        )
134

135
        component = {"dimensionality": dimensionality}
1✔
136

137
        if inc_orientation:
1✔
138
            if dimensionality in [1, 2]:
1✔
139
                vertices = np.array(vertices)
1✔
140

141
                g = vertices.sum(axis=0) / vertices.shape[0]
1✔
142

143
                # run singular value decomposition
144
                _, _, vh = np.linalg.svd(vertices - g)
1✔
145

146
                # get direction (first column is best fit line,
147
                # 3rd column is unitary norm)
148
                index = 2 if dimensionality == 2 else 0
1✔
149
                orientation = get_integer_index(vh[index, :])
1✔
150
            else:
151
                orientation = None
×
152

153
            component["orientation"] = orientation
1✔
154

155
        if inc_site_ids:
1✔
156
            component["site_ids"] = tuple(graph.nodes())
×
157

158
        if inc_molecule_graph and dimensionality == 0:
1✔
159
            component["molecule_graph"] = zero_d_graph_to_molecule_graph(bonded_structure, graph)
×
160

161
        component_structure = Structure.from_sites([bonded_structure.structure[n] for n in sorted(graph.nodes())])
1✔
162

163
        sorted_graph = nx.convert_node_labels_to_integers(graph, ordering="sorted")
1✔
164
        component_graph = StructureGraph(component_structure, graph_data=json_graph.adjacency_data(sorted_graph))
1✔
165
        component["structure_graph"] = component_graph
1✔
166

167
        components.append(component)
1✔
168
    return components
1✔
169

170

171
def calculate_dimensionality_of_site(bonded_structure, site_index, inc_vertices=False):
1✔
172
    """
173
    Calculates the dimensionality of the component containing the given site.
174

175
    Implements directly the modified breadth-first-search algorithm described in
176
    Algorithm 1 of:
177

178
    P. M. Larsen, M. Pandey, M. Strange, K. W. Jacobsen. Definition of a
179
    scoring parameter to identify low-dimensional materials components.
180
    Phys. Rev. Materials 3, 034003 (2019).
181

182
    Args:
183
        bonded_structure (StructureGraph): A structure with bonds, represented
184
            as a pymatgen structure graph. For example, generated using the
185
            CrystalNN.get_bonded_structure() method.
186
        site_index (int): The index of a site in the component of interest.
187
        inc_vertices (bool, optional): Whether to return the vertices (site
188
            images) of the component.
189

190
    Returns:
191
        (int or tuple): If inc_vertices is False, the dimensionality of the
192
        component will be returned as an int. If inc_vertices is true, the
193
        function will return a tuple of (dimensionality, vertices), where
194
        vertices is a list of tuples. E.g. [(0, 0, 0), (1, 1, 1)].
195
    """
196

197
    def neighbors(comp_index):
1✔
198
        return [(s.index, s.jimage) for s in bonded_structure.get_connected_sites(comp_index)]
1✔
199

200
    def rank(vertices):
1✔
201
        if len(vertices) == 0:
1✔
202
            return -1
×
203
        if len(vertices) == 1:
1✔
204
            return 0
1✔
205
        vertices = np.array(list(vertices))
1✔
206
        return np.linalg.matrix_rank(vertices[1:] - vertices[0])
1✔
207

208
    def rank_increase(seen, candidate):
1✔
209
        rank0 = len(seen) - 1
1✔
210
        rank1 = rank(seen | {candidate})
1✔
211
        return rank1 > rank0
1✔
212

213
    connected_sites = {i: neighbors(i) for i in range(bonded_structure.structure.num_sites)}
1✔
214

215
    seen_vertices = set()
1✔
216
    seen_comp_vertices = defaultdict(set)
1✔
217

218
    queue = [(site_index, (0, 0, 0))]
1✔
219
    while len(queue) > 0:
1✔
220
        comp_i, image_i = queue.pop(0)
1✔
221

222
        if (comp_i, image_i) in seen_vertices:
1✔
223
            continue
1✔
224
        seen_vertices.add((comp_i, image_i))
1✔
225

226
        if not rank_increase(seen_comp_vertices[comp_i], image_i):
1✔
227
            continue
1✔
228

229
        seen_comp_vertices[comp_i].add(image_i)
1✔
230

231
        for comp_j, image_j in connected_sites[comp_i]:
1✔
232
            image_j = tuple(np.add(image_j, image_i))
1✔
233

234
            if (comp_j, image_j) in seen_vertices:
1✔
235
                continue
1✔
236

237
            if rank_increase(seen_comp_vertices[comp_j], image_j):
1✔
238
                queue.append((comp_j, image_j))
1✔
239

240
    if inc_vertices:
1✔
241
        return (
1✔
242
            rank(seen_comp_vertices[site_index]),
243
            list(seen_comp_vertices[site_index]),
244
        )
245
    return rank(seen_comp_vertices[site_index])
1✔
246

247

248
def zero_d_graph_to_molecule_graph(bonded_structure, graph):
1✔
249
    """
250
    Converts a zero-dimensional networkx Graph object into a MoleculeGraph.
251

252
    Implements a similar breadth-first search to that in
253
    calculate_dimensionality_of_site().
254

255
    Args:
256
        bonded_structure (StructureGraph): A structure with bonds, represented
257
            as a pymatgen structure graph. For example, generated using the
258
            CrystalNN.get_bonded_structure() method.
259
        graph (nx.Graph): A networkx `Graph` object for the component of
260
            interest.
261

262
    Returns:
263
        (MoleculeGraph): A MoleculeGraph object of the component.
264
    """
265
    import networkx as nx
1✔
266

267
    seen_indices = []
1✔
268
    sites = []
1✔
269

270
    start_index = list(graph.nodes())[0]
1✔
271
    queue = [(start_index, (0, 0, 0), bonded_structure.structure[start_index])]
1✔
272
    while len(queue) > 0:
1✔
273
        comp_i, image_i, site_i = queue.pop(0)
1✔
274

275
        if comp_i in [x[0] for x in seen_indices]:
1✔
276
            raise ValueError("Graph component is not 0D")
1✔
277

278
        seen_indices.append((comp_i, image_i))
1✔
279
        sites.append(site_i)
1✔
280

281
        for site_j in bonded_structure.get_connected_sites(comp_i, jimage=image_i):
1✔
282
            if (site_j.index, site_j.jimage) not in seen_indices and (
1✔
283
                site_j.index,
284
                site_j.jimage,
285
                site_j.site,
286
            ) not in queue:
287
                queue.append((site_j.index, site_j.jimage, site_j.site))
1✔
288

289
    # sort the list of indices and the graph by index to make consistent
290
    indices_ordering = np.argsort([x[0] for x in seen_indices])
1✔
291
    sorted_sites = np.array(sites, dtype=object)[indices_ordering]
1✔
292
    sorted_graph = nx.convert_node_labels_to_integers(graph, ordering="sorted")
1✔
293
    mol = Molecule([s.specie for s in sorted_sites], [s.coords for s in sorted_sites])
1✔
294
    mol_graph = MoleculeGraph.with_edges(mol, nx.Graph(sorted_graph).edges())
1✔
295

296
    return mol_graph
1✔
297

298

299
def get_dimensionality_cheon(
1✔
300
    structure_raw,
301
    tolerance=0.45,
302
    ldict=None,
303
    standardize=True,
304
    larger_cell=False,
305
):
306
    """
307
    Algorithm for finding the dimensions of connected subunits in a structure.
308
    This method finds the dimensionality of the material even when the material
309
    is not layered along low-index planes, or does not have flat
310
    layers/molecular wires.
311

312
    Author: "Gowoon Cheon"
313
    Email: "gcheon@stanford.edu"
314

315
    See details at :
316

317
    Cheon, G.; Duerloo, K.-A. N.; Sendek, A. D.; Porter, C.; Chen, Y.; Reed,
318
    E. J. Data Mining for New Two- and One-Dimensional Weakly Bonded Solids and
319
    Lattice-Commensurate Heterostructures. Nano Lett. 2017.
320

321
    Args:
322
        structure_raw (Structure): A pymatgen Structure object.
323
        tolerance (float): length in angstroms used in finding bonded atoms.
324
            Two atoms are considered bonded if (radius of atom 1) + (radius of
325
            atom 2) + (tolerance) < (distance between atoms 1 and 2). Default
326
            value = 0.45, the value used by JMol and Cheon et al.
327
        ldict (dict): dictionary of bond lengths used in finding bonded atoms.
328
            Values from JMol are used as default
329
        standardize: works with conventional standard structures if True. It is
330
            recommended to keep this as True.
331
        larger_cell: tests with 3x3x3 supercell instead of 2x2x2. Testing with
332
            2x2x2 supercell is faster but misclassifies rare interpenetrated 3D
333
             structures. Testing with a larger cell circumvents this problem
334

335
    Returns:
336
        (str): dimension of the largest cluster as a string. If there are ions
337
        or molecules it returns 'intercalated ion/molecule'
338
    """
339
    if ldict is None:
1✔
340
        ldict = JmolNN().el_radius
1✔
341
    if standardize:
1✔
342
        structure = SpacegroupAnalyzer(structure_raw).get_conventional_standard_structure()
1✔
343
    else:
344
        structure = structure_raw
×
345
    structure_save = copy.copy(structure_raw)
1✔
346
    connected_list1 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
1✔
347
    max1, min1, clusters1 = find_clusters(structure, connected_list1)
1✔
348
    if larger_cell:
1✔
349
        structure.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 3]])
1✔
350
        connected_list3 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
1✔
351
        max3, min3, clusters3 = find_clusters(structure, connected_list3)
1✔
352
        if min3 == min1:
1✔
353
            if max3 == max1:
×
354
                dim = "0D"
×
355
            else:
356
                dim = "intercalated molecule"
×
357
        else:
358
            dim = np.log2(float(max3) / max1) / np.log2(3)
1✔
359
            if dim == int(dim):
1✔
360
                dim = str(int(dim)) + "D"
1✔
361
            else:
362
                return None
×
363
    else:
364
        structure.make_supercell([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
1✔
365
        connected_list2 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
1✔
366
        max2, min2, clusters2 = find_clusters(structure, connected_list2)
1✔
367
        if min2 == 1:
1✔
368
            dim = "intercalated ion"
1✔
369
        elif min2 == min1:
1✔
370
            if max2 == max1:
×
371
                dim = "0D"
×
372
            else:
373
                dim = "intercalated molecule"
×
374
        else:
375
            dim = np.log2(float(max2) / max1)
1✔
376
            if dim == int(dim):
1✔
377
                dim = str(int(dim)) + "D"
1✔
378
            else:
379
                structure = copy.copy(structure_save)
×
380
                structure.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 3]])
×
381
                connected_list3 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
×
382
                max3, min3, clusters3 = find_clusters(structure, connected_list3)
×
383
                if min3 == min2:
×
384
                    if max3 == max2:
×
385
                        dim = "0D"
×
386
                    else:
387
                        dim = "intercalated molecule"
×
388
                else:
389
                    dim = np.log2(float(max3) / max1) / np.log2(3)
×
390
                    if dim == int(dim):
×
391
                        dim = str(int(dim)) + "D"
×
392
                    else:
393
                        return None
×
394
    return dim
1✔
395

396

397
def find_connected_atoms(struct, tolerance=0.45, ldict=None):
1✔
398
    """
399
    Finds bonded atoms and returns a adjacency matrix of bonded atoms.
400

401
    Author: "Gowoon Cheon"
402
    Email: "gcheon@stanford.edu"
403

404
    Args:
405
        struct (Structure): Input structure
406
        tolerance: length in angstroms used in finding bonded atoms. Two atoms
407
            are considered bonded if (radius of atom 1) + (radius of atom 2) +
408
            (tolerance) < (distance between atoms 1 and 2). Default
409
            value = 0.45, the value used by JMol and Cheon et al.
410
        ldict: dictionary of bond lengths used in finding bonded atoms. Values
411
            from JMol are used as default
412

413
    Returns:
414
        (np.ndarray): A numpy array of shape (number of atoms, number of atoms);
415
        If any image of atom j is bonded to atom i with periodic boundary
416
        conditions, the matrix element [atom i, atom j] is 1.
417
    """
418
    if ldict is None:
1✔
419
        ldict = JmolNN().el_radius
×
420

421
    # pylint: disable=E1136
422
    n_atoms = len(struct.species)
1✔
423
    fc = np.array(struct.frac_coords)
1✔
424
    fc_copy = np.repeat(fc[:, :, np.newaxis], 27, axis=2)
1✔
425
    neighbors = np.array(list(itertools.product([0, 1, -1], [0, 1, -1], [0, 1, -1]))).T
1✔
426
    neighbors = np.repeat(neighbors[np.newaxis, :, :], 1, axis=0)
1✔
427
    fc_diff = fc_copy - neighbors
1✔
428
    species = list(map(str, struct.species))
1✔
429
    # in case of charged species
430
    for i, item in enumerate(species):
1✔
431
        if item not in ldict:
1✔
432
            species[i] = str(Species.from_string(item).element)
1✔
433
    latmat = struct.lattice.matrix
1✔
434
    connected_matrix = np.zeros((n_atoms, n_atoms))
1✔
435

436
    for i in range(n_atoms):
1✔
437
        for j in range(i + 1, n_atoms):
1✔
438
            max_bond_length = ldict[species[i]] + ldict[species[j]] + tolerance
1✔
439
            frac_diff = fc_diff[j] - fc_copy[i]
1✔
440
            distance_ij = np.dot(latmat.T, frac_diff)
1✔
441
            # print(np.linalg.norm(distance_ij,axis=0))
442
            if sum(np.linalg.norm(distance_ij, axis=0) < max_bond_length) > 0:
1✔
443
                connected_matrix[i, j] = 1
1✔
444
                connected_matrix[j, i] = 1
1✔
445
    return connected_matrix
1✔
446

447

448
def find_clusters(struct, connected_matrix):
1✔
449
    """
450
    Finds bonded clusters of atoms in the structure with periodic boundary
451
    conditions.
452

453
    If there are atoms that are not bonded to anything, returns [0,1,0]. (For
454
    faster computation time)
455

456
    Author: "Gowoon Cheon"
457
    Email: "gcheon@stanford.edu"
458

459
    Args:
460
        struct (Structure): Input structure
461
        connected_matrix: Must be made from the same structure with
462
            find_connected_atoms() function.
463

464
    Returns:
465
        max_cluster: the size of the largest cluster in the crystal structure
466
        min_cluster: the size of the smallest cluster in the crystal structure
467
        clusters: list of bonded clusters found here, clusters are formatted as
468
        sets of indices of atoms
469
    """
470
    n_atoms = len(struct.species)
1✔
471
    if n_atoms == 0:
1✔
472
        return [0, 0, 0]
×
473
    if 0 in np.sum(connected_matrix, axis=0):
1✔
474
        return [0, 1, 0]
1✔
475

476
    cluster_sizes = []
1✔
477
    clusters = []
1✔
478
    visited = [False for item in range(n_atoms)]
1✔
479
    connected_matrix += np.eye(len(connected_matrix))
1✔
480

481
    def visit(atom, atom_cluster):
1✔
482
        visited[atom] = True
1✔
483
        new_cluster = set(np.where(connected_matrix[atom] != 0)[0]) | atom_cluster
1✔
484
        atom_cluster = new_cluster
1✔
485
        for new_atom in atom_cluster:
1✔
486
            if not visited[new_atom]:
1✔
487
                visited[new_atom] = True
1✔
488
                atom_cluster = visit(new_atom, atom_cluster)
1✔
489
        return atom_cluster
1✔
490

491
    for i in range(n_atoms):
1✔
492
        if not visited[i]:
1✔
493
            atom_cluster = set()
1✔
494
            cluster = visit(i, atom_cluster)
1✔
495
            clusters.append(cluster)
1✔
496
            cluster_sizes.append(len(cluster))
1✔
497

498
    max_cluster = max(cluster_sizes)
1✔
499
    min_cluster = min(cluster_sizes)
1✔
500
    return [max_cluster, min_cluster, clusters]
1✔
501

502

503
def get_dimensionality_gorai(
1✔
504
    structure,
505
    max_hkl=2,
506
    el_radius_updates=None,
507
    min_slab_size=5,
508
    min_vacuum_size=5,
509
    standardize=True,
510
    bonds=None,
511
):
512
    """
513
    This method returns whether a structure is 3D, 2D (layered), or 1D (linear
514
    chains or molecules) according to the algorithm published in Gorai, P.,
515
    Toberer, E. & Stevanovic, V. Computational Identification of Promising
516
    Thermoelectric Materials Among Known Quasi-2D Binary Compounds. J. Mater.
517
    Chem. A 2, 4136 (2016).
518

519
    Note that a 1D structure detection might indicate problems in the bonding
520
    algorithm, particularly for ionic crystals (e.g., NaCl)
521

522
    Users can change the behavior of bonds detection by passing either
523
    el_radius_updates to update atomic radii for auto-detection of max bond
524
    distances, or bonds to explicitly specify max bond distances for atom pairs.
525
    Note that if you pass both, el_radius_updates are ignored.
526

527
    Args:
528
        structure: (Structure) structure to analyze dimensionality for
529
        max_hkl: (int) max index of planes to look for layers
530
        el_radius_updates: (dict) symbol->float to update atomic radii
531
        min_slab_size: (float) internal surface construction parameter
532
        min_vacuum_size: (float) internal surface construction parameter
533
        standardize (bool): whether to standardize the structure before
534
            analysis. Set to False only if you already have the structure in a
535
            convention where layers / chains will be along low <hkl> indexes.
536
        bonds ({(specie1, specie2): max_bond_dist}: bonds are
537
                specified as a dict of tuples: float of specie1, specie2
538
                and the max bonding distance. For example, PO4 groups may be
539
                defined as {("P", "O"): 3}.
540

541
    Returns: (int) the dimensionality of the structure - 1 (molecules/chains),
542
        2 (layered), or 3 (3D)
543

544
    """
545
    if standardize:
1✔
546
        structure = SpacegroupAnalyzer(structure).get_conventional_standard_structure()
1✔
547

548
    if not bonds:
1✔
549
        bonds = get_max_bond_lengths(structure, el_radius_updates)
1✔
550

551
    num_surfaces = 0
1✔
552
    for h in range(max_hkl):
1✔
553
        for k in range(max_hkl):
1✔
554
            for l in range(max_hkl):
1✔
555
                if max([h, k, l]) > 0 and num_surfaces < 2:
1✔
556
                    sg = SlabGenerator(
1✔
557
                        structure,
558
                        (h, k, l),
559
                        min_slab_size=min_slab_size,
560
                        min_vacuum_size=min_vacuum_size,
561
                    )
562
                    slabs = sg.get_slabs(bonds)
1✔
563
                    for _ in slabs:
1✔
564
                        num_surfaces += 1
1✔
565

566
    return 3 - min(num_surfaces, 2)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc