aton 0.2.2__tar.gz → 0.2.4__tar.gz

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.
Files changed (52) hide show
  1. {aton-0.2.2 → aton-0.2.4}/PKG-INFO +4 -2
  2. {aton-0.2.2 → aton-0.2.4}/README.md +3 -1
  3. {aton-0.2.2 → aton-0.2.4}/aton/_version.py +1 -1
  4. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/__init__.py +23 -0
  5. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/potential.py +5 -5
  6. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/rotate.py +14 -1
  7. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/solve.py +59 -6
  8. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/system.py +13 -7
  9. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/systems.py +37 -0
  10. {aton-0.2.2 → aton-0.2.4}/aton/txt/__init__.py +1 -1
  11. {aton-0.2.2 → aton-0.2.4}/aton.egg-info/PKG-INFO +4 -2
  12. {aton-0.2.2 → aton-0.2.4}/aton.egg-info/SOURCES.txt +0 -0
  13. {aton-0.2.2 → aton-0.2.4}/aton.egg-info/dependency_links.txt +0 -0
  14. {aton-0.2.2 → aton-0.2.4}/aton.egg-info/requires.txt +0 -0
  15. {aton-0.2.2 → aton-0.2.4}/aton.egg-info/top_level.txt +0 -0
  16. {aton-0.2.2 → aton-0.2.4}/LICENSE +0 -0
  17. {aton-0.2.2 → aton-0.2.4}/aton/__init__.py +0 -0
  18. {aton-0.2.2 → aton-0.2.4}/aton/interface/__init__.py +0 -0
  19. {aton-0.2.2 → aton-0.2.4}/aton/interface/castep.py +0 -0
  20. {aton-0.2.2 → aton-0.2.4}/aton/interface/phonopy.py +0 -0
  21. {aton-0.2.2 → aton-0.2.4}/aton/interface/qe.py +0 -0
  22. {aton-0.2.2 → aton-0.2.4}/aton/interface/slurm.py +0 -0
  23. {aton-0.2.2 → aton-0.2.4}/aton/phys/__init__.py +0 -0
  24. {aton-0.2.2 → aton-0.2.4}/aton/phys/atoms.py +0 -0
  25. {aton-0.2.2 → aton-0.2.4}/aton/phys/functions.py +0 -0
  26. {aton-0.2.2 → aton-0.2.4}/aton/phys/units.py +0 -0
  27. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/constants.py +0 -0
  28. {aton-0.2.2 → aton-0.2.4}/aton/qrotor/plot.py +0 -0
  29. {aton-0.2.2 → aton-0.2.4}/aton/spx/__init__.py +0 -0
  30. {aton-0.2.2 → aton-0.2.4}/aton/spx/classes.py +0 -0
  31. {aton-0.2.2 → aton-0.2.4}/aton/spx/deuterium.py +0 -0
  32. {aton-0.2.2 → aton-0.2.4}/aton/spx/fit.py +0 -0
  33. {aton-0.2.2 → aton-0.2.4}/aton/spx/normalize.py +0 -0
  34. {aton-0.2.2 → aton-0.2.4}/aton/spx/plot.py +0 -0
  35. {aton-0.2.2 → aton-0.2.4}/aton/spx/samples.py +0 -0
  36. {aton-0.2.2 → aton-0.2.4}/aton/st/__init__.py +0 -0
  37. {aton-0.2.2 → aton-0.2.4}/aton/st/alias.py +0 -0
  38. {aton-0.2.2 → aton-0.2.4}/aton/st/call.py +0 -0
  39. {aton-0.2.2 → aton-0.2.4}/aton/st/file.py +0 -0
  40. {aton-0.2.2 → aton-0.2.4}/aton/txt/edit.py +0 -0
  41. {aton-0.2.2 → aton-0.2.4}/aton/txt/extract.py +0 -0
  42. {aton-0.2.2 → aton-0.2.4}/aton/txt/find.py +0 -0
  43. {aton-0.2.2 → aton-0.2.4}/setup.cfg +0 -0
  44. {aton-0.2.2 → aton-0.2.4}/setup.py +0 -0
  45. {aton-0.2.2 → aton-0.2.4}/tests/__init__.py +0 -0
  46. {aton-0.2.2 → aton-0.2.4}/tests/test_edit.py +0 -0
  47. {aton-0.2.2 → aton-0.2.4}/tests/test_extract.py +0 -0
  48. {aton-0.2.2 → aton-0.2.4}/tests/test_file.py +0 -0
  49. {aton-0.2.2 → aton-0.2.4}/tests/test_find.py +0 -0
  50. {aton-0.2.2 → aton-0.2.4}/tests/test_qe.py +0 -0
  51. {aton-0.2.2 → aton-0.2.4}/tests/test_qrotor.py +0 -0
  52. {aton-0.2.2 → aton-0.2.4}/tests/test_spx.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: aton
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: The Ab-iniTiO & Neutron research toolbox, or ATON, provides powerful and comprehensive tools for cutting-edge materials research, focused on (but not limited to) neutron science.
5
5
  Author: Pablo Gila-Herranz
6
6
  Author-email: pgila001@ikasle.ehu.eus
@@ -41,9 +41,11 @@ or [ATON](https://pablogila.github.io/ATON/),
41
41
  provides powerful and comprehensive tools
42
42
  for cutting-edge materials research,
43
43
  focused on (but not limited to) neutron science.
44
+ Designed to bridge the gap between theoretical modeling and experimental validation,
45
+ ATON allows researchers to streamline and simplify workflows in the study of advanced materials.
44
46
 
45
47
  Just like its [ancient Egyptian deity](https://en.wikipedia.org/wiki/Aten) counterpart,
46
- this all-in-one Python package contains a range of tools
48
+ this all-in-one Python package comprises a range of utility tools
47
49
  from INS spectra analysis to *ab-initio* interfaces
48
50
  for [Quantum ESPRESSO](https://www.quantum-espresso.org/),
49
51
  [Phonopy](https://phonopy.github.io/phonopy/) and
@@ -8,9 +8,11 @@ or [ATON](https://pablogila.github.io/ATON/),
8
8
  provides powerful and comprehensive tools
9
9
  for cutting-edge materials research,
10
10
  focused on (but not limited to) neutron science.
11
+ Designed to bridge the gap between theoretical modeling and experimental validation,
12
+ ATON allows researchers to streamline and simplify workflows in the study of advanced materials.
11
13
 
12
14
  Just like its [ancient Egyptian deity](https://en.wikipedia.org/wiki/Aten) counterpart,
13
- this all-in-one Python package contains a range of tools
15
+ this all-in-one Python package comprises a range of utility tools
14
16
  from INS spectra analysis to *ab-initio* interfaces
15
17
  for [Quantum ESPRESSO](https://www.quantum-espresso.org/),
16
18
  [Phonopy](https://phonopy.github.io/phonopy/) and
@@ -10,5 +10,5 @@ https://semver.org/
10
10
 
11
11
  """
12
12
 
13
- __version__ = 'v0.2.2'
13
+ __version__ = 'v0.2.4'
14
14
 
@@ -94,6 +94,29 @@ system.solve(200000)
94
94
  qr.plot.energies(system)
95
95
  ```
96
96
 
97
+
98
+ ## Tunnel splittings and excitations
99
+
100
+ By default, energy eigenvalues are assumed to present triplet degeneracy,
101
+ see [A. J. Horsewill, Progress in Nuclear Magnetic Resonance Spectroscopy 35, 359–389 (1999)](https://doi.org/10.1016/S0079-6565(99)00016-3).
102
+ If this is not the case, check `aton.qrotor.solve.excitations()`.
103
+
104
+ When the quantum System is solved, tunnel splittings and excitations are also calculated:
105
+
106
+ ```python
107
+ system.solve()
108
+ system.splittings
109
+ system.excitations
110
+ ```
111
+
112
+ To export the tunnel splittings of several calculations to a CSV file:
113
+
114
+ ```python
115
+ calculations = [system1, system2, system3]
116
+ qr.systems.splittings(calculations)
117
+ ```
118
+
119
+
97
120
  Check the API documentation for more details.
98
121
 
99
122
  """
@@ -205,13 +205,13 @@ def from_qe(
205
205
  potential_data += '# https://pablogila.github.io/ATON\n'
206
206
  potential_data += '#\n'
207
207
  if energy.lower() in alias.units['eV']:
208
- potential_data += '# Angle/deg Potential/eV\n'
208
+ potential_data += '# Angle/deg, Potential/eV\n'
209
209
  elif energy.lower() in alias.units['meV']:
210
- potential_data += '# Angle/deg Potential/meV\n'
210
+ potential_data += '# Angle/deg, Potential/meV\n'
211
211
  elif energy.lower() in alias.units['Ry']:
212
- potential_data += '# Angle/deg Potential/Ry\n'
212
+ potential_data += '# Angle/deg, Potential/Ry\n'
213
213
  else:
214
- potential_data += '# Angle/deg Potential/meV\n'
214
+ potential_data += '# Angle/deg, Potential/meV\n'
215
215
  potential_data += '#\n'
216
216
  potential_data_list = []
217
217
  print('Extracting the potential as a function of the angle...')
@@ -248,7 +248,7 @@ def from_qe(
248
248
  potential_data_list_sorted = sorted(potential_data_list, key=lambda x: x[0])
249
249
  # Append the sorted values as a string
250
250
  for angle_value, energy_value in potential_data_list_sorted:
251
- potential_data += f'{angle_value} {energy_value}\n'
251
+ potential_data += f'{angle_value}, {energy_value}\n'
252
252
  with open(filepath, 'w') as f:
253
253
  f.write(potential_data)
254
254
  print('----------------------------------')
@@ -51,6 +51,11 @@ def structure_qe(
51
51
  To override this and instead use the vector between the first two atoms
52
52
  as the rotation axis, set `use_centroid = False`.
53
53
 
54
+ **WARNING: The `positions` list is order-sensitive**.
55
+ If you rotate more than one chemical group in a structure,
56
+ be sure to follow the same direction for each group (e.g. all clockwise)
57
+ to ensure that all axes of rotation point in the same direction.
58
+
54
59
  To debug, `show_axis = True` adds two additional helium atoms as the rotation vector.
55
60
  """
56
61
  print('Rotating Quantum ESPRESSO input structure with QRotor...')
@@ -106,13 +111,21 @@ def rotate_coords(
106
111
  Then rotates said coordinates by a given `angle` in degrees.
107
112
  Returns a list with the updated positions.
108
113
 
109
- By default, the rotation axis is defined by the perpendicular vector
114
+ By default, the rotation vector is defined by the perpendicular
110
115
  passing through the geometrical center of the first three points.
111
116
  To override this and use the vector between the first two atoms
112
117
  as the rotation axis, set `use_centroid = False`.
113
118
 
119
+ **WARNING: The `positions` list is order-sensitive**.
120
+ If you rotate more than one chemical group in a structure,
121
+ be sure to follow the same direction for each group (e.g. all clockwise)
122
+ to ensure that all rotation vectors point in the same direction.
123
+
114
124
  If `show_axis = True` it returns two additional coordinates at the end of the list,
115
125
  with the centroid and the rotation vector. Only works with `use_centroid = True`.
126
+
127
+ The rotation uses Rodrigues' rotation formula,
128
+ powered by [`scipy.spatial.transform.Rotation.from_rotvec`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.from_rotvec.html#scipy.spatial.transform.Rotation.from_rotvec).
116
129
  """
117
130
  if len(positions) < 3:
118
131
  raise ValueError("At least three atoms must be rotated.")
@@ -1,8 +1,14 @@
1
1
  """
2
2
  # Description
3
3
 
4
- This module is used to solve the hamiltonian eigenvalues and eigenvectors for a given quantum system.
5
- Sparse matrices are used to achieve optimal performance.
4
+ This module is used to solve any given quantum system.
5
+
6
+ Although the functions of this module can be used independently,
7
+ it is highly recommended to use the `System.solve()` method instead,
8
+ which does all the solving automatically (see `aton.qrotor.system.System.solve()`).
9
+ However, advanced users might want to use some of these functions independently;
10
+ for example, if your system energy levels are not degenerated in triplets,
11
+ you might want to use `excitations()` to solve the energy excitations and tunnel splittings with the proper degeneracy.
6
12
 
7
13
 
8
14
  # Index
@@ -14,6 +20,7 @@ Sparse matrices are used to achieve optimal performance.
14
20
  | `schrodinger()` | Solve the Schrödiger equation for the system |
15
21
  | `hamiltonian_matrix()` | Calculate the hamiltonian matrix of the system |
16
22
  | `laplacian_matrix()` | Calculate the second derivative matrix for a given grid |
23
+ | `excitations()` | Get excitation levels and tunnel splitting energies for a set of eigenvalues |
17
24
 
18
25
  ---
19
26
  """
@@ -86,16 +93,16 @@ def schrodinger(system:System) -> System:
86
93
  system.potential_max = max(V)
87
94
  system.potential_min = min(V)
88
95
  system.energy_barrier = max(V) - min(eigenvalues)
89
- system.transitions = []
90
- for i in range(len(eigenvalues)-1):
91
- system.transitions.append(eigenvalues[i+1] - eigenvalues[0])
96
+ # Solve excitations and tunnel splittings, assuming triplet degeneracy
97
+ system = excitations(system, deg=3)
98
+ # Do we really need to save eigenvectors?
92
99
  if system.save_eigenvectors == True:
93
100
  system.eigenvectors = np.transpose(eigenvectors)
94
101
  return system
95
102
 
96
103
 
97
104
  def hamiltonian_matrix(system:System):
98
- """Calculates the Hamiltonian matrix for a given `system`."""
105
+ """Calculates the Hamiltonian sparse matrix for a given `system`."""
99
106
  print(f'Creating Hamiltonian matrix of size {system.gridsize}...')
100
107
  V = system.potential_values.tolist()
101
108
  potential = sparse.diags(V, format='lil')
@@ -117,3 +124,49 @@ def laplacian_matrix(grid):
117
124
  laplacian_matrix /= dx**2
118
125
  return laplacian_matrix
119
126
 
127
+
128
+ def excitations(
129
+ system:System,
130
+ deg:int=3,
131
+ ) -> tuple:
132
+ """Calculate the excitation levels and the tunnel splitting energies of a system.
133
+
134
+ Stops the calculation when energies reach the maximum potential.
135
+ Assumes that eigenvalues are degenerated in triplets;
136
+ this degeneracy can be specified with `deg`.
137
+ """
138
+ eigenvalues = system.eigenvalues
139
+ V_max = system.potential_max
140
+ ground_energy = min(eigenvalues)
141
+ excitations = []
142
+ tunnel_splittings = []
143
+ i = 0
144
+ while (i + deg-1) <= len(eigenvalues):
145
+ # Get the eigenvalues corresponding to this triplet (or whatever degeneracy)
146
+ i_max = i + deg # Index indicating the end of this triplet
147
+ triplet = eigenvalues[i:i_max]
148
+ # Check that we are still below the potential max
149
+ if any(triplet) > V_max:
150
+ break
151
+ # Check that all eigenvalues are valid, and not None
152
+ if any(triplet) is None:
153
+ break
154
+ # Get the excitation energy, by comparing with the ground state
155
+ if i != 0: # Skip the ground energy level
156
+ excitations.append(min(triplet) - ground_energy)
157
+ # Check the energy differences inside each triplet (or whatever degeneracy)
158
+ E_diff = []
159
+ for j in range(deg-1): # 0, 1 (not 2)
160
+ E_0 = triplet[j]
161
+ E_1 = triplet[j+1]
162
+ diff = E_1 - E_0
163
+ E_diff.append(diff)
164
+ # Get the maximum energy difference inside the triplet, which is the tunnel splitting
165
+ tunnel_splittings.append(max(E_diff))
166
+ # Move to the next triplet
167
+ i += deg
168
+ # Set the energy excitations and tunnel splittings
169
+ system.excitations = excitations
170
+ system.splittings = tunnel_splittings
171
+ return system
172
+
@@ -18,6 +18,8 @@ class System:
18
18
  """Quantum system.
19
19
 
20
20
  Contains all the data for a single QRotor calculation, with both inputs and outputs.
21
+
22
+ Energy units are in meV and angles are in radians, unless stated otherwise.
21
23
  """
22
24
  def __init__(
23
25
  self,
@@ -85,14 +87,19 @@ class System:
85
87
  self.eigenvectors = []
86
88
  """Eigenvectors, if `save_eigenvectors` is True. Beware of the file size."""
87
89
  self.energy_barrier: float = None
88
- """`max(V) - min(eigenvalues)`"""
89
- self.transitions: list = None
90
- """eigenvalues[i+1] - eigenvalues[0]"""
90
+ """Activation energy or energy barrier, from the ground torsional state to the top of the potential barrier, `max(V) - min(eigenvalues)`"""
91
+ self.excitations: list = None
92
+ """Torsional excitations, as eigenvalues with respect to the ground state.
93
+
94
+ Considers the lowest eigenvalue from each degenerated energy level.
95
+ """
96
+ self.splittings: list = None
97
+ """Tunnel splitting energies, for every degenerated energy level."""
91
98
  self.runtime: float = None
92
99
  """Time taken to solve the eigenvalues."""
93
100
 
94
101
  def solve(self, new_gridsize:int=None):
95
- """Solves the quantum system.
102
+ """Default method to solve the quantum system.
96
103
 
97
104
  The potential can be interpolated to a `new_gridsize`.
98
105
 
@@ -129,10 +136,8 @@ class System:
129
136
  # Check that the grid is still within -2pi and 2pi, otherwise normalise it for a final time
130
137
  while self.grid[0] <= (-2 * np.pi + 0.1): # With a small tolerance
131
138
  self.grid = self.grid + 2 * np.pi
132
- print('plus 2')
133
139
  while self.grid[-1] >= 2.5 * np.pi: # It was not a problem until reaching 5/2 pi
134
140
  self.grid = self.grid -2 * np.pi
135
- print('minus 2')
136
141
  print(f'Potential shifted by {phase}π')
137
142
  if calculate:
138
143
  self.solve()
@@ -215,7 +220,8 @@ class System:
215
220
  'potential_max': self.potential_max,
216
221
  'eigenvalues': self.eigenvalues.tolist() if isinstance(self.eigenvalues, np.ndarray) else self.eigenvalues,
217
222
  'energy_barrier': self.energy_barrier,
218
- 'transitions': self.transitions,
223
+ 'excitations': self.excitations,
224
+ 'splittings': self.splittings,
219
225
  'runtime': self.runtime,
220
226
  }
221
227
 
@@ -16,12 +16,15 @@ This module contains utility functions to handle multiple `aton.qrotor.system` c
16
16
  | `sort_by_gridsize()` | Sort systems by gridsize |
17
17
  | `reduce_size()` | Discard data that takes too much space |
18
18
  | `get_ideal_E()` | Calculate the ideal energy for a specified level |
19
+ | `splittings()` | Get the first tunnel splitting energies for all systems |
19
20
 
20
21
  ---
21
22
  """
22
23
 
23
24
 
24
25
  from .system import System
26
+ from aton import txt
27
+ import pandas as pd
25
28
 
26
29
 
27
30
  def as_list(systems) -> None:
@@ -129,3 +132,37 @@ def get_ideal_E(E_level:int) -> int:
129
132
  ideal_E = int(real_E_level ** 2)
130
133
  return ideal_E
131
134
 
135
+
136
+ def splittings(
137
+ systems:list,
138
+ comment:str='',
139
+ filepath:str='tunnel_splittings.csv',
140
+ ) -> pd.DataFrame:
141
+ """Save the tunnel splitting energies for all `systems` to a tunnel_splittings.csv file.
142
+
143
+ Returns a Pandas Dataset with `System.comment` columns and `System.splittings` values.
144
+
145
+ The output file can be changed with `filepath`,
146
+ or set to null to avoid saving the dataset.
147
+ A `comment` can be included at the top of the file.
148
+ Note that `System.comment` must not include commas (`,`).
149
+ """
150
+ as_list(systems)
151
+ version = systems[0].version
152
+ tunnelling_E = {}
153
+ for s in systems:
154
+ tunnelling_E[s.comment] = s.splittings
155
+ df = pd.DataFrame(tunnelling_E)
156
+ if not filepath:
157
+ return df
158
+ # Else save to file
159
+ df.to_csv(filepath, sep=',', index=False)
160
+ # Include a comment at the top of the file
161
+ file_comment = f'# {comment}\n' if comment else f''
162
+ file_comment += f'# Tunnel splitting energies\n'
163
+ file_comment += f'# Calculated with ATON {version}\n'
164
+ file_comment += f'# https://pablogila.github.io/ATON\n#'
165
+ txt.edit.insert_at(filepath, file_comment, 0)
166
+ print(f'Tunnel splitting energies saved to {filepath}')
167
+ return df
168
+
@@ -26,7 +26,7 @@ alat_lines = txt.find.lines('relax.out', 'Lattice parameter =')
26
26
  # Extract the numerical value of the last match
27
27
  alat = txt.extract.number(alat_lines[-1], 'Lattice parameter')
28
28
  # Paste it into another file
29
- txt.edit.replace_line('scf.in', 'Lattice parameter =', f'Lattice parameter ='{alat})
29
+ txt.edit.replace_line('scf.in', 'Lattice parameter =', f'Lattice parameter = {alat}')
30
30
  ```
31
31
 
32
32
  Advanced usage such as regular expression matching or
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: aton
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: The Ab-iniTiO & Neutron research toolbox, or ATON, provides powerful and comprehensive tools for cutting-edge materials research, focused on (but not limited to) neutron science.
5
5
  Author: Pablo Gila-Herranz
6
6
  Author-email: pgila001@ikasle.ehu.eus
@@ -41,9 +41,11 @@ or [ATON](https://pablogila.github.io/ATON/),
41
41
  provides powerful and comprehensive tools
42
42
  for cutting-edge materials research,
43
43
  focused on (but not limited to) neutron science.
44
+ Designed to bridge the gap between theoretical modeling and experimental validation,
45
+ ATON allows researchers to streamline and simplify workflows in the study of advanced materials.
44
46
 
45
47
  Just like its [ancient Egyptian deity](https://en.wikipedia.org/wiki/Aten) counterpart,
46
- this all-in-one Python package contains a range of tools
48
+ this all-in-one Python package comprises a range of utility tools
47
49
  from INS spectra analysis to *ab-initio* interfaces
48
50
  for [Quantum ESPRESSO](https://www.quantum-espresso.org/),
49
51
  [Phonopy](https://phonopy.github.io/phonopy/) and
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes