qrotor 4.0.0a2__tar.gz → 4.0.2__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.

Potentially problematic release.


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

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrotor
3
- Version: 4.0.0a2
3
+ Version: 4.0.2
4
4
  Summary: QRotor
5
5
  Author: Pablo Gila-Herranz
6
6
  Author-email: pgila001@ikasle.ehu.eus
@@ -21,6 +21,7 @@ Requires-Dist: pandas
21
21
  Requires-Dist: numpy
22
22
  Requires-Dist: matplotlib
23
23
  Requires-Dist: aton
24
+ Requires-Dist: periodictable
24
25
  Dynamic: author
25
26
  Dynamic: author-email
26
27
  Dynamic: classifier
@@ -33,7 +34,7 @@ Dynamic: requires-dist
33
34
  Dynamic: requires-python
34
35
  Dynamic: summary
35
36
 
36
- <p align="center"><img width="40.0%" src="pics/qrotor.png"></p>
37
+ <p align="center"><img width="60.0%" src="pics/qrotor.png"></p>
37
38
 
38
39
  QRotor is a Python package used to study molecular rotations,
39
40
  such as those of methyl and amine groups.
@@ -44,27 +45,66 @@ These quantum systems are represented by the `qrotor.System()` object.
44
45
  QRotor can obtain custom potentials from DFT,
45
46
  which are used to solve the quantum system.
46
47
 
47
- Check the [full documentation online](https://pablogila.github.io/qrotor/).
48
+
49
+ ---
50
+
51
+
52
+ # Installation
53
+
54
+ As always, it is recommended to install your packages in a virtual environment:
55
+ ```bash
56
+ python3 -m venv .venv
57
+ source .venv/bin/activate
58
+ ```
59
+
60
+
61
+ ## With pip
62
+
63
+ Install or upgrade ATON with
64
+ ```bash
65
+ pip install qrotor -U
66
+ ```
67
+
68
+
69
+ ## From source
70
+
71
+ Optionally, you can install ATON from the [GitHub repo](https://github.com/pablogila/qrotor/).
72
+ Clone the repository or download the [latest stable release](https://github.com/pablogila/qrotor/tags)
73
+ as a ZIP, unzip it, and run inside it:
74
+ ```bash
75
+ pip install .
76
+ ```
48
77
 
49
78
 
50
- # Index
79
+ ---
80
+
81
+
82
+ # Documentation
83
+
84
+ QRotor contains the following modules:
51
85
 
52
86
  | | |
53
87
  | --- | --- |
88
+ | [qrotor.constants](https://pablogila.github.io/qrotor/qrotor/constants.html) | Common bond lengths and inertias |
54
89
  | [qrotor.system](https://pablogila.github.io/qrotor/qrotor/system.html) | Definition of the quantum `System` object |
55
- | [qrotor.systems](https://pablogila.github.io/qrotor/qrotor/systems.html) | Functions to manage several System objects, such as a list of systems |
90
+ | [qrotor.systems](https://pablogila.github.io/qrotor/qrotor/systems.html) | Utilities to manage several System objects, such as a list of systems |
56
91
  | [qrotor.rotate](https://pablogila.github.io/qrotor/qrotor/rotate.html) | Rotate specific atoms from structural files |
57
- | [qrotor.constants](https://pablogila.github.io/qrotor/qrotor/constants.html) | Common bond lengths and inertias |
58
92
  | [qrotor.potential](https://pablogila.github.io/qrotor/qrotor/potential.html) | Potential definitions and loading functions |
59
93
  | [qrotor.solve](https://pablogila.github.io/qrotor/qrotor/solve.html) | Solve rotation eigenvalues and eigenvectors |
60
- | [qrotor.plot](https://pablogila.github.io/qrotor/qrotor/plot.html) | Plotting functions |
94
+ | [qrotor.plot](https://pablogila.github.io/qrotor/qrotor/plot.html) | Plotting utilities |
95
+
96
+ Check the [full documentation online](https://pablogila.github.io/qrotor/).
97
+
98
+
99
+ ---
61
100
 
62
101
 
63
102
  # Usage
64
103
 
65
104
  ## Solving quantum rotational systems
66
105
 
67
- A basic calculation of the eigenvalues for a zero potential goes as follows.
106
+ Let's start with a basic calculation of the eigenvalues for a zero potential, corresponding to a free rotor.
107
+ A predefined synthetic potential can be used, see all available options in the [qrotor.potential](https://pablogila.github.io/qrotor/qrotor/potential.html) documentation.
68
108
  Note that the default energy unit is meV unless stated otherwise.
69
109
 
70
110
  ```python
@@ -74,7 +114,7 @@ system.gridsize = 200000 # Size of the potential grid
74
114
  system.B = 1 # Rotational inertia
75
115
  system.potential_name = 'zero'
76
116
  system.solve()
77
- system.eigenvalues
117
+ print(system.eigenvalues)
78
118
  # [0.0, 1.0, 1.0, 4.0, 4.0, 9.0, 9.0, ...] # approx values
79
119
  ```
80
120
 
@@ -87,10 +127,10 @@ in a cosine potential of amplitude 30 meV:
87
127
  ```python
88
128
  import qrotor as qr
89
129
  system = qr.System()
90
- system.gridsize = 200000 # Size of the potential grid
130
+ system.gridsize = 200000
91
131
  system.B = qr.B_CH3 # Rotational inertia of a methyl group
92
132
  system.potential_name = 'cosine'
93
- system.potential_constants = [0, 30, 3, 0] # Offset, max, freq, phase (for cos pot.)
133
+ system.potential_constants = [0, 30, 3, 0] # Offset, max, freq, phase (for cosine potential)
94
134
  system.solve()
95
135
  # Plot potential and eigenvalues
96
136
  qr.plot.energies(system)
@@ -102,7 +142,7 @@ qr.plot.wavefunction(system, levels=[0,1,2], square=True)
102
142
  ## Custom potentials from DFT
103
143
 
104
144
  QRotor can be used to obtain custom rotational potentials from DFT calculations.
105
- Using Quantum ESPRESSO, running an SCF calculation for a methyl rotation every 10 degrees:
145
+ To run a Quantum ESPRESSO SCF calculation for a methyl rotation every 10 degrees:
106
146
 
107
147
  ```python
108
148
  import qrotor as qr
@@ -121,10 +161,8 @@ api.slurm.sbatch(files=scf_files)
121
161
 
122
162
  To load the calculated potential to a QRotor System,
123
163
  ```python
124
- # Compile a 'potential.csv' file with the calculated potential as a function of the angle
125
- qr.potential.from_qe()
126
- # Load to the system
127
- system = qr.potential.load()
164
+ # Compile a 'potential.csv' file with the calculated potential as a function of the angle, and load it into a new system
165
+ system = qr.potential.from_qe()
128
166
  # Solve the system, interpolating to a bigger gridsize
129
167
  system.B = qr.B_CH3
130
168
  system.solve(200000)
@@ -139,9 +177,9 @@ below the potential maximum are also calculated upon solving the system:
139
177
 
140
178
  ```python
141
179
  system.solve()
142
- system.splittings
143
- system.excitations
144
- system.deg
180
+ print(system.splittings)
181
+ print(system.excitations)
182
+ print(system.deg)
145
183
  ```
146
184
 
147
185
  An integer `System.deg` degeneracy (e.g. 3 for methyls)
@@ -165,3 +203,71 @@ See [R. M. Dimeo, American Journal of Physics 71, 885–893 (2003)](https://doi.
165
203
  and [A. J. Horsewill, Progress in Nuclear Magnetic Resonance Spectroscopy 35, 359–389 (1999)](https://doi.org/10.1016/S0079-6565(99)00016-3)
166
204
  for further reference.
167
205
 
206
+
207
+ ---
208
+
209
+
210
+ # Contributing
211
+
212
+ If you are interested in opening an issue or a pull request, please feel free to do so on [GitHub](https://github.com/pablogila/qrotor/).
213
+ For major changes, please get in touch first to discuss the details.
214
+
215
+
216
+ ## Code style
217
+
218
+ Please try to follow some general guidelines:
219
+ - Use a code style consistent with the rest of the project.
220
+ - Include docstrings to document new additions.
221
+ - Include automated tests for new features or modifications, see [automated testing](#automated-testing).
222
+ - Arrange function arguments by order of relevance.
223
+
224
+
225
+ ## Automated testing
226
+
227
+ If you are modifying the source code, you should run the automated tests of the [`tests/`](https://github.com/pablogila/qrotor/tree/main/tests) folder to check that everything works as intended.
228
+ To do so, first install PyTest in your environment,
229
+ ```bash
230
+ pip install pytest
231
+ ```
232
+
233
+ And then run PyTest inside the main directory,
234
+ ```bash
235
+ pytest -vv
236
+ ```
237
+
238
+
239
+ ## Compiling the documentation
240
+
241
+ The documentation can be compiled automatically to `docs/qrotor.html` with [Pdoc](https://pdoc.dev/) and [ATON](https://pablogila.github.io/aton), by running:
242
+ ```shell
243
+ python3 makedocs.py
244
+ ```
245
+
246
+ This runs Pdoc, updating links and pictures, and using the custom theme CSS template from the `css/` folder.
247
+
248
+
249
+ ---
250
+
251
+
252
+ # Citation
253
+
254
+ QRotor is currently under development.
255
+ Please cite it if you use it in your research,
256
+ > Pablo Gila-Herranz, *QRotor*, https://pablogila.github.io/qrotor
257
+
258
+
259
+ ---
260
+
261
+
262
+ # License
263
+
264
+ Copyright (C) 2025 Pablo Gila-Herranz
265
+ This program is free software: you can redistribute it and/or modify
266
+ it under the terms of the **GNU Affero General Public License** as published
267
+ by the Free Software Foundation, either version **3** of the License, or
268
+ (at your option) any later version.
269
+ This program is distributed in the hope that it will be useful,
270
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
271
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
272
+ See the attached GNU Affero General Public License for more details.
273
+
@@ -1,4 +1,4 @@
1
- <p align="center"><img width="40.0%" src="pics/qrotor.png"></p>
1
+ <p align="center"><img width="60.0%" src="pics/qrotor.png"></p>
2
2
 
3
3
  QRotor is a Python package used to study molecular rotations,
4
4
  such as those of methyl and amine groups.
@@ -9,27 +9,66 @@ These quantum systems are represented by the `qrotor.System()` object.
9
9
  QRotor can obtain custom potentials from DFT,
10
10
  which are used to solve the quantum system.
11
11
 
12
- Check the [full documentation online](https://pablogila.github.io/qrotor/).
12
+
13
+ ---
14
+
15
+
16
+ # Installation
17
+
18
+ As always, it is recommended to install your packages in a virtual environment:
19
+ ```bash
20
+ python3 -m venv .venv
21
+ source .venv/bin/activate
22
+ ```
23
+
24
+
25
+ ## With pip
26
+
27
+ Install or upgrade ATON with
28
+ ```bash
29
+ pip install qrotor -U
30
+ ```
31
+
32
+
33
+ ## From source
34
+
35
+ Optionally, you can install ATON from the [GitHub repo](https://github.com/pablogila/qrotor/).
36
+ Clone the repository or download the [latest stable release](https://github.com/pablogila/qrotor/tags)
37
+ as a ZIP, unzip it, and run inside it:
38
+ ```bash
39
+ pip install .
40
+ ```
13
41
 
14
42
 
15
- # Index
43
+ ---
44
+
45
+
46
+ # Documentation
47
+
48
+ QRotor contains the following modules:
16
49
 
17
50
  | | |
18
51
  | --- | --- |
52
+ | [qrotor.constants](https://pablogila.github.io/qrotor/qrotor/constants.html) | Common bond lengths and inertias |
19
53
  | [qrotor.system](https://pablogila.github.io/qrotor/qrotor/system.html) | Definition of the quantum `System` object |
20
- | [qrotor.systems](https://pablogila.github.io/qrotor/qrotor/systems.html) | Functions to manage several System objects, such as a list of systems |
54
+ | [qrotor.systems](https://pablogila.github.io/qrotor/qrotor/systems.html) | Utilities to manage several System objects, such as a list of systems |
21
55
  | [qrotor.rotate](https://pablogila.github.io/qrotor/qrotor/rotate.html) | Rotate specific atoms from structural files |
22
- | [qrotor.constants](https://pablogila.github.io/qrotor/qrotor/constants.html) | Common bond lengths and inertias |
23
56
  | [qrotor.potential](https://pablogila.github.io/qrotor/qrotor/potential.html) | Potential definitions and loading functions |
24
57
  | [qrotor.solve](https://pablogila.github.io/qrotor/qrotor/solve.html) | Solve rotation eigenvalues and eigenvectors |
25
- | [qrotor.plot](https://pablogila.github.io/qrotor/qrotor/plot.html) | Plotting functions |
58
+ | [qrotor.plot](https://pablogila.github.io/qrotor/qrotor/plot.html) | Plotting utilities |
59
+
60
+ Check the [full documentation online](https://pablogila.github.io/qrotor/).
61
+
62
+
63
+ ---
26
64
 
27
65
 
28
66
  # Usage
29
67
 
30
68
  ## Solving quantum rotational systems
31
69
 
32
- A basic calculation of the eigenvalues for a zero potential goes as follows.
70
+ Let's start with a basic calculation of the eigenvalues for a zero potential, corresponding to a free rotor.
71
+ A predefined synthetic potential can be used, see all available options in the [qrotor.potential](https://pablogila.github.io/qrotor/qrotor/potential.html) documentation.
33
72
  Note that the default energy unit is meV unless stated otherwise.
34
73
 
35
74
  ```python
@@ -39,7 +78,7 @@ system.gridsize = 200000 # Size of the potential grid
39
78
  system.B = 1 # Rotational inertia
40
79
  system.potential_name = 'zero'
41
80
  system.solve()
42
- system.eigenvalues
81
+ print(system.eigenvalues)
43
82
  # [0.0, 1.0, 1.0, 4.0, 4.0, 9.0, 9.0, ...] # approx values
44
83
  ```
45
84
 
@@ -52,10 +91,10 @@ in a cosine potential of amplitude 30 meV:
52
91
  ```python
53
92
  import qrotor as qr
54
93
  system = qr.System()
55
- system.gridsize = 200000 # Size of the potential grid
94
+ system.gridsize = 200000
56
95
  system.B = qr.B_CH3 # Rotational inertia of a methyl group
57
96
  system.potential_name = 'cosine'
58
- system.potential_constants = [0, 30, 3, 0] # Offset, max, freq, phase (for cos pot.)
97
+ system.potential_constants = [0, 30, 3, 0] # Offset, max, freq, phase (for cosine potential)
59
98
  system.solve()
60
99
  # Plot potential and eigenvalues
61
100
  qr.plot.energies(system)
@@ -67,7 +106,7 @@ qr.plot.wavefunction(system, levels=[0,1,2], square=True)
67
106
  ## Custom potentials from DFT
68
107
 
69
108
  QRotor can be used to obtain custom rotational potentials from DFT calculations.
70
- Using Quantum ESPRESSO, running an SCF calculation for a methyl rotation every 10 degrees:
109
+ To run a Quantum ESPRESSO SCF calculation for a methyl rotation every 10 degrees:
71
110
 
72
111
  ```python
73
112
  import qrotor as qr
@@ -86,10 +125,8 @@ api.slurm.sbatch(files=scf_files)
86
125
 
87
126
  To load the calculated potential to a QRotor System,
88
127
  ```python
89
- # Compile a 'potential.csv' file with the calculated potential as a function of the angle
90
- qr.potential.from_qe()
91
- # Load to the system
92
- system = qr.potential.load()
128
+ # Compile a 'potential.csv' file with the calculated potential as a function of the angle, and load it into a new system
129
+ system = qr.potential.from_qe()
93
130
  # Solve the system, interpolating to a bigger gridsize
94
131
  system.B = qr.B_CH3
95
132
  system.solve(200000)
@@ -104,9 +141,9 @@ below the potential maximum are also calculated upon solving the system:
104
141
 
105
142
  ```python
106
143
  system.solve()
107
- system.splittings
108
- system.excitations
109
- system.deg
144
+ print(system.splittings)
145
+ print(system.excitations)
146
+ print(system.deg)
110
147
  ```
111
148
 
112
149
  An integer `System.deg` degeneracy (e.g. 3 for methyls)
@@ -130,3 +167,71 @@ See [R. M. Dimeo, American Journal of Physics 71, 885–893 (2003)](https://doi.
130
167
  and [A. J. Horsewill, Progress in Nuclear Magnetic Resonance Spectroscopy 35, 359–389 (1999)](https://doi.org/10.1016/S0079-6565(99)00016-3)
131
168
  for further reference.
132
169
 
170
+
171
+ ---
172
+
173
+
174
+ # Contributing
175
+
176
+ If you are interested in opening an issue or a pull request, please feel free to do so on [GitHub](https://github.com/pablogila/qrotor/).
177
+ For major changes, please get in touch first to discuss the details.
178
+
179
+
180
+ ## Code style
181
+
182
+ Please try to follow some general guidelines:
183
+ - Use a code style consistent with the rest of the project.
184
+ - Include docstrings to document new additions.
185
+ - Include automated tests for new features or modifications, see [automated testing](#automated-testing).
186
+ - Arrange function arguments by order of relevance.
187
+
188
+
189
+ ## Automated testing
190
+
191
+ If you are modifying the source code, you should run the automated tests of the [`tests/`](https://github.com/pablogila/qrotor/tree/main/tests) folder to check that everything works as intended.
192
+ To do so, first install PyTest in your environment,
193
+ ```bash
194
+ pip install pytest
195
+ ```
196
+
197
+ And then run PyTest inside the main directory,
198
+ ```bash
199
+ pytest -vv
200
+ ```
201
+
202
+
203
+ ## Compiling the documentation
204
+
205
+ The documentation can be compiled automatically to `docs/qrotor.html` with [Pdoc](https://pdoc.dev/) and [ATON](https://pablogila.github.io/aton), by running:
206
+ ```shell
207
+ python3 makedocs.py
208
+ ```
209
+
210
+ This runs Pdoc, updating links and pictures, and using the custom theme CSS template from the `css/` folder.
211
+
212
+
213
+ ---
214
+
215
+
216
+ # Citation
217
+
218
+ QRotor is currently under development.
219
+ Please cite it if you use it in your research,
220
+ > Pablo Gila-Herranz, *QRotor*, https://pablogila.github.io/qrotor
221
+
222
+
223
+ ---
224
+
225
+
226
+ # License
227
+
228
+ Copyright (C) 2025 Pablo Gila-Herranz
229
+ This program is free software: you can redistribute it and/or modify
230
+ it under the terms of the **GNU Affero General Public License** as published
231
+ by the Free Software Foundation, either version **3** of the License, or
232
+ (at your option) any later version.
233
+ This program is distributed in the hope that it will be useful,
234
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
235
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
236
+ See the attached GNU Affero General Public License for more details.
237
+
@@ -10,5 +10,5 @@ https://semver.org/
10
10
 
11
11
  """
12
12
 
13
- __version__ = 'v4.0.0a2'
13
+ __version__ = 'v4.0.2'
14
14
 
@@ -11,7 +11,8 @@ Bond lengths and angles were obtained from MAPbI3, see
11
11
 
12
12
 
13
13
  import numpy as np
14
- import aton.phys as phys
14
+ import periodictable
15
+ import scipy.constants as const
15
16
 
16
17
 
17
18
  # Distance between Carbon and Hydrogen atoms (measured from MAPbI3)
@@ -31,29 +32,31 @@ angle_NH = 180 - angle_NH_external
31
32
  """Internal angle of the X-N-H bond, in degrees."""
32
33
 
33
34
  # Rotation radius (calculated from distance and angle)
34
- r_CH = distance_CH * np.sin(np.deg2rad(angle_CH)) * phys.AA_to_m
35
+ r_CH = distance_CH * np.sin(np.deg2rad(angle_CH)) * 1e-10
35
36
  """Rotation radius of the methyl group, in meters."""
36
- r_NH = distance_NH * np.sin(np.deg2rad(angle_NH)) * phys.AA_to_m
37
+ r_NH = distance_NH * np.sin(np.deg2rad(angle_NH)) * 1e-10
37
38
  """Rotation radius of the amine group, in meters."""
38
39
 
39
40
  # Inertia, SI units
40
- I_CH3 = 3 * (phys.atoms['H'].mass * phys.amu_to_kg * r_CH**2)
41
+ _amu = const.physical_constants['atomic mass constant'][0]
42
+ I_CH3 = 3 * (periodictable.H.mass * _amu * r_CH**2)
41
43
  """Inertia of CH3, in kg·m^2."""
42
- I_CD3 = 3 * (phys.atoms['H'].isotope[2].mass * phys.amu_to_kg * r_CH**2)
44
+ I_CD3 = 3 * (periodictable.D.mass * _amu * r_CH**2)
43
45
  """Inertia of CD3, in kg·m^2."""
44
- I_NH3 = 3 * (phys.atoms['H'].mass * phys.amu_to_kg * r_NH**2)
46
+ I_NH3 = 3 * (periodictable.H.mass * _amu * r_NH**2)
45
47
  """Inertia of NH3, in kg·m^2."""
46
- I_ND3 = 3 * (phys.atoms['H'].isotope[2].mass * phys.amu_to_kg * r_NH**2)
48
+ I_ND3 = 3 * (periodictable.D.mass * _amu * r_NH**2)
47
49
  """Inertia of ND3, in kg·m^2."""
48
50
 
49
- # Rotational energy.
50
- B_CH3 = ((phys.hbar**2) / (2 * I_CH3)) * phys.J_to_meV
51
+ # Rotational energy
52
+ _hbar = const.physical_constants['reduced Planck constant'][0]
53
+ B_CH3 = ((_hbar**2) / (2 * I_CH3)) * (1000 / const.eV)
51
54
  """Rotational energy of CH3, in meV·s/kg·m^2."""
52
- B_CD3 = ((phys.hbar**2) / (2 * I_CD3)) * phys.J_to_meV
55
+ B_CD3 = ((_hbar**2) / (2 * I_CD3)) * (1000 / const.eV)
53
56
  """Rotational energy of CD3, in meV·s/kg·m^2."""
54
- B_NH3 = ((phys.hbar**2) / (2 * I_NH3)) * phys.J_to_meV
57
+ B_NH3 = ((_hbar**2) / (2 * I_NH3)) * (1000 / const.eV)
55
58
  """Rotational energy of NH3, in meV·s/kg·m^2."""
56
- B_ND3 = ((phys.hbar**2) / (2 * I_ND3)) * phys.J_to_meV
59
+ B_ND3 = ((_hbar**2) / (2 * I_ND3)) * (1000 / const.eV)
57
60
  """Rotational energy of ND3, in meV·s/kg·m^2."""
58
61
 
59
62
  # Potential constants from titov2023 [C1, C2, C3, C4, C5]
@@ -70,3 +73,13 @@ for the `qrotor.potential.titov2023` potential.
70
73
  In meV units.
71
74
  """
72
75
 
76
+ # Quick conversion factors
77
+ Ry_to_eV = const.physical_constants['Rydberg constant times hc in eV'][0]
78
+ """Quick conversion factor from eV to Rydberg energy."""
79
+ Ry_to_meV = Ry_to_eV * 1000
80
+ """Quick conversion factor from meV to Rydberg energy."""
81
+ eV_to_Ry = 1 / Ry_to_eV
82
+ """Quick conversion factor from Rydberg to eV."""
83
+ meV_to_Ry = 1 / Ry_to_meV
84
+ """Quick conversion factor from Rydberg to meV."""
85
+
@@ -21,11 +21,11 @@ This module provides straightforward functions to plot QRotor data.
21
21
 
22
22
  from .system import System
23
23
  from . import systems
24
+ from . import constants
24
25
  import matplotlib.pyplot as plt
25
26
  import numpy as np
26
27
  from copy import deepcopy
27
28
  import aton.alias as alias
28
- import aton.phys as phys
29
29
 
30
30
 
31
31
  def potential(
@@ -271,7 +271,7 @@ def splittings(
271
271
  The different `System.comment` are shown in the horizontal axis.
272
272
  An optional `title` can be specified.
273
273
  Default units shown are $\\mu$eV (`'ueV'`).
274
- Available units are: `'ueV'`, `'meV'`, `'Ry'`.
274
+ Available units are: `'ueV'`, `'meV'`, `'Ry'`, or `'B'` (free rotor units).
275
275
  """
276
276
  title = title if title != None else 'Tunnel splitting energies'
277
277
  calcs = deepcopy(data)
@@ -284,11 +284,14 @@ def splittings(
284
284
  x = [c.comment for c in calcs]
285
285
  # What units do we want?
286
286
  if units.lower() in alias.units['ueV']:
287
- y = [j * phys.meV_to_ueV for j in y]
287
+ y = [j * 1000 for j in y] # Convert meV to micro eV
288
288
  ax.set_ylabel("Energy / $\\mu$eV")
289
289
  elif units.lower() in alias.units['Ry']:
290
- y = [j * phys.meV_to_Ry for j in y]
290
+ y = [j * constants.meV_to_Ry for j in y]
291
291
  ax.set_ylabel("Energy / Ry")
292
+ elif units.upper() == 'B':
293
+ y = [j / c.B for j, c in zip(y, calcs)]
294
+ ax.set_ylabel("Energy / B")
292
295
  #else: # It's okay let's use meV
293
296
 
294
297
  ax.bar(range(len(y)), y)
@@ -50,7 +50,6 @@ from scipy.interpolate import CubicSpline
50
50
  import aton.alias as alias
51
51
  import aton.file as file
52
52
  import aton.api.qe as qe
53
- import aton.phys as phys
54
53
  from ._version import __version__
55
54
 
56
55
 
@@ -67,6 +66,7 @@ def save(
67
66
  in degrees and meVs by default.
68
67
  The units can be changed with `angle` and `energy`,
69
68
  but only change these defaults if you know what you are doing.
69
+ An optional `comment` can be included in the header of the file.
70
70
  """
71
71
  print('Saving potential data file...')
72
72
  # Check if a previous potential.dat file exists, and ask to overwrite it
@@ -78,7 +78,7 @@ def save(
78
78
  print("Aborted.")
79
79
  return None
80
80
  # Set header
81
- potential_data = f'# {comment}\n' if comment else f'# {system.comment}\n' if system.comment else ''
81
+ potential_data = f'## {comment}\n' if comment else f'## {system.comment}\n' if system.comment else ''
82
82
  potential_data += '# Rotational potential dataset\n'
83
83
  potential_data += f'# Saved with QRotor {__version__}\n'
84
84
  potential_data += '# https://pablogila.github.io/qrotor\n'
@@ -100,10 +100,10 @@ def save(
100
100
  if energy.lower() in alias.units['meV']:
101
101
  potential_data += 'Potential/meV\n'
102
102
  elif energy.lower() in alias.units['eV']:
103
- potential_values = potential_values * phys.meV_to_eV
103
+ potential_values = potential_values * 1e-3
104
104
  potential_data += 'Potential/eV\n'
105
105
  elif energy.lower() in alias.units['Ry']:
106
- potential_values = potential_values * phys.meV_to_Ry
106
+ potential_values = potential_values * constants.meV_to_Ry
107
107
  potential_data += 'Potential/Ry\n'
108
108
  else:
109
109
  print(f"WARNING: Unrecognised '{energy}' energy units, using meV instead")
@@ -144,6 +144,11 @@ def load(
144
144
  system = System() if system is None else system
145
145
  with open(file_path, 'r') as f:
146
146
  lines = f.readlines()
147
+ # Read the comment
148
+ loaded_comment = ''
149
+ if lines[0].startswith('## '):
150
+ loaded_comment = lines[0][3:].strip()
151
+ # Read data
147
152
  positions = []
148
153
  potentials = []
149
154
  for line in lines:
@@ -161,19 +166,24 @@ def load(
161
166
  raise ValueError(f"Angle unit '{angle}' not recognized.")
162
167
  # Save energies to numpy arrays
163
168
  if energy.lower() in alias.units['eV']:
164
- potentials = np.array(potentials) * phys.eV_to_meV
169
+ potentials = np.array(potentials) * 1000
165
170
  elif energy.lower() in alias.units['meV']:
166
171
  potentials = np.array(potentials)
167
172
  elif energy.lower() in alias.units['Ry']:
168
- potentials = np.array(potentials) * phys.Ry_to_meV
173
+ potentials = np.array(potentials) * constants.Ry_to_meV
169
174
  else:
170
175
  raise ValueError(f"Energy unit '{energy}' not recognized.")
171
176
  # Set the system
172
177
  system.grid = np.array(positions)
173
178
  system.gridsize = len(positions)
174
179
  system.potential_values = np.array(potentials)
175
- # System comment as the parent folder name
176
- system.comment = os.path.basename(os.path.dirname(file_path)) if comment==None else comment
180
+ # System comment as the loaded comment or the parent folder name
181
+ if comment:
182
+ system.comment = comment
183
+ elif loaded_comment:
184
+ system.comment = loaded_comment
185
+ else:
186
+ system.comment = os.path.basename(os.path.dirname(file_path))
177
187
  print(f"Loaded {filepath}")
178
188
  return system
179
189
 
@@ -185,9 +195,10 @@ def from_qe(
185
195
  exclude:list=['slurm-'],
186
196
  energy:str='meV',
187
197
  comment:str=None,
188
- ) -> None:
198
+ ) -> System:
189
199
  """Compiles a rotational potential CSV file from Quantum ESPRESSO outputs,
190
200
  created with `qrotor.rotate.structure_qe()`.
201
+ Returns a `System` object with the new potential values.
191
202
 
192
203
  The angle in degrees is extracted from the output filenames,
193
204
  which must follow `whatever_ANGLE.out`.
@@ -214,7 +225,7 @@ def from_qe(
214
225
  files = file.get_list(folder=folder, include=include, exclude=exclude, abspath=True)
215
226
  folder_name = os.path.basename(folder)
216
227
  # Set header
217
- potential_data = f'# {comment}\n' if comment else f'# {folder_name}\n'
228
+ potential_data = f'## {comment}\n' if comment else f'## {folder_name}\n'
218
229
  potential_data += '# Rotational potential dataset\n'
219
230
  potential_data += f'# Calculated with QE using QRotor {__version__}\n'
220
231
  potential_data += '# https://pablogila.github.io/qrotor\n'
@@ -244,15 +255,15 @@ def from_qe(
244
255
  counter_errors += 1
245
256
  continue
246
257
  if energy.lower() in alias.units['eV']:
247
- energy_value = content['Energy'] * phys.Ry_to_eV
258
+ energy_value = content['Energy'] * constants.Ry_to_eV
248
259
  elif energy.lower() in alias.units['meV']:
249
- energy_value = content['Energy'] * phys.Ry_to_meV
260
+ energy_value = content['Energy'] * constants.Ry_to_meV
250
261
  elif energy.lower() in alias.units['Ry']:
251
262
  energy_value = content['Energy']
252
263
  else:
253
264
  print(f"WARNING: Energy unit '{energy}' not recognized, using meV instead.")
254
265
  energy = 'meV'
255
- energy_value = content['Energy'] * phys.Ry_to_meV
266
+ energy_value = content['Energy'] * constants.Ry_to_meV
256
267
  splits = filename.split('_')
257
268
  angle_value = splits[-1].replace('.out', '')
258
269
  angle_value = float(angle_value)
@@ -274,7 +285,12 @@ def from_qe(
274
285
  # Warn the user if not in default units
275
286
  if energy.lower() not in alias.units['meV']:
276
287
  print(f"WARNING: You saved the potential in '{energy}' units! Remember that QRotor works in meVs!")
277
- return None
288
+ new_system = None
289
+ try:
290
+ new_system = load(filepath=filepath, comment=comment, energy=energy)
291
+ except:
292
+ pass
293
+ return new_system
278
294
 
279
295
 
280
296
  def merge(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrotor
3
- Version: 4.0.0a2
3
+ Version: 4.0.2
4
4
  Summary: QRotor
5
5
  Author: Pablo Gila-Herranz
6
6
  Author-email: pgila001@ikasle.ehu.eus
@@ -21,6 +21,7 @@ Requires-Dist: pandas
21
21
  Requires-Dist: numpy
22
22
  Requires-Dist: matplotlib
23
23
  Requires-Dist: aton
24
+ Requires-Dist: periodictable
24
25
  Dynamic: author
25
26
  Dynamic: author-email
26
27
  Dynamic: classifier
@@ -33,7 +34,7 @@ Dynamic: requires-dist
33
34
  Dynamic: requires-python
34
35
  Dynamic: summary
35
36
 
36
- <p align="center"><img width="40.0%" src="pics/qrotor.png"></p>
37
+ <p align="center"><img width="60.0%" src="pics/qrotor.png"></p>
37
38
 
38
39
  QRotor is a Python package used to study molecular rotations,
39
40
  such as those of methyl and amine groups.
@@ -44,27 +45,66 @@ These quantum systems are represented by the `qrotor.System()` object.
44
45
  QRotor can obtain custom potentials from DFT,
45
46
  which are used to solve the quantum system.
46
47
 
47
- Check the [full documentation online](https://pablogila.github.io/qrotor/).
48
+
49
+ ---
50
+
51
+
52
+ # Installation
53
+
54
+ As always, it is recommended to install your packages in a virtual environment:
55
+ ```bash
56
+ python3 -m venv .venv
57
+ source .venv/bin/activate
58
+ ```
59
+
60
+
61
+ ## With pip
62
+
63
+ Install or upgrade ATON with
64
+ ```bash
65
+ pip install qrotor -U
66
+ ```
67
+
68
+
69
+ ## From source
70
+
71
+ Optionally, you can install ATON from the [GitHub repo](https://github.com/pablogila/qrotor/).
72
+ Clone the repository or download the [latest stable release](https://github.com/pablogila/qrotor/tags)
73
+ as a ZIP, unzip it, and run inside it:
74
+ ```bash
75
+ pip install .
76
+ ```
48
77
 
49
78
 
50
- # Index
79
+ ---
80
+
81
+
82
+ # Documentation
83
+
84
+ QRotor contains the following modules:
51
85
 
52
86
  | | |
53
87
  | --- | --- |
88
+ | [qrotor.constants](https://pablogila.github.io/qrotor/qrotor/constants.html) | Common bond lengths and inertias |
54
89
  | [qrotor.system](https://pablogila.github.io/qrotor/qrotor/system.html) | Definition of the quantum `System` object |
55
- | [qrotor.systems](https://pablogila.github.io/qrotor/qrotor/systems.html) | Functions to manage several System objects, such as a list of systems |
90
+ | [qrotor.systems](https://pablogila.github.io/qrotor/qrotor/systems.html) | Utilities to manage several System objects, such as a list of systems |
56
91
  | [qrotor.rotate](https://pablogila.github.io/qrotor/qrotor/rotate.html) | Rotate specific atoms from structural files |
57
- | [qrotor.constants](https://pablogila.github.io/qrotor/qrotor/constants.html) | Common bond lengths and inertias |
58
92
  | [qrotor.potential](https://pablogila.github.io/qrotor/qrotor/potential.html) | Potential definitions and loading functions |
59
93
  | [qrotor.solve](https://pablogila.github.io/qrotor/qrotor/solve.html) | Solve rotation eigenvalues and eigenvectors |
60
- | [qrotor.plot](https://pablogila.github.io/qrotor/qrotor/plot.html) | Plotting functions |
94
+ | [qrotor.plot](https://pablogila.github.io/qrotor/qrotor/plot.html) | Plotting utilities |
95
+
96
+ Check the [full documentation online](https://pablogila.github.io/qrotor/).
97
+
98
+
99
+ ---
61
100
 
62
101
 
63
102
  # Usage
64
103
 
65
104
  ## Solving quantum rotational systems
66
105
 
67
- A basic calculation of the eigenvalues for a zero potential goes as follows.
106
+ Let's start with a basic calculation of the eigenvalues for a zero potential, corresponding to a free rotor.
107
+ A predefined synthetic potential can be used, see all available options in the [qrotor.potential](https://pablogila.github.io/qrotor/qrotor/potential.html) documentation.
68
108
  Note that the default energy unit is meV unless stated otherwise.
69
109
 
70
110
  ```python
@@ -74,7 +114,7 @@ system.gridsize = 200000 # Size of the potential grid
74
114
  system.B = 1 # Rotational inertia
75
115
  system.potential_name = 'zero'
76
116
  system.solve()
77
- system.eigenvalues
117
+ print(system.eigenvalues)
78
118
  # [0.0, 1.0, 1.0, 4.0, 4.0, 9.0, 9.0, ...] # approx values
79
119
  ```
80
120
 
@@ -87,10 +127,10 @@ in a cosine potential of amplitude 30 meV:
87
127
  ```python
88
128
  import qrotor as qr
89
129
  system = qr.System()
90
- system.gridsize = 200000 # Size of the potential grid
130
+ system.gridsize = 200000
91
131
  system.B = qr.B_CH3 # Rotational inertia of a methyl group
92
132
  system.potential_name = 'cosine'
93
- system.potential_constants = [0, 30, 3, 0] # Offset, max, freq, phase (for cos pot.)
133
+ system.potential_constants = [0, 30, 3, 0] # Offset, max, freq, phase (for cosine potential)
94
134
  system.solve()
95
135
  # Plot potential and eigenvalues
96
136
  qr.plot.energies(system)
@@ -102,7 +142,7 @@ qr.plot.wavefunction(system, levels=[0,1,2], square=True)
102
142
  ## Custom potentials from DFT
103
143
 
104
144
  QRotor can be used to obtain custom rotational potentials from DFT calculations.
105
- Using Quantum ESPRESSO, running an SCF calculation for a methyl rotation every 10 degrees:
145
+ To run a Quantum ESPRESSO SCF calculation for a methyl rotation every 10 degrees:
106
146
 
107
147
  ```python
108
148
  import qrotor as qr
@@ -121,10 +161,8 @@ api.slurm.sbatch(files=scf_files)
121
161
 
122
162
  To load the calculated potential to a QRotor System,
123
163
  ```python
124
- # Compile a 'potential.csv' file with the calculated potential as a function of the angle
125
- qr.potential.from_qe()
126
- # Load to the system
127
- system = qr.potential.load()
164
+ # Compile a 'potential.csv' file with the calculated potential as a function of the angle, and load it into a new system
165
+ system = qr.potential.from_qe()
128
166
  # Solve the system, interpolating to a bigger gridsize
129
167
  system.B = qr.B_CH3
130
168
  system.solve(200000)
@@ -139,9 +177,9 @@ below the potential maximum are also calculated upon solving the system:
139
177
 
140
178
  ```python
141
179
  system.solve()
142
- system.splittings
143
- system.excitations
144
- system.deg
180
+ print(system.splittings)
181
+ print(system.excitations)
182
+ print(system.deg)
145
183
  ```
146
184
 
147
185
  An integer `System.deg` degeneracy (e.g. 3 for methyls)
@@ -165,3 +203,71 @@ See [R. M. Dimeo, American Journal of Physics 71, 885–893 (2003)](https://doi.
165
203
  and [A. J. Horsewill, Progress in Nuclear Magnetic Resonance Spectroscopy 35, 359–389 (1999)](https://doi.org/10.1016/S0079-6565(99)00016-3)
166
204
  for further reference.
167
205
 
206
+
207
+ ---
208
+
209
+
210
+ # Contributing
211
+
212
+ If you are interested in opening an issue or a pull request, please feel free to do so on [GitHub](https://github.com/pablogila/qrotor/).
213
+ For major changes, please get in touch first to discuss the details.
214
+
215
+
216
+ ## Code style
217
+
218
+ Please try to follow some general guidelines:
219
+ - Use a code style consistent with the rest of the project.
220
+ - Include docstrings to document new additions.
221
+ - Include automated tests for new features or modifications, see [automated testing](#automated-testing).
222
+ - Arrange function arguments by order of relevance.
223
+
224
+
225
+ ## Automated testing
226
+
227
+ If you are modifying the source code, you should run the automated tests of the [`tests/`](https://github.com/pablogila/qrotor/tree/main/tests) folder to check that everything works as intended.
228
+ To do so, first install PyTest in your environment,
229
+ ```bash
230
+ pip install pytest
231
+ ```
232
+
233
+ And then run PyTest inside the main directory,
234
+ ```bash
235
+ pytest -vv
236
+ ```
237
+
238
+
239
+ ## Compiling the documentation
240
+
241
+ The documentation can be compiled automatically to `docs/qrotor.html` with [Pdoc](https://pdoc.dev/) and [ATON](https://pablogila.github.io/aton), by running:
242
+ ```shell
243
+ python3 makedocs.py
244
+ ```
245
+
246
+ This runs Pdoc, updating links and pictures, and using the custom theme CSS template from the `css/` folder.
247
+
248
+
249
+ ---
250
+
251
+
252
+ # Citation
253
+
254
+ QRotor is currently under development.
255
+ Please cite it if you use it in your research,
256
+ > Pablo Gila-Herranz, *QRotor*, https://pablogila.github.io/qrotor
257
+
258
+
259
+ ---
260
+
261
+
262
+ # License
263
+
264
+ Copyright (C) 2025 Pablo Gila-Herranz
265
+ This program is free software: you can redistribute it and/or modify
266
+ it under the terms of the **GNU Affero General Public License** as published
267
+ by the Free Software Foundation, either version **3** of the License, or
268
+ (at your option) any later version.
269
+ This program is distributed in the hope that it will be useful,
270
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
271
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
272
+ See the attached GNU Affero General Public License for more details.
273
+
@@ -16,4 +16,8 @@ qrotor.egg-info/dependency_links.txt
16
16
  qrotor.egg-info/requires.txt
17
17
  qrotor.egg-info/top_level.txt
18
18
  tests/__init__.py
19
- tests/test_qrotor.py
19
+ tests/test_constants.py
20
+ tests/test_potential.py
21
+ tests/test_rotate.py
22
+ tests/test_solve.py
23
+ tests/test_system.py
@@ -3,3 +3,4 @@ pandas
3
3
  numpy
4
4
  matplotlib
5
5
  aton
6
+ periodictable
@@ -1,7 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
3
  DESCRIPTION = "QRotor"
4
- LONG_DESCRIPTION = "QRotor"
5
4
 
6
5
  exec(open('qrotor/_version.py').read())
7
6
 
@@ -17,7 +16,7 @@ setup(
17
16
  long_description = LONG_DESCRIPTION,
18
17
  long_description_content_type = 'text/markdown',
19
18
  packages = find_packages(),
20
- install_requires = ['scipy', 'pandas', 'numpy', 'matplotlib', 'aton'],
19
+ install_requires = ['scipy', 'pandas', 'numpy', 'matplotlib', 'aton', 'periodictable'],
21
20
  extras_requires = {'dev': ['pytest', 'twine', 'build']},
22
21
  python_requires = '>=3',
23
22
  license = 'AGPL-3.0',
@@ -0,0 +1,13 @@
1
+ import qrotor as qr
2
+
3
+
4
+ def test_constants():
5
+ assert round(qr.B_CH3, 5) == 0.64518
6
+ assert round(qr.B_CD3, 5) == 0.32289
7
+ assert round(qr.B_NH3, 5) == 0.73569
8
+ assert round(qr.B_ND3, 5) == 0.36819
9
+ assert round(qr.Ry_to_eV, 5) == 13.60569
10
+ assert round(qr.Ry_to_meV, 5) == 13605.69312
11
+ assert round(qr.eV_to_Ry, 5) == 0.07350
12
+ assert round(qr.meV_to_Ry, 10) == .0000734986
13
+
@@ -0,0 +1,37 @@
1
+ import qrotor as qr
2
+ import aton
3
+
4
+
5
+ folder = 'tests/samples/'
6
+ structure = folder + 'CH3NH3.in'
7
+ structure_120 = folder + 'CH3NH3_120.in'
8
+ structure_60 = folder + 'CH3NH3_60.in'
9
+
10
+
11
+ def test_save_and_load():
12
+ system = qr.System()
13
+ system.gridsize = 36
14
+ system.potential_name = 'sin'
15
+ system.B = 1
16
+ system.solve_potential()
17
+ potential_file = folder + '_temp_potential.csv'
18
+ # Remove the file if it exists
19
+ try:
20
+ aton.file.remove(potential_file)
21
+ except:
22
+ pass
23
+ qr.potential.save(system, comment='hi', filepath=potential_file)
24
+ system_new = qr.potential.load(potential_file)
25
+ assert system_new.gridsize == system.gridsize
26
+ assert round(system_new.potential_values[0], 5) == round(system.potential_values[0], 5)
27
+ assert round(system_new.potential_values[5], 5) == round(system.potential_values[5], 5)
28
+ assert round(system_new.potential_values[13], 5) == round(system.potential_values[13], 5)
29
+ assert system_new.comment == 'hi'
30
+ aton.file.remove(potential_file)
31
+ # If we don't provide a comment, it should be the name of the folder
32
+ system.comment = None
33
+ qr.potential.save(system, filepath=potential_file)
34
+ system_new = qr.potential.load(potential_file)
35
+ assert system_new.comment == 'samples'
36
+ aton.file.remove(potential_file)
37
+
@@ -1,8 +1,7 @@
1
- import aton.qrotor as qr
1
+ import qrotor as qr
2
2
  import aton.api as api
3
3
  import aton.txt.extract as extract
4
4
  import aton.file as file
5
- import numpy as np
6
5
 
7
6
 
8
7
  folder = 'tests/samples/'
@@ -52,50 +51,3 @@ def test_rotate():
52
51
  assert coord_rounded == rotated_coord_rounded
53
52
  file.remove(structure_60)
54
53
 
55
-
56
- def test_solve_zero():
57
- system = qr.System()
58
- system.gridsize = 50000
59
- system.potential_name = 'zero'
60
- system.B = 1
61
- system.solve()
62
- assert round(system.eigenvalues[0], 2) == 0.0
63
- assert round(system.eigenvalues[1], 2) == 1.0
64
- assert round(system.eigenvalues[2], 2) == 1.0
65
- assert round(system.eigenvalues[3], 2) == 4.0
66
- assert round(system.eigenvalues[4], 2) == 4.0
67
- assert round(system.eigenvalues[5], 2) == 9.0
68
- assert round(system.eigenvalues[6], 2) == 9.0
69
- assert round(system.eigenvalues[7], 2) == 16.0
70
- assert round(system.eigenvalues[8], 2) == 16.0
71
-
72
-
73
- def test_solve_potential():
74
- system = qr.System()
75
- system.gridsize = 500
76
- system.potential_name = 'sin'
77
- system.potential_constants = [0, 1, 3, 0]
78
- system.solve_potential()
79
- assert round(system.potential_max, 2) == 1.0
80
-
81
-
82
- def test_phase():
83
- sys = qr.System()
84
- sys.B = 1.0
85
- sys.potential_name = 'cos'
86
- sys.gridsize = 10000
87
- sys.solve()
88
- # plus pi/2, which will be -3pi/2
89
- sys.change_phase(0.5)
90
- assert round(sys.grid[0], 2) == round(-np.pi * 3/2, 2)
91
- # The first potential value should be 0,
92
- # but remember that the potential offset is corrected
93
- # so it should be half potential_max, so 1.0/2
94
- assert round(sys.potential_values[0], 2) == 0.5
95
- # minus pi, which will become -pi/2
96
- sys.change_phase(-1)
97
- assert round(sys.grid[0], 2) == round(-np.pi/2, 2)
98
- assert round(sys.potential_values[0], 2) == 0.5
99
- # Were eigenvalues calculated?
100
- assert len(sys.eigenvalues) > 0
101
-
@@ -0,0 +1,28 @@
1
+ import qrotor as qr
2
+
3
+
4
+ def test_solve_zero():
5
+ system = qr.System()
6
+ system.gridsize = 50000
7
+ system.potential_name = 'zero'
8
+ system.B = 1
9
+ system.solve()
10
+ assert round(system.eigenvalues[0], 2) == 0.0
11
+ assert round(system.eigenvalues[1], 2) == 1.0
12
+ assert round(system.eigenvalues[2], 2) == 1.0
13
+ assert round(system.eigenvalues[3], 2) == 4.0
14
+ assert round(system.eigenvalues[4], 2) == 4.0
15
+ assert round(system.eigenvalues[5], 2) == 9.0
16
+ assert round(system.eigenvalues[6], 2) == 9.0
17
+ assert round(system.eigenvalues[7], 2) == 16.0
18
+ assert round(system.eigenvalues[8], 2) == 16.0
19
+
20
+
21
+ def test_solve_potential():
22
+ system = qr.System()
23
+ system.gridsize = 500
24
+ system.potential_name = 'sin'
25
+ system.potential_constants = [0, 1, 3, 0]
26
+ system.solve_potential()
27
+ assert round(system.potential_max, 2) == 1.0
28
+
@@ -0,0 +1,24 @@
1
+ import qrotor as qr
2
+ import numpy as np
3
+
4
+
5
+ def test_phase():
6
+ sys = qr.System()
7
+ sys.B = 1.0
8
+ sys.potential_name = 'cos'
9
+ sys.gridsize = 10000
10
+ sys.solve()
11
+ # plus pi/2, which will be -3pi/2
12
+ sys.change_phase(0.5)
13
+ assert round(sys.grid[0], 2) == round(-np.pi * 3/2, 2)
14
+ # The first potential value should be 0,
15
+ # but remember that the potential offset is corrected
16
+ # so it should be half potential_max, so 1.0/2
17
+ assert round(sys.potential_values[0], 2) == 0.5
18
+ # minus pi, which will become -pi/2
19
+ sys.change_phase(-1)
20
+ assert round(sys.grid[0], 2) == round(-np.pi/2, 2)
21
+ assert round(sys.potential_values[0], 2) == 0.5
22
+ # Were eigenvalues calculated?
23
+ assert len(sys.eigenvalues) > 0
24
+
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes