qrotor 4.2.2__tar.gz → 4.4.0__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.
- {qrotor-4.2.2 → qrotor-4.4.0}/PKG-INFO +1 -1
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/_version.py +1 -1
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/plot.py +7 -4
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/potential.py +8 -5
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/rotate.py +8 -8
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/system.py +9 -50
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/systems.py +127 -25
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor.egg-info/PKG-INFO +1 -1
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor.egg-info/SOURCES.txt +0 -1
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor.egg-info/top_level.txt +0 -1
- {qrotor-4.2.2 → qrotor-4.4.0}/tests/test_rotate.py +4 -4
- qrotor-4.2.2/tests/__init__.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/LICENSE +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/README.md +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/__init__.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/constants.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor/solve.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor.egg-info/dependency_links.txt +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/qrotor.egg-info/requires.txt +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/setup.cfg +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/setup.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/tests/test_constants.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/tests/test_potential.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/tests/test_solve.py +0 -0
- {qrotor-4.2.2 → qrotor-4.4.0}/tests/test_system.py +0 -0
|
@@ -98,7 +98,10 @@ def energies(
|
|
|
98
98
|
data,
|
|
99
99
|
title:str=None,
|
|
100
100
|
) -> None:
|
|
101
|
-
"""Plot the eigenvalues of `data` (System or a list of System objects).
|
|
101
|
+
"""Plot the eigenvalues of `data` (System or a list of System objects).
|
|
102
|
+
|
|
103
|
+
You can use up to 1 tag per system to differentiate between molecular groups.
|
|
104
|
+
"""
|
|
102
105
|
if isinstance(data, System):
|
|
103
106
|
var = [data]
|
|
104
107
|
else: # Should be a list
|
|
@@ -137,14 +140,14 @@ def energies(
|
|
|
137
140
|
# Plot eigenvalues
|
|
138
141
|
if any(system.eigenvalues):
|
|
139
142
|
text_offset = 3 * len(unique_groups)
|
|
140
|
-
if system.
|
|
141
|
-
unique_groups.append(system.
|
|
143
|
+
if system.tags not in unique_groups:
|
|
144
|
+
unique_groups.append(system.tags)
|
|
142
145
|
for j, energy in enumerate(system.eigenvalues):
|
|
143
146
|
plt.axhline(y=energy, color=E_color, linestyle=E_linestyle)
|
|
144
147
|
# Textbox positions are a bit weird when plotting more than 2 systems, but whatever...
|
|
145
148
|
plt.text(j%3*1.0 + text_offset, energy, f'$E_{{{j}}}$ = {round(energy,4):.04f}', va='top', bbox=dict(edgecolor=edgecolor, boxstyle='round,pad=0.2', facecolor='white', alpha=0.8))
|
|
146
149
|
if len(systems.get_groups(var)) > 1:
|
|
147
|
-
plt.plot([], [], color=E_color, label=f'{system.
|
|
150
|
+
plt.plot([], [], color=E_color, label=f'{system.tags} Energies') # Add to legend
|
|
148
151
|
|
|
149
152
|
if len(systems.get_groups(var)) > 1:
|
|
150
153
|
plt.subplots_adjust(right=0.85)
|
|
@@ -49,7 +49,7 @@ from copy import deepcopy
|
|
|
49
49
|
from scipy.interpolate import CubicSpline
|
|
50
50
|
import aton.alias as alias
|
|
51
51
|
import aton.file as file
|
|
52
|
-
import aton.api.
|
|
52
|
+
import aton.api.pwx as pwx
|
|
53
53
|
from ._version import __version__
|
|
54
54
|
|
|
55
55
|
|
|
@@ -125,6 +125,7 @@ def save(
|
|
|
125
125
|
def load(
|
|
126
126
|
filepath:str='potential.csv',
|
|
127
127
|
comment:str=None,
|
|
128
|
+
tags:str='',
|
|
128
129
|
system:System=None,
|
|
129
130
|
angle:str='deg',
|
|
130
131
|
energy:str='meV',
|
|
@@ -184,6 +185,8 @@ def load(
|
|
|
184
185
|
system.comment = loaded_comment
|
|
185
186
|
else:
|
|
186
187
|
system.comment = os.path.basename(os.path.dirname(file_path))
|
|
188
|
+
if tags:
|
|
189
|
+
system.tags = tags
|
|
187
190
|
print(f"Loaded {filepath}")
|
|
188
191
|
return system
|
|
189
192
|
|
|
@@ -196,8 +199,8 @@ def from_qe(
|
|
|
196
199
|
energy:str='meV',
|
|
197
200
|
comment:str=None,
|
|
198
201
|
) -> System:
|
|
199
|
-
"""Compiles a rotational potential CSV file from Quantum ESPRESSO outputs,
|
|
200
|
-
created with `qrotor.rotate.
|
|
202
|
+
"""Compiles a rotational potential CSV file from Quantum ESPRESSO pw.x outputs,
|
|
203
|
+
created with `qrotor.rotate.input_qe()`.
|
|
201
204
|
Returns a `System` object with the new potential values.
|
|
202
205
|
|
|
203
206
|
The angle in degrees is extracted from the output filenames,
|
|
@@ -227,7 +230,7 @@ def from_qe(
|
|
|
227
230
|
# Set header
|
|
228
231
|
potential_data = f'## {comment}\n' if comment else f'## {folder_name}\n'
|
|
229
232
|
potential_data += '# Rotational potential dataset\n'
|
|
230
|
-
potential_data += f'# Calculated with QE using QRotor {__version__}\n'
|
|
233
|
+
potential_data += f'# Calculated with QE pw.x using QRotor {__version__}\n'
|
|
231
234
|
potential_data += '# https://pablogila.github.io/qrotor\n'
|
|
232
235
|
potential_data += '#\n'
|
|
233
236
|
if energy.lower() in alias.units['eV']:
|
|
@@ -249,7 +252,7 @@ def from_qe(
|
|
|
249
252
|
file_path = file.get(filepath=file_path, include='.out', return_anyway=True)
|
|
250
253
|
if not file_path: # Not an output file, skip it
|
|
251
254
|
continue
|
|
252
|
-
content =
|
|
255
|
+
content = pwx.read_out(file_path)
|
|
253
256
|
if not content['Success']: # Ignore unsuccessful calculations
|
|
254
257
|
print(f'x {filename}')
|
|
255
258
|
counter_errors += 1
|
|
@@ -9,7 +9,7 @@ Works with Quantum ESPRESSO input files.
|
|
|
9
9
|
|
|
10
10
|
| | |
|
|
11
11
|
| --- | --- |
|
|
12
|
-
| `
|
|
12
|
+
| `input_qe()` | Rotate specific atoms from a Quantum ESPRESSO input file |
|
|
13
13
|
| `rotate_coords()` | Rotate a specific list of coordinates |
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -26,7 +26,7 @@ import aton.txt.extract as extract
|
|
|
26
26
|
import aton.txt.edit as edit
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
def
|
|
29
|
+
def input_qe(
|
|
30
30
|
filepath:str,
|
|
31
31
|
positions:list,
|
|
32
32
|
angle:float,
|
|
@@ -66,13 +66,13 @@ def structure_qe(
|
|
|
66
66
|
lines = []
|
|
67
67
|
full_positions = []
|
|
68
68
|
for position in positions:
|
|
69
|
-
line = api.
|
|
69
|
+
line = api.pwx.get_atom(filepath, position, precision)
|
|
70
70
|
lines.append(line)
|
|
71
71
|
pos = extract.coords(line)
|
|
72
72
|
if len(pos) > 3: # Keep only the first three coordinates
|
|
73
73
|
pos = pos[:3]
|
|
74
74
|
# Convert to cartesian
|
|
75
|
-
pos_cartesian = api.
|
|
75
|
+
pos_cartesian = api.pwx.to_cartesian(filepath, pos)
|
|
76
76
|
full_positions.append(pos_cartesian)
|
|
77
77
|
print(f'Found atom: "{line}"')
|
|
78
78
|
# Set the angles to rotate
|
|
@@ -92,7 +92,7 @@ def structure_qe(
|
|
|
92
92
|
rotated_positions_cartesian = rotate_coords(full_positions, angle, use_centroid, show_axis)
|
|
93
93
|
rotated_positions = []
|
|
94
94
|
for coord in rotated_positions_cartesian:
|
|
95
|
-
pos = api.
|
|
95
|
+
pos = api.pwx.from_cartesian(filepath, coord)
|
|
96
96
|
rotated_positions.append(pos)
|
|
97
97
|
_save_qe(filepath, output, lines, rotated_positions)
|
|
98
98
|
outputs.append(output)
|
|
@@ -184,7 +184,7 @@ def _save_qe(
|
|
|
184
184
|
additional_positions = positions[-2:]
|
|
185
185
|
for pos in additional_positions:
|
|
186
186
|
pos.insert(0, 'He')
|
|
187
|
-
api.
|
|
187
|
+
api.pwx.add_atom(output, pos)
|
|
188
188
|
elif len(lines) != len(positions):
|
|
189
189
|
raise ValueError(f"What?! len(lines)={len(lines)} and len(positions)={len(positions)}")
|
|
190
190
|
# Add angle to calculation prefix
|
|
@@ -192,11 +192,11 @@ def _save_qe(
|
|
|
192
192
|
splits = output_name.split('_')
|
|
193
193
|
angle_str = splits[-1].replace('.in', '')
|
|
194
194
|
prefix = ''
|
|
195
|
-
content = api.
|
|
195
|
+
content = api.pwx.read_in(output)
|
|
196
196
|
if 'prefix' in content.keys():
|
|
197
197
|
prefix = content['prefix']
|
|
198
198
|
prefix = prefix.strip("'")
|
|
199
199
|
prefix = "'" + prefix + angle_str + "'"
|
|
200
|
-
api.
|
|
200
|
+
api.pwx.set_value(output, 'prefix', prefix)
|
|
201
201
|
return output
|
|
202
202
|
|
|
@@ -24,16 +24,14 @@ class System:
|
|
|
24
24
|
def __init__(
|
|
25
25
|
self,
|
|
26
26
|
comment: str = None,
|
|
27
|
+
B: float = B_CH3,
|
|
28
|
+
gridsize: int = 200000,
|
|
27
29
|
searched_E: int = 21,
|
|
28
30
|
correct_potential_offset: bool = True,
|
|
29
31
|
save_eigenvectors: bool = True,
|
|
30
|
-
group: str = '',
|
|
31
|
-
B: float = B_CH3,
|
|
32
|
-
gridsize: int = 200000,
|
|
33
|
-
grid = [],
|
|
34
32
|
potential_name: str = '',
|
|
35
33
|
potential_constants: list = None,
|
|
36
|
-
|
|
34
|
+
tags: str = '',
|
|
37
35
|
):
|
|
38
36
|
"""A new quantum system can be instantiated as `system = qrotor.System()`.
|
|
39
37
|
This new system will contain the default values listed above.
|
|
@@ -49,17 +47,12 @@ class System:
|
|
|
49
47
|
"""Correct the potential offset as `V - min(V)` or not."""
|
|
50
48
|
self.save_eigenvectors: bool = save_eigenvectors
|
|
51
49
|
"""Save or not the eigenvectors. Final file size will be bigger."""
|
|
52
|
-
self.
|
|
53
|
-
"""
|
|
50
|
+
self.tags: str = tags
|
|
51
|
+
"""Custom tags separated by spaces, such as the molecular group, etc.
|
|
54
52
|
|
|
55
|
-
Can be used to
|
|
56
|
-
It can also be configured afterwards with `System.set_group()`.
|
|
57
|
-
This group can be used as metadata to analyse different datasets.
|
|
53
|
+
Can be used to filter between datasets.
|
|
58
54
|
"""
|
|
59
|
-
self.set_group(group) # Normalise the group name, and set the value of B
|
|
60
55
|
## Potential
|
|
61
|
-
if not B:
|
|
62
|
-
B = self.B
|
|
63
56
|
self.B: float = B
|
|
64
57
|
"""Kinetic rotational energy, as in $B=\\frac{\\hbar^2}{2I}$.
|
|
65
58
|
|
|
@@ -67,7 +60,7 @@ class System:
|
|
|
67
60
|
"""
|
|
68
61
|
self.gridsize: int = gridsize
|
|
69
62
|
"""Number of points in the grid."""
|
|
70
|
-
self.grid =
|
|
63
|
+
self.grid = []
|
|
71
64
|
"""The grid with the points to be used in the calculation.
|
|
72
65
|
|
|
73
66
|
Can be set automatically over $2 \\pi$ with `System.set_grid()`.
|
|
@@ -80,7 +73,7 @@ class System:
|
|
|
80
73
|
"""
|
|
81
74
|
self.potential_constants: list = potential_constants
|
|
82
75
|
"""List of constants to be used in the calculation of the potential energy, in the `qrotor.potential` module."""
|
|
83
|
-
self.potential_values =
|
|
76
|
+
self.potential_values = []
|
|
84
77
|
"""Numpy [ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) with the potential values for each point in the grid.
|
|
85
78
|
|
|
86
79
|
Can be calculated with a function available in the `qrotor.potential` module,
|
|
@@ -205,40 +198,6 @@ class System:
|
|
|
205
198
|
else:
|
|
206
199
|
raise ValueError('gridsize must be provided if there is no System.gridsize')
|
|
207
200
|
return self
|
|
208
|
-
|
|
209
|
-
def set_group(self, group:str=None, B:float=None):
|
|
210
|
-
"""Normalise `System.group` name, and set `System.B` based on it."""
|
|
211
|
-
for name in alias.chemical['CH3']:
|
|
212
|
-
if group.lower() == name:
|
|
213
|
-
self.group = 'CH3'
|
|
214
|
-
if not B:
|
|
215
|
-
B = B_CH3
|
|
216
|
-
self.B = B
|
|
217
|
-
return self
|
|
218
|
-
for name in alias.chemical['CD3']:
|
|
219
|
-
if group.lower() == name:
|
|
220
|
-
self.group = 'CD3'
|
|
221
|
-
if not B:
|
|
222
|
-
B = B_CD3
|
|
223
|
-
self.B = B
|
|
224
|
-
return self
|
|
225
|
-
for name in alias.chemical['NH3']:
|
|
226
|
-
if group.lower() == name:
|
|
227
|
-
self.group = 'NH3'
|
|
228
|
-
if not B:
|
|
229
|
-
B = B_NH3
|
|
230
|
-
self.B = B
|
|
231
|
-
return self
|
|
232
|
-
for name in alias.chemical['ND3']:
|
|
233
|
-
if group.lower() == name:
|
|
234
|
-
self.group = 'ND3'
|
|
235
|
-
if not B:
|
|
236
|
-
B = B_ND3
|
|
237
|
-
self.B = B
|
|
238
|
-
return self
|
|
239
|
-
self.group = group # No match was found
|
|
240
|
-
self.B = None
|
|
241
|
-
return self
|
|
242
201
|
|
|
243
202
|
def reduce_size(self):
|
|
244
203
|
"""Discard data that takes too much space,
|
|
@@ -256,7 +215,7 @@ class System:
|
|
|
256
215
|
'searched_E': self.searched_E,
|
|
257
216
|
'correct_potential_offset': self.correct_potential_offset,
|
|
258
217
|
'save_eigenvectors': self.save_eigenvectors,
|
|
259
|
-
'
|
|
218
|
+
'tags': self.tags,
|
|
260
219
|
'B': self.B,
|
|
261
220
|
'gridsize': self.gridsize,
|
|
262
221
|
'potential_name': self.potential_name,
|
|
@@ -12,14 +12,16 @@ These are commonly used as a list of `System` objects.
|
|
|
12
12
|
| `as_list()` | Ensures that a list only contains System objects |
|
|
13
13
|
| `save_energies()` | Save the energy eigenvalues for all systems to a CSV |
|
|
14
14
|
| `save_splittings()` | Save the tunnel splitting energies for all systems to a CSV |
|
|
15
|
+
| `save_summary()` | Save a summary of some relevant parameters for all systems to a CSV |
|
|
15
16
|
| `get_energies()` | Get the eigenvalues from all systems |
|
|
16
17
|
| `get_gridsizes()` | Get all gridsizes |
|
|
17
18
|
| `get_runtimes()` | Get all runtimes |
|
|
18
|
-
| `get_groups()` | Get the chemical groups in use |
|
|
19
19
|
| `get_ideal_E()` | Calculate the ideal energy for a specified level |
|
|
20
20
|
| `sort_by_gridsize()` | Sort systems by gridsize |
|
|
21
21
|
| `reduce_size()` | Discard data that takes too much space |
|
|
22
22
|
| `summary()` | Print a summary of a System or list of Systems |
|
|
23
|
+
| `list_tags()` | Get a list with all system tags |
|
|
24
|
+
| `filter_tags()` | Filter the systems with or without specific tags |
|
|
23
25
|
|
|
24
26
|
---
|
|
25
27
|
"""
|
|
@@ -51,9 +53,9 @@ def as_list(systems) -> None:
|
|
|
51
53
|
def save_energies(
|
|
52
54
|
systems:list,
|
|
53
55
|
comment:str='',
|
|
54
|
-
filepath:str='
|
|
56
|
+
filepath:str='qrotor_eigenvalues.csv',
|
|
55
57
|
) -> pd.DataFrame:
|
|
56
|
-
"""Save the energy eigenvalues for all `systems` to a
|
|
58
|
+
"""Save the energy eigenvalues for all `systems` to a qrotor_eigenvalues.csv file.
|
|
57
59
|
|
|
58
60
|
Returns a Pandas Dataset with `System.comment` columns and `System.eigenvalues` values.
|
|
59
61
|
|
|
@@ -62,7 +64,7 @@ def save_energies(
|
|
|
62
64
|
A `comment` can be included at the top of the file.
|
|
63
65
|
Note that `System.comment` must not include commas (`,`).
|
|
64
66
|
"""
|
|
65
|
-
as_list(systems)
|
|
67
|
+
systems = as_list(systems)
|
|
66
68
|
version = systems[0].version
|
|
67
69
|
E = {}
|
|
68
70
|
# Find max length of eigenvalues
|
|
@@ -81,7 +83,7 @@ def save_energies(
|
|
|
81
83
|
# Else save to file
|
|
82
84
|
df.to_csv(filepath, sep=',', index=False)
|
|
83
85
|
# Include a comment at the top of the file
|
|
84
|
-
file_comment = f'
|
|
86
|
+
file_comment = f'## {comment}\n' if comment else f''
|
|
85
87
|
file_comment += f'# Energy eigenvalues\n'
|
|
86
88
|
file_comment += f'# Calculated with QRotor {version}\n'
|
|
87
89
|
file_comment += f'# https://pablogila.github.io/qrotor\n#'
|
|
@@ -93,9 +95,9 @@ def save_energies(
|
|
|
93
95
|
def save_splittings(
|
|
94
96
|
systems:list,
|
|
95
97
|
comment:str='',
|
|
96
|
-
filepath:str='
|
|
98
|
+
filepath:str='qrotor_splittings.csv',
|
|
97
99
|
) -> pd.DataFrame:
|
|
98
|
-
"""Save the tunnel splitting energies for all `systems` to a
|
|
100
|
+
"""Save the tunnel splitting energies for all `systems` to a qrotor_splittings.csv file.
|
|
99
101
|
|
|
100
102
|
Returns a Pandas Dataset with `System.comment` columns and `System.splittings` values.
|
|
101
103
|
|
|
@@ -105,7 +107,7 @@ def save_splittings(
|
|
|
105
107
|
Note that `System.comment` must not include commas (`,`).
|
|
106
108
|
Different splitting lengths across systems are allowed - missing values will be NaN.
|
|
107
109
|
"""
|
|
108
|
-
as_list(systems)
|
|
110
|
+
systems = as_list(systems)
|
|
109
111
|
version = systems[0].version
|
|
110
112
|
tunnelling_E = {}
|
|
111
113
|
# Find max length of splittings
|
|
@@ -119,7 +121,7 @@ def save_splittings(
|
|
|
119
121
|
# Else save to file
|
|
120
122
|
df.to_csv(filepath, sep=',', index=False)
|
|
121
123
|
# Include a comment at the top of the file
|
|
122
|
-
file_comment = f'
|
|
124
|
+
file_comment = f'## {comment}\n' if comment else f''
|
|
123
125
|
file_comment += f'# Tunnel splitting energies\n'
|
|
124
126
|
file_comment += f'# Calculated with QRotor {version}\n'
|
|
125
127
|
file_comment += f'# https://pablogila.github.io/qrotor\n#'
|
|
@@ -128,12 +130,80 @@ def save_splittings(
|
|
|
128
130
|
return df
|
|
129
131
|
|
|
130
132
|
|
|
133
|
+
def save_summary(
|
|
134
|
+
systems:list,
|
|
135
|
+
comment:str='',
|
|
136
|
+
filepath:str='qrotor_summary.csv',
|
|
137
|
+
) -> pd.DataFrame:
|
|
138
|
+
"""Save a summary for all `systems` to a qrotor_summary.csv file.
|
|
139
|
+
|
|
140
|
+
Produces one row per System with the columns:
|
|
141
|
+
`comment`, `ZPE`, `E_activation`, `potential_max`, `1st_splitting`,
|
|
142
|
+
`1st_excitation`, `B`, `degeneracy`, `gridsize`.
|
|
143
|
+
|
|
144
|
+
Set `filepath` to null to just return the DataFrame.
|
|
145
|
+
"""
|
|
146
|
+
systems = as_list(systems)
|
|
147
|
+
version = systems[0].version
|
|
148
|
+
rows = []
|
|
149
|
+
for s in systems:
|
|
150
|
+
eigenvalues = getattr(s, 'eigenvalues', None)
|
|
151
|
+
if eigenvalues is not None and len(eigenvalues) > 0:
|
|
152
|
+
first_val = eigenvalues[0]
|
|
153
|
+
zpe = float('nan') if first_val is None else first_val
|
|
154
|
+
else:
|
|
155
|
+
zpe = float('nan')
|
|
156
|
+
splittings = getattr(s, 'splittings', None)
|
|
157
|
+
if splittings is not None and len(splittings) > 0:
|
|
158
|
+
first_splitting = float('nan') if splittings[0] is None else splittings[0]
|
|
159
|
+
else:
|
|
160
|
+
first_splitting = float('nan')
|
|
161
|
+
excitations = getattr(s, 'excitations', None)
|
|
162
|
+
if excitations is not None and len(excitations) > 0:
|
|
163
|
+
first_excitation = float('nan') if excitations[0] is None else excitations[0]
|
|
164
|
+
else:
|
|
165
|
+
first_excitation = float('nan')
|
|
166
|
+
system_comment = getattr(s, 'comment', None)
|
|
167
|
+
E_activation = getattr(s, 'E_activation', None)
|
|
168
|
+
B = getattr(s, 'B', None)
|
|
169
|
+
tags = getattr(s, 'tags', None)
|
|
170
|
+
deg = getattr(s, 'deg', None)
|
|
171
|
+
gridsize = getattr(s, 'gridsize', None)
|
|
172
|
+
potential_max = getattr(s, 'potential_max', None)
|
|
173
|
+
# Each row contains the following:
|
|
174
|
+
rows.append({
|
|
175
|
+
'comment': system_comment,
|
|
176
|
+
'ZPE': zpe,
|
|
177
|
+
'E_activation': E_activation,
|
|
178
|
+
'potential_max': potential_max,
|
|
179
|
+
'1st_splitting': first_splitting,
|
|
180
|
+
'1st_excitation': first_excitation,
|
|
181
|
+
'B': B,
|
|
182
|
+
'degeneracy': deg,
|
|
183
|
+
'gridsize': gridsize,
|
|
184
|
+
'tags': tags,
|
|
185
|
+
})
|
|
186
|
+
# Save to file or just return df
|
|
187
|
+
df = pd.DataFrame(rows)
|
|
188
|
+
if not filepath:
|
|
189
|
+
return df
|
|
190
|
+
df.to_csv(filepath, sep=',', index=False)
|
|
191
|
+
# Include a comment at the top of the file
|
|
192
|
+
file_comment = f'## {comment}\n' if comment else ''
|
|
193
|
+
file_comment += '# Summary of systems\n'
|
|
194
|
+
file_comment += f'# Calculated with QRotor {version}\n'
|
|
195
|
+
file_comment += '# https://pablogila.github.io/qrotor\n#'
|
|
196
|
+
txt.edit.insert_at(filepath, file_comment, 0)
|
|
197
|
+
print(f'Summary saved to {filepath}')
|
|
198
|
+
return df
|
|
199
|
+
|
|
200
|
+
|
|
131
201
|
def get_energies(systems:list) -> list:
|
|
132
202
|
"""Get a list with all lists of eigenvalues from all systems.
|
|
133
203
|
|
|
134
204
|
If no eigenvalues are present for a particular system, appends None.
|
|
135
205
|
"""
|
|
136
|
-
as_list(systems)
|
|
206
|
+
systems = as_list(systems)
|
|
137
207
|
energies = []
|
|
138
208
|
for i in systems:
|
|
139
209
|
if all(i.eigenvalues):
|
|
@@ -148,7 +218,7 @@ def get_gridsizes(systems:list) -> list:
|
|
|
148
218
|
|
|
149
219
|
If no gridsize value is present for a particular system, appends None.
|
|
150
220
|
"""
|
|
151
|
-
as_list(systems)
|
|
221
|
+
systems = as_list(systems)
|
|
152
222
|
gridsizes = []
|
|
153
223
|
for i in systems:
|
|
154
224
|
if i.gridsize:
|
|
@@ -165,7 +235,7 @@ def get_runtimes(systems:list) -> list:
|
|
|
165
235
|
|
|
166
236
|
If no runtime value is present for a particular system, appends None.
|
|
167
237
|
"""
|
|
168
|
-
as_list(systems)
|
|
238
|
+
systems = as_list(systems)
|
|
169
239
|
runtimes = []
|
|
170
240
|
for i in systems:
|
|
171
241
|
if i.runtime:
|
|
@@ -175,16 +245,6 @@ def get_runtimes(systems:list) -> list:
|
|
|
175
245
|
return runtimes
|
|
176
246
|
|
|
177
247
|
|
|
178
|
-
def get_groups(systems:list) -> list:
|
|
179
|
-
"""Returns a list with all `System.group` values."""
|
|
180
|
-
as_list(systems)
|
|
181
|
-
groups = []
|
|
182
|
-
for i in systems:
|
|
183
|
-
if i.group not in groups:
|
|
184
|
-
groups.append(i.group)
|
|
185
|
-
return groups
|
|
186
|
-
|
|
187
|
-
|
|
188
248
|
def get_ideal_E(E_level:int) -> int:
|
|
189
249
|
"""Calculates the ideal energy for a specified `E_level`.
|
|
190
250
|
|
|
@@ -201,7 +261,7 @@ def get_ideal_E(E_level:int) -> int:
|
|
|
201
261
|
|
|
202
262
|
def sort_by_gridsize(systems:list) -> list:
|
|
203
263
|
"""Sorts a list of System objects by `System.gridsize`."""
|
|
204
|
-
as_list(systems)
|
|
264
|
+
systems = as_list(systems)
|
|
205
265
|
systems = sorted(systems, key=lambda sys: sys.gridsize)
|
|
206
266
|
return systems
|
|
207
267
|
|
|
@@ -212,13 +272,16 @@ def reduce_size(systems:list) -> list:
|
|
|
212
272
|
Removes eigenvectors, potential values and grids,
|
|
213
273
|
for all System values inside the `systems` list.
|
|
214
274
|
"""
|
|
215
|
-
as_list(systems)
|
|
275
|
+
systems = as_list(systems)
|
|
216
276
|
for dataset in systems:
|
|
217
277
|
dataset = dataset.reduce_size()
|
|
218
278
|
return systems
|
|
219
279
|
|
|
220
280
|
|
|
221
|
-
def summary(
|
|
281
|
+
def summary(
|
|
282
|
+
systems,
|
|
283
|
+
verbose:bool=False
|
|
284
|
+
) -> None:
|
|
222
285
|
"""Print a summary of a System or list of Systems.
|
|
223
286
|
|
|
224
287
|
Print extra info with `verbose=True`
|
|
@@ -243,3 +306,42 @@ def summary(systems, verbose:bool=False) -> None:
|
|
|
243
306
|
print('--------------------')
|
|
244
307
|
return None
|
|
245
308
|
|
|
309
|
+
|
|
310
|
+
def list_tags(systems:list) -> list:
|
|
311
|
+
"""Returns a list with all system tags."""
|
|
312
|
+
systems = as_list(systems)
|
|
313
|
+
tags = []
|
|
314
|
+
for i in systems:
|
|
315
|
+
# i.tags is guaranteed to exist and be a string (may be empty)
|
|
316
|
+
system_tags = i.tags.split()
|
|
317
|
+
for tag in system_tags:
|
|
318
|
+
if tag not in tags:
|
|
319
|
+
tags.append(tag)
|
|
320
|
+
return tags
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def filter_tags(
|
|
324
|
+
systems:list,
|
|
325
|
+
include:str='',
|
|
326
|
+
exclude:str='',
|
|
327
|
+
) -> list:
|
|
328
|
+
"""Returns a filtered list of systems with or without specific tags.
|
|
329
|
+
|
|
330
|
+
Tags are separated by blank spaces.
|
|
331
|
+
Include tags from `include`, exclude tags from `exclude`.
|
|
332
|
+
"""
|
|
333
|
+
systems = as_list(systems)
|
|
334
|
+
included_tags = include.split()
|
|
335
|
+
excluded_tags = exclude.split()
|
|
336
|
+
filtered_systems = []
|
|
337
|
+
for i in systems:
|
|
338
|
+
tags_found = list_tags(i)
|
|
339
|
+
if excluded_tags and any(tag in excluded_tags for tag in tags_found):
|
|
340
|
+
continue
|
|
341
|
+
if included_tags:
|
|
342
|
+
if any(tag in included_tags for tag in tags_found):
|
|
343
|
+
filtered_systems.append(i)
|
|
344
|
+
else:
|
|
345
|
+
filtered_systems.append(i)
|
|
346
|
+
return filtered_systems
|
|
347
|
+
|
|
@@ -17,9 +17,9 @@ def test_rotate():
|
|
|
17
17
|
'0.118 0.816 0.277',
|
|
18
18
|
]
|
|
19
19
|
# 120 degrees (it should remain the same)
|
|
20
|
-
qr.rotate.
|
|
20
|
+
qr.rotate.input_qe(filepath=structure, positions=CH3, angle=120, precision=2)
|
|
21
21
|
for coord in CH3:
|
|
22
|
-
rotated_coord = api.
|
|
22
|
+
rotated_coord = api.pwx.get_atom(filepath=structure_120, position=coord, precision=2)
|
|
23
23
|
rotated_coord = extract.coords(rotated_coord)
|
|
24
24
|
coord = extract.coords(coord)
|
|
25
25
|
rotated_coord_rounded = []
|
|
@@ -37,9 +37,9 @@ def test_rotate():
|
|
|
37
37
|
'0.095062781582172 0.488975944606740 0.115053787468686',
|
|
38
38
|
'0.128156574395412 0.205890189020629 0.680672454316303',
|
|
39
39
|
]
|
|
40
|
-
qr.rotate.
|
|
40
|
+
qr.rotate.input_qe(filepath=structure, positions=CH3, angle=60, precision=2)
|
|
41
41
|
for coord in ideal:
|
|
42
|
-
rotated_coord = api.
|
|
42
|
+
rotated_coord = api.pwx.get_atom(filepath=structure_60, position=coord, precision=3)
|
|
43
43
|
rotated_coord = extract.coords(rotated_coord)
|
|
44
44
|
coord = extract.coords(coord)
|
|
45
45
|
rotated_coord_rounded = []
|
qrotor-4.2.2/tests/__init__.py
DELETED
|
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
|