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

pyiron / structuretoolkit / 5628806564

pending completion
5628806564

push

github-actions

web-flow
Merge pull request #24 from pyiron/pyxtal

Add pyxtal wrapper

70 of 70 new or added lines in 3 files covered. (100.0%)

2218 of 2549 relevant lines covered (87.01%)

0.87 hits per line

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

95.24
/structuretoolkit/build/random.py
1
# coding: utf-8
2
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
3
# Distributed under the terms of "New BSD License", see the LICENSE file.
4

5
from typing import Union, List, Tuple
1✔
6
import warnings
1✔
7

8
try:
1✔
9
    from tqdm.auto import tqdm
1✔
10
except ImportError:
×
11
    tqdm = lambda x: x
×
12

13
from ase import Atoms
1✔
14
from structuretoolkit.common.helper import center_coordinates_in_unit_cell
1✔
15

16

17
def pyxtal(
1✔
18
    group: Union[int, List[int]],
19
    species: Tuple[str],
20
    num_ions: Tuple[int],
21
    dim=3,
22
    repeat=1,
23
    allow_exceptions=True,
24
    **kwargs,
25
) -> Union[Atoms, List[dict]]:
26
    """
27
    Generate random crystal structures with PyXtal.
28

29
    `group` must be between 1 and the largest possible value for the given dimensionality:
30
        dim=3 => 1 - 230 (space groups)
31
        dim=2 => 1 -  80 (layer groups)
32
        dim=1 => 1 -  75 (rod groups)
33
        dim=0 => 1 -  58 (point groups)
34

35
    When `group` is passed as a list of integers or `repeat>1`, generate multiple structures and return them in a list
36
    of dicts containing the keys `atoms`, `symmetry` and `repeat` for the ASE structure, the symmetry group
37
    number and which iteration it is, respectively.
38

39
    Args:
40
        group (list of int, or int): the symmetry group to generate or a list of them
41
        species (tuple of str): which species to include, defines the stoichiometry together with `num_ions`
42
        num_ions (tuple of int): how many of each species to include, defines the stoichiometry together with `species`
43
        dim (int): dimensionality of the symmetry group, 0 is point groups, 1 is rod groups, 2 is layer groups and 3 is space groups
44
        repeat (int): how many random structures to generate
45
        allow_exceptions (bool): when generating multiple structures, silence errors when the requested stoichiometry and symmetry group are incompatible
46
        **kwargs: passed to `pyxtal.pyxtal` function verbatim
47

48
    Returns:
49
        :class:`~.Atoms`: the generated structure, if repeat==1 and only one symmetry group is requested
50
        list of dict of all generated structures, if repeat>1 or multiple symmetry groups are requested
51

52
    Raises:
53
        ValueError: if `species` and `num_ions` are not of the same length
54
        ValueError: if stoichiometry and symmetry group are incompatible and allow_exceptions==False or only one structure is requested
55
    """
56
    from pyxtal import pyxtal as _pyxtal
1✔
57
    from pyxtal.msg import Comp_CompatibilityError
1✔
58

59
    if len(species) != len(num_ions):
1✔
60
        raise ValueError(
1✔
61
            "species and num_ions must be of same length, "
62
            f"not {species} and {num_ions}!"
63
        )
64
    stoich = "".join(f"{s}{n}" for s, n in zip(species, num_ions))
1✔
65

66
    def generate(group):
1✔
67
        s = _pyxtal()
1✔
68
        try:
1✔
69
            s.from_random(
1✔
70
                dim=dim, group=group, species=species, numIons=num_ions, **kwargs
71
            )
72
        except Comp_CompatibilityError as e:
1✔
73
            if not allow_exceptions:
1✔
74
                raise ValueError(
1✔
75
                    f"Symmetry group {group} incompatible with stoichiometry {stoich}!"
76
                ) from None
77
            else:
78
                return None
1✔
79
        s = s.to_ase()
1✔
80
        s = center_coordinates_in_unit_cell(structure=s)
1✔
81
        return s
1✔
82

83
    # return a single structure
84
    if repeat == 1 and isinstance(group, int):
1✔
85
        allow_exceptions = False
1✔
86
        return generate(group)
1✔
87
    else:
88
        structures = []
1✔
89
        if isinstance(group, int):
1✔
90
            group = [group]
1✔
91
        failed_groups = []
1✔
92
        for g in tqdm(group, desc="Spacegroups"):
1✔
93
            for i in range(repeat):
1✔
94
                s = generate(g)
1✔
95
                if s is None:
1✔
96
                    failed_groups.append(g)
1✔
97
                    continue
1✔
98
                structures.append({
1✔
99
                    "atoms": s,
100
                    "symmetry": g,
101
                    "repeat": i
102
                })
103
        if len(failed_groups) > 0:
1✔
104
            warnings.warn(
1✔
105
                f'Groups [{", ".join(map(str,failed_groups))}] could not be generated with stoichiometry {stoich}!'
106
            )
107
        return structures
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