Coverage for /builds/ase/ase/ase/lattice/triclinic.py: 95.92%

49 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-08-02 00:12 +0000

1# fmt: off 

2 

3"""Function-like object creating triclinic lattices. 

4 

5The following lattice creator is defined: 

6 Triclinic 

7""" 

8 

9import numpy as np 

10 

11from ase.data import reference_states as _refstate 

12from ase.lattice.bravais import Bravais 

13 

14 

15class TriclinicFactory(Bravais): 

16 "A factory for creating triclinic lattices." 

17 

18 # The name of the crystal structure in ChemicalElements 

19 xtal_name = "triclinic" 

20 

21 # The natural basis vectors of the crystal structure 

22 int_basis = np.array([[1, 0, 0], 

23 [0, 1, 0], 

24 [0, 0, 1]]) 

25 basis_factor = 1.0 

26 

27 # Converts the natural basis back to the crystallographic basis 

28 inverse_basis = np.array([[1, 0, 0], 

29 [0, 1, 0], 

30 [0, 0, 1]]) 

31 inverse_basis_factor = 1.0 

32 

33 def get_lattice_constant(self): 

34 """Get the lattice constant of an element with triclinic 

35 crystal structure.""" 

36 if _refstate[self.atomicnumber]['symmetry'] != self.xtal_name: 

37 raise ValueError(('Cannot guess the %s lattice constant of' 

38 + ' an element with crystal structure %s.') 

39 % (self.xtal_name, 

40 _refstate[self.atomicnumber]['symmetry'])) 

41 return _refstate[self.atomicnumber].copy() 

42 

43 def make_crystal_basis(self): 

44 """Make the basis matrix for the crystal unit cell and the system 

45 unit cell.""" 

46 lattice = self.latticeconstant 

47 if isinstance(lattice, type({})): 

48 a = lattice['a'] 

49 try: 

50 b = lattice['b'] 

51 except KeyError: 

52 b = a * lattice['b/a'] 

53 try: 

54 c = lattice['c'] 

55 except KeyError: 

56 c = a * lattice['c/a'] 

57 alpha = lattice['alpha'] 

58 beta = lattice['beta'] 

59 gamma = lattice['gamma'] 

60 else: 

61 if len(lattice) == 6: 

62 (a, b, c, alpha, beta, gamma) = lattice 

63 else: 

64 raise ValueError( 

65 "Improper lattice constants for triclinic crystal.") 

66 

67 degree = np.pi / 180.0 

68 cosa = np.cos(alpha * degree) 

69 cosb = np.cos(beta * degree) 

70 sinb = np.sin(beta * degree) 

71 cosg = np.cos(gamma * degree) 

72 sing = np.sin(gamma * degree) 

73 lattice = np.array( 

74 [[a, 0, 0], 

75 [b * cosg, b * sing, 0], 

76 [c * cosb, c * (cosa - cosb * cosg) / sing, 

77 c * np.sqrt(sinb**2 - ((cosa - cosb * cosg) / sing)**2)]]) 

78 self.latticeconstant = lattice 

79 self.miller_basis = lattice 

80 self.crystal_basis = (self.basis_factor * 

81 np.dot(self.int_basis, lattice)) 

82 self.basis = np.dot(self.directions, self.crystal_basis) 

83 assert abs(np.dot(lattice[0], lattice[1]) - a * b * cosg) < 1e-5 

84 assert abs(np.dot(lattice[0], lattice[2]) - a * c * cosb) < 1e-5 

85 assert abs(np.dot(lattice[1], lattice[2]) - b * c * cosa) < 1e-5 

86 assert abs(np.dot(lattice[0], lattice[0]) - a * a) < 1e-5 

87 assert abs(np.dot(lattice[1], lattice[1]) - b * b) < 1e-5 

88 assert abs(np.dot(lattice[2], lattice[2]) - c * c) < 1e-5 

89 

90 

91Triclinic = TriclinicFactory()