qrotor 4.3.0__py3-none-any.whl → 4.4.1__py3-none-any.whl

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

Potentially problematic release.


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

qrotor/_version.py CHANGED
@@ -11,5 +11,5 @@ https://semver.org/
11
11
  ---
12
12
  """
13
13
 
14
- __version__ = "v4.3.0"
14
+ __version__ = "v4.4.1"
15
15
 
qrotor/plot.py CHANGED
@@ -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.group not in unique_groups:
141
- unique_groups.append(system.group)
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.group} Energies') # Add to legend
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)
qrotor/potential.py CHANGED
@@ -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
 
qrotor/system.py CHANGED
@@ -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
- potential_values = [],
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.group: str = group
53
- """Chemical group, methyl or amine: `'CH3'`, `'CD3'`, `'NH3'`, `'ND3'`.
50
+ self.tags: str = tags
51
+ """Custom tags separated by spaces, such as the molecular group, etc.
54
52
 
55
- Can be used to set the value of `B` automatically at startup.
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 = 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 = 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
- 'group': self.group,
218
+ 'tags': self.tags,
260
219
  'B': self.B,
261
220
  'gridsize': self.gridsize,
262
221
  'potential_name': self.potential_name,
qrotor/systems.py CHANGED
@@ -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='eigenvalues.csv',
56
+ filepath:str='qrotor_eigenvalues.csv',
55
57
  ) -> pd.DataFrame:
56
- """Save the energy eigenvalues for all `systems` to a eigenvalues.csv file.
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'# {comment}\n' if comment else 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='splittings.csv',
98
+ filepath:str='qrotor_splittings.csv',
97
99
  ) -> pd.DataFrame:
98
- """Save the tunnel splitting energies for all `systems` to a splittings.csv file.
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'# {comment}\n' if comment else 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(systems, verbose:bool=False) -> None:
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,48 @@ 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
+ strict:bool=False,
328
+ ) -> list:
329
+ """Returns a filtered list of systems with or without specific tags.
330
+
331
+ You can `include` or `exclude` any number of tags, separated by blank spaces.
332
+ By default, the filters are triggered if any tag is found, i.e. *tag1 OR tag2*.
333
+ Set `strict=True` to require all tags to match, i.e. *tag1 AND tag2*.
334
+ """
335
+ systems = as_list(systems)
336
+ included_tags = include.split()
337
+ excluded_tags = exclude.split()
338
+ filtered_systems = []
339
+ for i in systems:
340
+ tags_found = list_tags(i)
341
+ if excluded_tags:
342
+ if strict and all(tag in tags_found for tag in excluded_tags):
343
+ continue
344
+ elif not strict and any(tag in tags_found for tag in excluded_tags):
345
+ continue
346
+ if included_tags:
347
+ if strict and not all(tag in tags_found for tag in included_tags):
348
+ continue
349
+ elif not strict and not any(tag in tags_found for tag in included_tags):
350
+ continue
351
+ filtered_systems.append(i)
352
+ return filtered_systems
353
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrotor
3
- Version: 4.3.0
3
+ Version: 4.4.1
4
4
  Summary: QRotor
5
5
  Author: Pablo Gila-Herranz
6
6
  Author-email: pgila001@ikasle.ehu.eus
@@ -0,0 +1,21 @@
1
+ qrotor/__init__.py,sha256=rG2dH4QjsVUOMBhFnv5gXs3QnrUg7fywd5pIDmMBXcQ,246
2
+ qrotor/_version.py,sha256=-0UGWvfKUxLJlpnjNakdqSmawlKdSDhL09z5yQDtirE,198
3
+ qrotor/constants.py,sha256=YRri136Zg5dqqDS-180sxOB5ytBJW74msUbHYbrfiMc,6655
4
+ qrotor/plot.py,sha256=iJWHohW8hvKGRUjoqLYyQXweqrahF0XOIyyhDJ05_bI,14171
5
+ qrotor/potential.py,sha256=MsmUoac3wRhlIprY8ipThy0HNYaO8iRnfF51VsUJ5HU,18561
6
+ qrotor/rotate.py,sha256=FppTiAwE3c7JtPyOGBF4YHxq9JzE-YilN_lpaOgPm9Q,8109
7
+ qrotor/solve.py,sha256=YkOR1SJlpk41PCNEhslv6X3wV1TWMNztT78qX3Pngf0,10722
8
+ qrotor/system.py,sha256=NQ7fcSo2R1QY1D0k9ymjJT9i9BSvuAOE7zqt5NJxFCQ,9946
9
+ qrotor/systems.py,sha256=KbeaomvMcmQluJW2VMzQounu4qB42_jX2CU0ablDNCI,12389
10
+ qrotor-4.4.1.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
11
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ tests/test_constants.py,sha256=YHKkPyZlzjchxxzON_VSNsQdKnpkknsFVoIA6TcUk70,399
13
+ tests/test_potential.py,sha256=_Vq9t9Xm59kNbyYwXlRnvKcxwL7vntD2j14W2aUtF6I,1302
14
+ tests/test_rotate.py,sha256=pbwLeET6mCw7x8nFFvwn5ZvONRzNsexjSB_SZq7cJ1s,1890
15
+ tests/test_solve.py,sha256=tEjLUZC7oe6LCQD5b2xf2aaK9lu-zI4lzuPXOGR2GAs,861
16
+ tests/test_system.py,sha256=36d-8AdoJdzq0O9_O3s8wwBPGa-M7A86YiHqhhAsCZ8,742
17
+ tests/test_systems.py,sha256=wKaBDaF2QIvJAux5tsuFecp8oGx4LGNhWVJaCxNlb4g,1440
18
+ qrotor-4.4.1.dist-info/METADATA,sha256=Nncza56dmFQXPwO-BjhSuj3uwE0wabhaxcdkt4SQp0I,9649
19
+ qrotor-4.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
+ qrotor-4.4.1.dist-info/top_level.txt,sha256=mLnYs07-amqX4TqbDV2_XvgdpHfgrYmzmYb7dwoh6EQ,13
21
+ qrotor-4.4.1.dist-info/RECORD,,
tests/__init__.py ADDED
File without changes
@@ -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
+
tests/test_rotate.py ADDED
@@ -0,0 +1,53 @@
1
+ import qrotor as qr
2
+ import aton.api as api
3
+ import aton.txt.extract as extract
4
+ import aton.file as file
5
+
6
+
7
+ folder = 'tests/samples/'
8
+ structure = folder + 'CH3NH3.in'
9
+ structure_120 = folder + 'CH3NH3_120.in'
10
+ structure_60 = folder + 'CH3NH3_60.in'
11
+
12
+
13
+ def test_rotate():
14
+ CH3 = [
15
+ '0.100 0.183 0.316',
16
+ '0.151 0.532 0.842',
17
+ '0.118 0.816 0.277',
18
+ ]
19
+ # 120 degrees (it should remain the same)
20
+ qr.rotate.input_qe(filepath=structure, positions=CH3, angle=120, precision=2)
21
+ for coord in CH3:
22
+ rotated_coord = api.pwx.get_atom(filepath=structure_120, position=coord, precision=2)
23
+ rotated_coord = extract.coords(rotated_coord)
24
+ coord = extract.coords(coord)
25
+ rotated_coord_rounded = []
26
+ coord_rounded = []
27
+ for i in rotated_coord:
28
+ rotated_coord_rounded.append(round(i, 2))
29
+ for i in coord:
30
+ coord_rounded.append(round(i, 2))
31
+ assert coord_rounded == rotated_coord_rounded
32
+ file.remove(structure_120)
33
+
34
+ # 60 degrees (it should change quite a lot)
35
+ ideal = [
36
+ '0.146468644022416 0.837865866372631 0.641449758215011',
37
+ '0.095062781582172 0.488975944606740 0.115053787468686',
38
+ '0.128156574395412 0.205890189020629 0.680672454316303',
39
+ ]
40
+ qr.rotate.input_qe(filepath=structure, positions=CH3, angle=60, precision=2)
41
+ for coord in ideal:
42
+ rotated_coord = api.pwx.get_atom(filepath=structure_60, position=coord, precision=3)
43
+ rotated_coord = extract.coords(rotated_coord)
44
+ coord = extract.coords(coord)
45
+ rotated_coord_rounded = []
46
+ coord_rounded = []
47
+ for i in rotated_coord:
48
+ rotated_coord_rounded.append(round(i, 2))
49
+ for i in coord:
50
+ coord_rounded.append(round(i, 2))
51
+ assert coord_rounded == rotated_coord_rounded
52
+ file.remove(structure_60)
53
+
tests/test_solve.py ADDED
@@ -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
+
tests/test_system.py ADDED
@@ -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
+
tests/test_systems.py ADDED
@@ -0,0 +1,30 @@
1
+ import qrotor as qr
2
+
3
+
4
+ def test_tags():
5
+ sys1 = qr.System(tags='tag1 tag2 tag3', comment='sys1', potential_name='zero')
6
+ sys2 = qr.System(tags='tag2 tag3 tag4', comment='sys2')
7
+ sys3 = qr.System(tags='tag4 tag5 tag6', comment='sys3')
8
+ sys1.solve(100)
9
+ test1 = qr.systems.filter_tags(sys1, include='tag4')
10
+ assert test1 == []
11
+ test2 = qr.systems.filter_tags([sys1, sys2], include='tag4 tag5', strict=False)
12
+ assert len(test2) == 1
13
+ assert test2[0].comment == 'sys2'
14
+ test3 = qr.systems.filter_tags([sys1, sys2], include='tag4 tag5', strict=True)
15
+ assert test3 == []
16
+ test4 = qr.systems.filter_tags([sys1, sys2, sys3], include='tag3 tag4', strict=False)
17
+ assert len(test4) == 3
18
+ test5 = qr.systems.filter_tags([sys1, sys2, sys3], include='tag3 tag4', strict=True)
19
+ assert len(test5) == 1
20
+ assert test5[0].comment == 'sys2'
21
+ test6 = qr.systems.filter_tags([sys1, sys2, sys3], include='tag3 tag4', exclude='tag6', strict=False)
22
+ assert len(test6) == 2
23
+ test7 = qr.systems.filter_tags([sys1, sys2, sys3], include='tag4', exclude='tag5 tag6', strict=True)
24
+ assert len(test7) == 1
25
+ assert test7[0].comment == 'sys2'
26
+ test8 = qr.systems.filter_tags([sys1, sys2, sys3], include='', exclude='tag1 tag2', strict=True)
27
+ assert len(test8) == 2
28
+ test9 = qr.systems.filter_tags([sys1, sys2, sys3], include='', exclude='tag1 tag2', strict=False)
29
+ assert test9[0].comment == 'sys3'
30
+
@@ -1,14 +0,0 @@
1
- qrotor/__init__.py,sha256=rG2dH4QjsVUOMBhFnv5gXs3QnrUg7fywd5pIDmMBXcQ,246
2
- qrotor/_version.py,sha256=yUq4NMbgza_UQXUxL5adzghdHM9U2mboRIIQkw4VrwE,198
3
- qrotor/constants.py,sha256=YRri136Zg5dqqDS-180sxOB5ytBJW74msUbHYbrfiMc,6655
4
- qrotor/plot.py,sha256=loyd-1sXvfD8_PyHCThE3VQpRC0qs1iONGY4LXjJyZ4,14086
5
- qrotor/potential.py,sha256=hKlDKA50Umwk0Tfzx4mUXHSWTcHQNqhHLA7T2XedtCY,18500
6
- qrotor/rotate.py,sha256=FppTiAwE3c7JtPyOGBF4YHxq9JzE-YilN_lpaOgPm9Q,8109
7
- qrotor/solve.py,sha256=YkOR1SJlpk41PCNEhslv6X3wV1TWMNztT78qX3Pngf0,10722
8
- qrotor/system.py,sha256=ahYurNUmVOV7B6aZSe7rhcruagj5rW9UClqG-H1vVvY,11454
9
- qrotor/systems.py,sha256=Hcx0QvMWpaPMfC6HWpkZPPWDyHk9rxWKdAxWNnD2NMg,8184
10
- qrotor-4.3.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
11
- qrotor-4.3.0.dist-info/METADATA,sha256=MJWzR5gyk2x4-VIWl2K7ReaJYb0uKMnRrh-iUvywBsE,9649
12
- qrotor-4.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- qrotor-4.3.0.dist-info/top_level.txt,sha256=SFRMgcJiR1GiEtZ4aLo-x5TdfSCo7Igxezp2qyI0u5A,7
14
- qrotor-4.3.0.dist-info/RECORD,,
File without changes