biotite 1.1.0__cp313-cp313-macosx_11_0_arm64.whl → 1.3.0__cp313-cp313-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of biotite might be problematic. Click here for more details.

Files changed (160) hide show
  1. biotite/application/application.py +3 -3
  2. biotite/application/autodock/app.py +1 -1
  3. biotite/application/blast/webapp.py +1 -1
  4. biotite/application/clustalo/app.py +1 -1
  5. biotite/application/localapp.py +2 -2
  6. biotite/application/msaapp.py +10 -10
  7. biotite/application/muscle/app3.py +3 -3
  8. biotite/application/muscle/app5.py +3 -3
  9. biotite/application/sra/app.py +0 -5
  10. biotite/application/util.py +21 -1
  11. biotite/application/viennarna/rnaalifold.py +8 -8
  12. biotite/application/viennarna/rnaplot.py +10 -8
  13. biotite/application/viennarna/util.py +1 -1
  14. biotite/application/webapp.py +1 -1
  15. biotite/database/afdb/__init__.py +12 -0
  16. biotite/database/afdb/download.py +191 -0
  17. biotite/database/entrez/dbnames.py +10 -0
  18. biotite/database/entrez/download.py +9 -10
  19. biotite/database/entrez/key.py +1 -1
  20. biotite/database/entrez/query.py +5 -4
  21. biotite/database/pubchem/download.py +6 -6
  22. biotite/database/pubchem/error.py +10 -0
  23. biotite/database/pubchem/query.py +12 -23
  24. biotite/database/rcsb/download.py +3 -2
  25. biotite/database/rcsb/query.py +2 -3
  26. biotite/database/uniprot/check.py +2 -2
  27. biotite/database/uniprot/download.py +2 -5
  28. biotite/database/uniprot/query.py +3 -4
  29. biotite/file.py +14 -2
  30. biotite/interface/__init__.py +19 -0
  31. biotite/interface/openmm/__init__.py +20 -0
  32. biotite/interface/openmm/state.py +93 -0
  33. biotite/interface/openmm/system.py +227 -0
  34. biotite/interface/pymol/__init__.py +201 -0
  35. biotite/interface/pymol/cgo.py +346 -0
  36. biotite/interface/pymol/convert.py +185 -0
  37. biotite/interface/pymol/display.py +267 -0
  38. biotite/interface/pymol/object.py +1226 -0
  39. biotite/interface/pymol/shapes.py +178 -0
  40. biotite/interface/pymol/startup.py +169 -0
  41. biotite/interface/rdkit/__init__.py +19 -0
  42. biotite/interface/rdkit/mol.py +490 -0
  43. biotite/interface/version.py +94 -0
  44. biotite/interface/warning.py +19 -0
  45. biotite/sequence/align/__init__.py +0 -4
  46. biotite/sequence/align/alignment.py +33 -11
  47. biotite/sequence/align/banded.cpython-313-darwin.so +0 -0
  48. biotite/sequence/align/banded.pyx +22 -22
  49. biotite/sequence/align/cigar.py +2 -2
  50. biotite/sequence/align/kmeralphabet.cpython-313-darwin.so +0 -0
  51. biotite/sequence/align/kmeralphabet.pyx +2 -2
  52. biotite/sequence/align/kmersimilarity.cpython-313-darwin.so +0 -0
  53. biotite/sequence/align/kmertable.cpython-313-darwin.so +0 -0
  54. biotite/sequence/align/kmertable.pyx +6 -6
  55. biotite/sequence/align/localgapped.cpython-313-darwin.so +0 -0
  56. biotite/sequence/align/localgapped.pyx +47 -47
  57. biotite/sequence/align/localungapped.cpython-313-darwin.so +0 -0
  58. biotite/sequence/align/localungapped.pyx +10 -10
  59. biotite/sequence/align/matrix.py +12 -3
  60. biotite/sequence/align/multiple.cpython-313-darwin.so +0 -0
  61. biotite/sequence/align/multiple.pyx +1 -2
  62. biotite/sequence/align/pairwise.cpython-313-darwin.so +0 -0
  63. biotite/sequence/align/pairwise.pyx +37 -39
  64. biotite/sequence/align/permutation.cpython-313-darwin.so +0 -0
  65. biotite/sequence/align/selector.cpython-313-darwin.so +0 -0
  66. biotite/sequence/align/selector.pyx +2 -2
  67. biotite/sequence/align/statistics.py +1 -1
  68. biotite/sequence/align/tracetable.cpython-313-darwin.so +0 -0
  69. biotite/sequence/alphabet.py +2 -2
  70. biotite/sequence/annotation.py +19 -13
  71. biotite/sequence/codec.cpython-313-darwin.so +0 -0
  72. biotite/sequence/codon.py +1 -2
  73. biotite/sequence/graphics/alignment.py +25 -39
  74. biotite/sequence/graphics/dendrogram.py +4 -2
  75. biotite/sequence/graphics/features.py +2 -2
  76. biotite/sequence/graphics/logo.py +10 -12
  77. biotite/sequence/io/fasta/convert.py +1 -2
  78. biotite/sequence/io/fasta/file.py +1 -1
  79. biotite/sequence/io/fastq/file.py +3 -3
  80. biotite/sequence/io/genbank/file.py +3 -3
  81. biotite/sequence/io/genbank/sequence.py +2 -0
  82. biotite/sequence/io/gff/convert.py +1 -1
  83. biotite/sequence/io/gff/file.py +1 -2
  84. biotite/sequence/phylo/nj.cpython-313-darwin.so +0 -0
  85. biotite/sequence/phylo/tree.cpython-313-darwin.so +0 -0
  86. biotite/sequence/phylo/upgma.cpython-313-darwin.so +0 -0
  87. biotite/sequence/profile.py +19 -25
  88. biotite/sequence/search.py +0 -1
  89. biotite/sequence/seqtypes.py +12 -5
  90. biotite/sequence/sequence.py +1 -2
  91. biotite/structure/__init__.py +2 -0
  92. biotite/structure/alphabet/i3d.py +1 -2
  93. biotite/structure/alphabet/pb.py +1 -2
  94. biotite/structure/alphabet/unkerasify.py +8 -2
  95. biotite/structure/atoms.py +35 -27
  96. biotite/structure/basepairs.py +39 -40
  97. biotite/structure/bonds.cpython-313-darwin.so +0 -0
  98. biotite/structure/bonds.pyx +8 -5
  99. biotite/structure/box.py +159 -23
  100. biotite/structure/celllist.cpython-313-darwin.so +0 -0
  101. biotite/structure/celllist.pyx +83 -68
  102. biotite/structure/chains.py +17 -55
  103. biotite/structure/charges.cpython-313-darwin.so +0 -0
  104. biotite/structure/compare.py +420 -13
  105. biotite/structure/density.py +1 -1
  106. biotite/structure/dotbracket.py +31 -32
  107. biotite/structure/filter.py +8 -8
  108. biotite/structure/geometry.py +15 -15
  109. biotite/structure/graphics/rna.py +19 -16
  110. biotite/structure/hbond.py +18 -21
  111. biotite/structure/info/atoms.py +11 -2
  112. biotite/structure/info/ccd.py +0 -2
  113. biotite/structure/info/components.bcif +0 -0
  114. biotite/structure/info/groups.py +0 -3
  115. biotite/structure/info/misc.py +0 -1
  116. biotite/structure/info/radii.py +92 -22
  117. biotite/structure/info/standardize.py +1 -2
  118. biotite/structure/integrity.py +4 -6
  119. biotite/structure/io/general.py +2 -2
  120. biotite/structure/io/gro/file.py +8 -9
  121. biotite/structure/io/mol/convert.py +1 -1
  122. biotite/structure/io/mol/ctab.py +33 -28
  123. biotite/structure/io/mol/mol.py +1 -1
  124. biotite/structure/io/mol/sdf.py +39 -13
  125. biotite/structure/io/pdb/convert.py +86 -5
  126. biotite/structure/io/pdb/file.py +90 -24
  127. biotite/structure/io/pdb/hybrid36.cpython-313-darwin.so +0 -0
  128. biotite/structure/io/pdbqt/file.py +4 -4
  129. biotite/structure/io/pdbx/bcif.py +22 -7
  130. biotite/structure/io/pdbx/cif.py +20 -7
  131. biotite/structure/io/pdbx/component.py +6 -0
  132. biotite/structure/io/pdbx/compress.py +71 -34
  133. biotite/structure/io/pdbx/convert.py +429 -77
  134. biotite/structure/io/pdbx/encoding.cpython-313-darwin.so +0 -0
  135. biotite/structure/io/pdbx/encoding.pyx +39 -23
  136. biotite/structure/io/trajfile.py +9 -6
  137. biotite/structure/io/util.py +38 -0
  138. biotite/structure/mechanics.py +0 -1
  139. biotite/structure/molecules.py +0 -15
  140. biotite/structure/pseudoknots.py +13 -19
  141. biotite/structure/repair.py +2 -4
  142. biotite/structure/residues.py +20 -48
  143. biotite/structure/rings.py +335 -0
  144. biotite/structure/sasa.cpython-313-darwin.so +0 -0
  145. biotite/structure/sasa.pyx +30 -30
  146. biotite/structure/segments.py +123 -9
  147. biotite/structure/sequence.py +0 -1
  148. biotite/structure/spacegroups.json +1567 -0
  149. biotite/structure/spacegroups.license +26 -0
  150. biotite/structure/sse.py +0 -2
  151. biotite/structure/superimpose.py +75 -253
  152. biotite/structure/tm.py +581 -0
  153. biotite/structure/transform.py +232 -26
  154. biotite/structure/util.py +3 -3
  155. biotite/version.py +9 -4
  156. biotite/visualize.py +111 -1
  157. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/METADATA +8 -36
  158. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/RECORD +160 -138
  159. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/WHEEL +3 -1
  160. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/licenses/LICENSE.rst +0 -0
@@ -338,8 +338,8 @@ def base_pairs_edge(atom_array, base_pairs):
338
338
 
339
339
  See Also
340
340
  --------
341
- base_pairs
342
- base_pairs_glycosidic_bond
341
+ base_pairs : Get the base pairs required for this function.
342
+ base_pairs_glycosidic_bond : Determine the orientation for each base pair.
343
343
 
344
344
  Notes
345
345
  -----
@@ -351,6 +351,11 @@ def base_pairs_edge(atom_array, base_pairs):
351
351
  The edge returned always corresponds to the edge with the most
352
352
  hydrogen bonding interactions.
353
353
 
354
+ References
355
+ ----------
356
+
357
+ .. footbibliography::
358
+
354
359
  Examples
355
360
  --------
356
361
  Compute the interacting base edges for the dna helix with the PDB
@@ -392,11 +397,6 @@ def base_pairs_edge(atom_array, base_pairs):
392
397
  WATSON_CRICK to WATSON_CRICK
393
398
  WATSON_CRICK to WATSON_CRICK
394
399
  WATSON_CRICK to WATSON_CRICK
395
-
396
- References
397
- ----------
398
-
399
- .. footbibliography::
400
400
  """
401
401
  # Result-``ndarray`` matches the dimensions of the input array
402
402
  results = np.zeros_like(base_pairs, dtype="uint8")
@@ -494,7 +494,7 @@ def base_pairs_glycosidic_bond(atom_array, base_pairs):
494
494
 
495
495
  Returns
496
496
  -------
497
- results : ndarray, dtype=edge, shape=(n,)
497
+ results : ndarray, dtype=int, shape=(n,)
498
498
  The ``ndarray`` has the same dimensions as ``base_pairs``. Each
499
499
  cell corresponds to the interacting edge of the referenced base
500
500
  in ``base_pairs``.
@@ -504,15 +504,20 @@ def base_pairs_glycosidic_bond(atom_array, base_pairs):
504
504
 
505
505
  See Also
506
506
  --------
507
- base_pairs
508
- base_pairs_edge
509
- GlycosidicBond
507
+ base_pairs : Get the base pairs required for this function.
508
+ base_pairs_edge : Determine the interacting edge for each base pair.
509
+ GlycosidicBond : The Enum type for interpretation of the return value.
510
510
 
511
511
  Notes
512
512
  -----
513
513
  The orientation is found using the geometric centers of the bases
514
514
  and the glycosidic bonds as described in :footcite:`Yang2003`.
515
515
 
516
+ References
517
+ ----------
518
+
519
+ .. footbibliography::
520
+
516
521
  Examples
517
522
  --------
518
523
  Compute the glycosidic bond orientations for the dna helix with the
@@ -544,11 +549,6 @@ def base_pairs_glycosidic_bond(atom_array, base_pairs):
544
549
  CIS
545
550
  CIS
546
551
  CIS
547
-
548
- References
549
- ----------
550
-
551
- .. footbibliography::
552
552
  """
553
553
  results = np.zeros(len(base_pairs), dtype="uint8")
554
554
 
@@ -638,7 +638,7 @@ def base_stacking(atom_array, min_atoms_per_base=3):
638
638
  ----------
639
639
  atom_array : AtomArray
640
640
  The :class:`AtomArray` to find stacked bases in.
641
- min_atoms_per_base : integer, optional (default: 3)
641
+ min_atoms_per_base : integer, optional
642
642
  The number of atoms a nucleotides' base must have to be
643
643
  considered a candidate for a stacking interaction.
644
644
 
@@ -654,6 +654,11 @@ def base_stacking(atom_array, min_atoms_per_base=3):
654
654
  Please note that ring normal vectors are assumed to be equal to the
655
655
  base normal vectors.
656
656
 
657
+ References
658
+ ----------
659
+
660
+ .. footbibliography::
661
+
657
662
  Examples
658
663
  --------
659
664
  Compute the stacking interactions for a DNA-double-helix (PDB ID
@@ -685,11 +690,6 @@ def base_stacking(atom_array, min_atoms_per_base=3):
685
690
  [21 22]
686
691
  [22 23]
687
692
  [23 24]]
688
-
689
- References
690
- ----------
691
-
692
- .. footbibliography::
693
693
  """
694
694
  # Get the stacking candidates according to a cutoff distance, where
695
695
  # each base is identified as the first index of its respective
@@ -783,10 +783,10 @@ def base_pairs(atom_array, min_atoms_per_base=3, unique=True):
783
783
  ----------
784
784
  atom_array : AtomArray
785
785
  The :class:`AtomArray` to find base pairs in.
786
- min_atoms_per_base : integer, optional (default: 3)
786
+ min_atoms_per_base : integer, optional
787
787
  The number of atoms a nucleotides' base must have to be
788
788
  considered a candidate for a base pair.
789
- unique : bool, optional (default: True)
789
+ unique : bool, optional
790
790
  If ``True``, each base is assumed to be only paired with one
791
791
  other base. If multiple pairings are plausible, the pairing with
792
792
  the most hydrogen bonds is selected.
@@ -833,6 +833,11 @@ def base_pairs(atom_array, min_atoms_per_base=3, unique=True):
833
833
  1.00Å and 0.96Å respectively. Thus, including some buffer, a 3.6Å
834
834
  cutoff should cover all hydrogen bonds.
835
835
 
836
+ References
837
+ ----------
838
+
839
+ .. footbibliography::
840
+
836
841
  Examples
837
842
  --------
838
843
  Compute the base pairs for the structure with the PDB ID 1QXB:
@@ -855,11 +860,6 @@ def base_pairs(atom_array, min_atoms_per_base=3, unique=True):
855
860
  ['DG' 'DC']
856
861
  ['DC' 'DG']
857
862
  ['DG' 'DC']]
858
-
859
- References
860
- ----------
861
-
862
- .. footbibliography::
863
863
  """
864
864
 
865
865
  # Get the nucleotides for the given atom_array
@@ -1203,26 +1203,25 @@ def map_nucleotide(residue, min_atoms_per_base=3, rmsd_cutoff=0.28):
1203
1203
  If a different nucleotide is given, it is mapped to the best
1204
1204
  fitting base using the algorithm described below.
1205
1205
 
1206
- (i) The number of matching atom names with the reference bases is
1207
- counted. If the number of matching atoms with all reference
1208
- bases is less than the specified `min_atoms_per_base`
1209
- (default 3) the nucleotide cannot be mapped and ``None`` is
1206
+ (i) The number of matching atom names with the reference bases is counted.
1207
+ If the number of matching atoms with all reference bases is less than the
1208
+ specified `min_atoms_per_base` the nucleotide cannot be mapped and ``None`` is
1210
1209
  returned.
1211
1210
 
1212
- (ii) The bases with maximum number of matching atoms are selected
1213
- and superimposed with each reference. The base with lowest RMSD
1214
- is chosen. If the RMSD is more than the specified
1215
- `rmsd_cutoff` (default 0.28) the nucleotide cannot be mapped
1216
- and ``None`` is returned.
1211
+ (ii) The bases with maximum number of matching atoms are selected and superimposed
1212
+ with each reference.
1213
+ The base with lowest RMSD is chosen.
1214
+ If the RMSD is more than the specified `rmsd_cutoff`, the nucleotide cannot be
1215
+ mapped and ``None`` is returned.
1217
1216
 
1218
1217
  Parameters
1219
1218
  ----------
1220
1219
  residue : AtomArray
1221
1220
  The nucleotide to be mapped.
1222
- min_atoms_per_base : int, optional (default: 3)
1221
+ min_atoms_per_base : int, optional
1223
1222
  The number of atoms the residue must have in common with the
1224
1223
  reference.
1225
- rmsd_cutoff : float, optional (default: 0.28)
1224
+ rmsd_cutoff : float, optional
1226
1225
  The maximum RSMD that is allowed for a mapping to occur.
1227
1226
 
1228
1227
  Returns
@@ -60,6 +60,7 @@ class BondType(IntEnum):
60
60
  - `AROMATIC_SINGLE` - Aromatic bond with a single formal bond
61
61
  - `AROMATIC_DOUBLE` - Aromatic bond with a double formal bond
62
62
  - `AROMATIC_TRIPLE` - Aromatic bond with a triple formal bond
63
+ - `AROMATIC` - Aromatic bond without specification of the formal bond
63
64
  - `COORDINATION` - Coordination complex involving a metal atom
64
65
  """
65
66
  ANY = 0
@@ -71,6 +72,7 @@ class BondType(IntEnum):
71
72
  AROMATIC_DOUBLE = 6
72
73
  AROMATIC_TRIPLE = 7
73
74
  COORDINATION = 8
75
+ AROMATIC = 9
74
76
 
75
77
 
76
78
  def without_aromaticity(self):
@@ -97,6 +99,8 @@ class BondType(IntEnum):
97
99
  return BondType.DOUBLE
98
100
  elif self == BondType.AROMATIC_TRIPLE:
99
101
  return BondType.TRIPLE
102
+ elif self == BondType.AROMATIC:
103
+ return BondType.ANY
100
104
  else:
101
105
  return self
102
106
 
@@ -517,7 +521,8 @@ class BondList(Copyable):
517
521
  for aromatic_type, non_aromatic_type in [
518
522
  (BondType.AROMATIC_SINGLE, BondType.SINGLE),
519
523
  (BondType.AROMATIC_DOUBLE, BondType.DOUBLE),
520
- (BondType.AROMATIC_TRIPLE, BondType.TRIPLE)
524
+ (BondType.AROMATIC_TRIPLE, BondType.TRIPLE),
525
+ (BondType.AROMATIC, BondType.ANY),
521
526
  ]:
522
527
  bond_types[bond_types == aromatic_type] = non_aromatic_type
523
528
 
@@ -938,7 +943,6 @@ class BondList(Copyable):
938
943
  ----------
939
944
  atom_index : int
940
945
  The index of the atom whose bonds should be removed.
941
-
942
946
  """
943
947
  cdef uint32 index = _to_positive_index(atom_index, self._atom_count)
944
948
 
@@ -1478,7 +1482,7 @@ def connect_via_distances(atoms, dict distance_range=None, bint inter_residue=Tr
1478
1482
  BondList
1479
1483
  The created bond list.
1480
1484
 
1481
- See also
1485
+ See Also
1482
1486
  --------
1483
1487
  connect_via_residue_names
1484
1488
 
@@ -1617,7 +1621,7 @@ def connect_via_residue_names(atoms, bint inter_residue=True,
1617
1621
  No bonds are added for residues that are not found in
1618
1622
  ``components.cif``.
1619
1623
 
1620
- See also
1624
+ See Also
1621
1625
  --------
1622
1626
  connect_via_distances
1623
1627
 
@@ -1659,7 +1663,6 @@ def connect_via_residue_names(atoms, bint inter_residue=True,
1659
1663
  ('OXT', 'HXT'): <BondType.SINGLE: 1>},
1660
1664
  'XYZ': {('A', 'B'): <BondType.SINGLE: 1>,
1661
1665
  ('B', 'C'): <BondType.SINGLE: 1>}}
1662
-
1663
1666
  """
1664
1667
  from .info.bonds import bonds_in_residue
1665
1668
  from .residues import get_residue_starts
biotite/structure/box.py CHANGED
@@ -4,12 +4,13 @@
4
4
 
5
5
  """
6
6
  Functions related to working with the simulation box or unit cell
7
- of a structure
7
+ of a structure.
8
8
  """
9
9
 
10
10
  __name__ = "biotite.structure"
11
11
  __author__ = "Patrick Kunzmann"
12
12
  __all__ = [
13
+ "space_group_transforms",
13
14
  "vectors_from_unitcell",
14
15
  "unitcell_from_vectors",
15
16
  "box_volume",
@@ -23,16 +24,127 @@ __all__ = [
23
24
  "is_orthogonal",
24
25
  ]
25
26
 
27
+ import functools
28
+ import json
26
29
  from numbers import Integral
30
+ from pathlib import Path
27
31
  import numpy as np
28
32
  import numpy.linalg as linalg
29
33
  from biotite.structure.atoms import repeat
30
34
  from biotite.structure.chains import get_chain_masks, get_chain_starts
31
35
  from biotite.structure.error import BadStructureError
32
36
  from biotite.structure.molecules import get_molecule_masks
37
+ from biotite.structure.transform import AffineTransformation
33
38
  from biotite.structure.util import vector_dot
34
39
 
35
40
 
41
+ def space_group_transforms(space_group):
42
+ """
43
+ Get the coordinate transformations for a given space group.
44
+
45
+ Applying each transformation to a structure (in fractional coordinates) reproduces
46
+ the entire unit cell.
47
+
48
+ Parameters
49
+ ----------
50
+ space_group : str or int
51
+ The space group name (full *Hermann-Mauguin* symbol) or
52
+ *International Table*'s number.
53
+
54
+ Returns
55
+ -------
56
+ transformations : list of AffineTransformation
57
+ The transformations that creates the symmetric copies of a structure in a unit
58
+ cell of the given space group.
59
+ Note that the transformations need to be applied to coordinates in fractions
60
+ of the unit cell and also return fractional coordinates, when applied.
61
+
62
+ See Also
63
+ --------
64
+ coord_to_fraction : Used to convert to fractional coordinates.
65
+ fraction_to_coord : Used to convert back to Cartesian coordinates.
66
+
67
+ Examples
68
+ --------
69
+
70
+ >>> transforms = space_group_transforms("P 21 21 21")
71
+ >>> for transform in transforms:
72
+ ... print(transform.rotation)
73
+ ... print(transform.target_translation)
74
+ ... print()
75
+ [[[1. 0. 0.]
76
+ [0. 1. 0.]
77
+ [0. 0. 1.]]]
78
+ [[0. 0. 0.]]
79
+ <BLANKLINE>
80
+ [[[-1. 0. 0.]
81
+ [ 0. -1. 0.]
82
+ [ 0. 0. 1.]]]
83
+ [[0.5 0.0 0.5]]
84
+ <BLANKLINE>
85
+ [[[-1. 0. 0.]
86
+ [ 0. 1. 0.]
87
+ [ 0. 0. -1.]]]
88
+ [[0.0 0.5 0.5]]
89
+ <BLANKLINE>
90
+ [[[ 1. 0. 0.]
91
+ [ 0. -1. 0.]
92
+ [ 0. 0. -1.]]]
93
+ [[0.5 0.5 0.0]]
94
+ <BLANKLINE>
95
+
96
+ Reproduce the unit cell for some coordinates (in this case only one atom).
97
+
98
+ >>> asym_coord = np.array([[1.0, 2.0, 3.0]])
99
+ >>> box = np.eye(3) * 10
100
+ >>> transforms = space_group_transforms("P 21 21 21")
101
+ >>> # Apply the transformations to fractional coordinates of the asymmetric unit
102
+ >>> unit_cell = np.concatenate(
103
+ ... [
104
+ ... fraction_to_coord(transform.apply(coord_to_fraction(asym_coord, box)), box)
105
+ ... for transform in transforms
106
+ ... ]
107
+ ... )
108
+ >>> print(unit_cell)
109
+ [[ 1. 2. 3.]
110
+ [ 4. -2. 8.]
111
+ [-1. 7. 2.]
112
+ [ 6. 3. -3.]]
113
+ """
114
+ transformation_data = _get_transformation_data()
115
+
116
+ if isinstance(space_group, str):
117
+ try:
118
+ space_group_index = transformation_data["group_names"][space_group]
119
+ except KeyError:
120
+ raise ValueError(f"Space group '{space_group}' does not exist")
121
+ else:
122
+ try:
123
+ space_group_index = transformation_data["group_numbers"][str(space_group)]
124
+ except KeyError:
125
+ raise ValueError(f"Space group number {space_group} does not exist")
126
+
127
+ space_group = transformation_data["space_groups"][space_group_index]
128
+ transformations = []
129
+ for transformation_index in space_group:
130
+ matrix = np.zeros((3, 3), dtype=np.float32)
131
+ translation = np.zeros(3, dtype=np.float32)
132
+ for i, part_index in enumerate(
133
+ transformation_data["transformations"][transformation_index]
134
+ ):
135
+ part = transformation_data["transformation_parts"][part_index]
136
+ matrix[i, :] = part[:3]
137
+ translation[i] = part[3]
138
+ transformations.append(
139
+ AffineTransformation(
140
+ center_translation=np.zeros(3, dtype=np.float32),
141
+ rotation=matrix,
142
+ target_translation=translation,
143
+ )
144
+ )
145
+ return transformations
146
+
147
+
36
148
  def vectors_from_unitcell(len_a, len_b, len_c, alpha, beta, gamma):
37
149
  """
38
150
  Calculate the three vectors spanning a box from the unit cell
@@ -45,10 +157,10 @@ def vectors_from_unitcell(len_a, len_b, len_c, alpha, beta, gamma):
45
157
  ----------
46
158
  len_a, len_b, len_c : float
47
159
  The lengths of the three box/unit cell vectors *a*, *b* and *c*.
48
- alpha, beta, gamma:
160
+ alpha, beta, gamma : float
49
161
  The angles between the box vectors in radians.
50
162
  *alpha* is the angle between *b* and *c*,
51
- *beta* between *a* and *c*, *gamma* between *a* and *b*
163
+ *beta* between *a* and *c*, *gamma* between *a* and *b*.
52
164
 
53
165
  Returns
54
166
  -------
@@ -58,9 +170,9 @@ def vectors_from_unitcell(len_a, len_b, len_c, alpha, beta, gamma):
58
170
  The value can be directly used as :attr:`box` attribute in an
59
171
  atom array.
60
172
 
61
- See also
173
+ See Also
62
174
  --------
63
- unitcell_from_vectors
175
+ unitcell_from_vectors : The reverse operation.
64
176
  """
65
177
  a_x = len_a
66
178
  b_x = len_b * np.cos(gamma)
@@ -87,7 +199,7 @@ def unitcell_from_vectors(box):
87
199
  Parameters
88
200
  ----------
89
201
  box : ndarray, shape=(3,3)
90
- The box vectors
202
+ The box vectors.
91
203
 
92
204
  Returns
93
205
  -------
@@ -96,9 +208,9 @@ def unitcell_from_vectors(box):
96
208
  alpha, beta, gamma : float
97
209
  The angles between the box vectors in radians.
98
210
 
99
- See also
211
+ See Also
100
212
  --------
101
- vectors_from_unitcell
213
+ vectors_from_unitcell : The reverse operation.
102
214
  """
103
215
  a = box[0]
104
216
  b = box[1]
@@ -124,6 +236,7 @@ def box_volume(box):
124
236
  Returns
125
237
  -------
126
238
  volume : float or ndarray, shape=(m,)
239
+ The volume(s) of the given box(es).
127
240
  """
128
241
  # Using the triple product
129
242
  return np.abs(linalg.det(box))
@@ -159,14 +272,16 @@ def repeat_box(atoms, amount=1):
159
272
  The repeated atoms.
160
273
  Includes the original atoms (central box) in the beginning of
161
274
  the atom array (stack).
275
+ If the input contains the ``sym_id`` annotation, the IDs are continued in the
276
+ repeated atoms, i.e. they do not start at 0 again.
162
277
  indices : ndarray, dtype=int, shape=(n,3)
163
278
  Indices to the atoms in the original atom array (stack).
164
279
  Equal to
165
280
  ``numpy.tile(np.arange(atoms.array_length()), (1 + 2 * amount) ** 3)``.
166
281
 
167
- See also
282
+ See Also
168
283
  --------
169
- repeat_box_coord
284
+ repeat_box_coord : Variant that acts directly on coordinates.
170
285
 
171
286
  Examples
172
287
  --------
@@ -233,6 +348,15 @@ def repeat_box(atoms, amount=1):
233
348
  >>> print(indices)
234
349
  [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
235
350
  1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1]
351
+
352
+ The ``sym_id`` is continued in the repeated atoms.
353
+
354
+ >>> array.set_annotation("sym_id", np.array([0, 0]))
355
+ >>> repeated, indices = repeat_box(array)
356
+ >>> print(repeated.sym_id)
357
+ [ 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11
358
+ 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23
359
+ 24 24 25 25 26 26]
236
360
  """
237
361
  if atoms.box is None:
238
362
  raise BadStructureError("Structure has no box")
@@ -246,7 +370,16 @@ def repeat_box(atoms, amount=1):
246
370
  atoms.stack_depth(), -1, atoms.array_length(), 3
247
371
  )
248
372
  repeat_coord = np.swapaxes(repeat_coord, 0, 1)
249
- return repeat(atoms, repeat_coord), indices
373
+
374
+ repeated_atoms = repeat(atoms, repeat_coord)
375
+ if "sym_id" in atoms.get_annotation_categories():
376
+ max_sym_id = np.max(atoms.sym_id)
377
+ # for the first repeat, (max_sym_id + 1) is added,
378
+ # for the second repeat 2*(max_sym_id + 1) etc.
379
+ repeated_atoms.sym_id += (max_sym_id + 1) * (
380
+ np.arange(repeated_atoms.array_length()) // atoms.array_length()
381
+ )
382
+ return repeated_atoms, indices
250
383
 
251
384
 
252
385
  def repeat_box_coord(coord, box, amount=1):
@@ -383,9 +516,9 @@ def remove_pbc(atoms, selection=None):
383
516
  The input structure with removed segmentation over periodic
384
517
  boundaries.
385
518
 
386
- See also
519
+ See Also
387
520
  --------
388
- remove_pbc_from_coord
521
+ remove_pbc_from_coord : Variant that acts directly on coordinates.
389
522
 
390
523
  Notes
391
524
  -----
@@ -430,8 +563,6 @@ def remove_pbc_from_coord(coord, box):
430
563
  is moved inside the box.
431
564
  All other coordinates are assembled relative to the origin by using
432
565
  the displacement coordinates in adjacent array positions.
433
- Basically, this function performs the reverse action of
434
- :func:`move_inside_box()`.
435
566
 
436
567
  Parameters
437
568
  ----------
@@ -447,10 +578,9 @@ def remove_pbc_from_coord(coord, box):
447
578
  sanitized_coord : ndarray, dtype=float, shape=(m,n,3) or shape=(n,3)
448
579
  The reassembled coordinates.
449
580
 
450
- See also
581
+ See Also
451
582
  --------
452
- remove_pbc_from_coord
453
- move_inside_box
583
+ move_inside_box : The reverse operation.
454
584
 
455
585
  Notes
456
586
  -----
@@ -501,9 +631,9 @@ def coord_to_fraction(coord, box):
501
631
  fraction : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
502
632
  The fractions of the box vectors.
503
633
 
504
- See also
634
+ See Also
505
635
  --------
506
- fraction_to_coord
636
+ fraction_to_coord : The reverse operation.
507
637
 
508
638
  Examples
509
639
  --------
@@ -548,9 +678,9 @@ def fraction_to_coord(fraction, box):
548
678
  coord : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
549
679
  The coordinates.
550
680
 
551
- See also
681
+ See Also
552
682
  --------
553
- coord_to_fraction
683
+ coord_to_fraction : The reverse operation.
554
684
  """
555
685
  return np.matmul(fraction, box)
556
686
 
@@ -570,7 +700,7 @@ def is_orthogonal(box):
570
700
  Returns
571
701
  -------
572
702
  is_orthgonal : bool or ndarray, shape=(m,), dtype=bool
573
- True, if the box vectors are orthogonal, false otherwise
703
+ True, if the box vectors are orthogonal, false otherwise.
574
704
 
575
705
  Notes
576
706
  -----
@@ -586,3 +716,9 @@ def is_orthogonal(box):
586
716
  & (np.abs(vector_dot(box[..., 0, :], box[..., 2, :])) < tol)
587
717
  & (np.abs(vector_dot(box[..., 1, :], box[..., 2, :])) < tol)
588
718
  )
719
+
720
+
721
+ @functools.cache
722
+ def _get_transformation_data():
723
+ with open(Path(__file__).parent / "spacegroups.json") as file:
724
+ return json.load(file)