qrotor 4.4.0__py3-none-any.whl → 4.5.0__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/__init__.py CHANGED
@@ -7,7 +7,7 @@ from ._version import __version__ as version
7
7
  from .system import System
8
8
  from .constants import *
9
9
  from . import systems
10
- from . import rotate
10
+ from . import rotation
11
11
  from . import potential
12
12
  from . import solve
13
13
  from . import plot
qrotor/_version.py CHANGED
@@ -11,5 +11,5 @@ https://semver.org/
11
11
  ---
12
12
  """
13
13
 
14
- __version__ = "v4.4.0"
14
+ __version__ = "v4.5.0"
15
15
 
qrotor/potential.py CHANGED
@@ -200,7 +200,7 @@ def from_qe(
200
200
  comment:str=None,
201
201
  ) -> System:
202
202
  """Compiles a rotational potential CSV file from Quantum ESPRESSO pw.x outputs,
203
- created with `qrotor.rotate.input_qe()`.
203
+ created with `qrotor.rotation.rotate_qe()`.
204
204
  Returns a `System` object with the new potential values.
205
205
 
206
206
  The angle in degrees is extracted from the output filenames,
@@ -9,7 +9,7 @@ Works with Quantum ESPRESSO input files.
9
9
 
10
10
  | | |
11
11
  | --- | --- |
12
- | `input_qe()` | Rotate specific atoms from a Quantum ESPRESSO input file |
12
+ | `rotate_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 input_qe(
29
+ def rotate_qe(
30
30
  filepath:str,
31
31
  positions:list,
32
32
  angle:float,
@@ -35,7 +35,7 @@ def input_qe(
35
35
  use_centroid:bool=True,
36
36
  show_axis:bool=False,
37
37
  ) -> list:
38
- """Rotates atoms from a Quantum ESPRESSO input file.
38
+ """Rotates atoms from a Quantum ESPRESSO pw.x input file.
39
39
 
40
40
  Takes a `filepath` with a molecular structure, and three or more atomic `positions` (list).
41
41
  These input positions can be approximate, and are used to identify the target atoms.
qrotor/systems.py CHANGED
@@ -324,11 +324,13 @@ def filter_tags(
324
324
  systems:list,
325
325
  include:str='',
326
326
  exclude:str='',
327
+ strict:bool=False,
327
328
  ) -> list:
328
329
  """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`.
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*.
332
334
  """
333
335
  systems = as_list(systems)
334
336
  included_tags = include.split()
@@ -336,12 +338,16 @@ def filter_tags(
336
338
  filtered_systems = []
337
339
  for i in systems:
338
340
  tags_found = list_tags(i)
339
- if excluded_tags and any(tag in excluded_tags for tag in tags_found):
340
- continue
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
341
346
  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)
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)
346
352
  return filtered_systems
347
353
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrotor
3
- Version: 4.4.0
3
+ Version: 4.5.0
4
4
  Summary: QRotor
5
5
  Author: Pablo Gila-Herranz
6
6
  Author-email: pgila001@ikasle.ehu.eus
@@ -106,7 +106,7 @@ QRotor contains the following modules:
106
106
  | [qrotor.constants](https://pablogila.github.io/qrotor/qrotor/constants.html) | Common bond lengths and inertias |
107
107
  | [qrotor.system](https://pablogila.github.io/qrotor/qrotor/system.html) | Definition of the quantum `System` object |
108
108
  | [qrotor.systems](https://pablogila.github.io/qrotor/qrotor/systems.html) | Utilities to manage several System objects, such as a list of systems |
109
- | [qrotor.rotate](https://pablogila.github.io/qrotor/qrotor/rotate.html) | Rotate specific atoms from structural files |
109
+ | [qrotor.rotation](https://pablogila.github.io/qrotor/qrotor/rotation.html) | Rotate specific atoms from structural files |
110
110
  | [qrotor.potential](https://pablogila.github.io/qrotor/qrotor/potential.html) | Potential definitions and loading functions |
111
111
  | [qrotor.solve](https://pablogila.github.io/qrotor/qrotor/solve.html) | Solve rotation eigenvalues and eigenvectors |
112
112
  | [qrotor.plot](https://pablogila.github.io/qrotor/qrotor/plot.html) | Plotting utilities |
@@ -179,7 +179,7 @@ atoms = [
179
179
  '3.103 3.206 3.309'
180
180
  ]
181
181
  # Create the input SCF files, saving the filenames to a list
182
- scf_files = qr.rotate.structure_qe('molecule.in', positions=atoms, angle=10, repeat=True)
182
+ scf_files = qr.rotation.rotate_qe('molecule.in', positions=atoms, angle=10, repeat=True)
183
183
  # Run the Quantum ESPRESSO calculations
184
184
  api.slurm.sbatch(files=scf_files)
185
185
  ```
@@ -0,0 +1,21 @@
1
+ qrotor/__init__.py,sha256=FgB2-SglHK-hAzjctoVqzJSBA1rLBQH2nv0o3LWuh5A,248
2
+ qrotor/_version.py,sha256=TtdvqIyM9prSdLh_gm1u2NzWAHa0f2sK482XiKtEmyo,198
3
+ qrotor/constants.py,sha256=YRri136Zg5dqqDS-180sxOB5ytBJW74msUbHYbrfiMc,6655
4
+ qrotor/plot.py,sha256=iJWHohW8hvKGRUjoqLYyQXweqrahF0XOIyyhDJ05_bI,14171
5
+ qrotor/potential.py,sha256=n6izUMbl2okMSg7xj_IV6rDr2B-RCWiqtSBcsTltL1M,18564
6
+ qrotor/rotation.py,sha256=4pXcIcb6fY44haRB6HWGLqC0la1V91Tr3NW4DrUNTkw,8115
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.5.0.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_rotation.py,sha256=qW6HQHdPNteN6qZ5blVoTSQINU8m9wn8hTcOszrdulE,1898
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.5.0.dist-info/METADATA,sha256=z96837SiDPa-FoSfs3rGVYQMvT3f_Hp3h_oqpFmzgRA,9648
19
+ qrotor-4.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
+ qrotor-4.5.0.dist-info/top_level.txt,sha256=mLnYs07-amqX4TqbDV2_XvgdpHfgrYmzmYb7dwoh6EQ,13
21
+ qrotor-4.5.0.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_rotation.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_rotation():
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.rotation.rotate_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.rotation.rotate_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=ROJNaCCcVwCHHX73Jf2tvmDGOerQZHlj_2VO-tE-DCw,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=h2e5cP0GKaXbnbbna5dyCbRYHWloSrQXVs_wrV69Mto,12006
10
- qrotor-4.4.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
11
- qrotor-4.4.0.dist-info/METADATA,sha256=ZJwODdQbVnxqiLEPZ3Iid_guIiWcw500ou-67Sn7oh8,9649
12
- qrotor-4.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- qrotor-4.4.0.dist-info/top_level.txt,sha256=SFRMgcJiR1GiEtZ4aLo-x5TdfSCo7Igxezp2qyI0u5A,7
14
- qrotor-4.4.0.dist-info/RECORD,,
File without changes