dynasor 2.2__tar.gz → 2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. {dynasor-2.2 → dynasor-2.4}/PKG-INFO +28 -8
  2. {dynasor-2.2 → dynasor-2.4}/README.rst +14 -7
  3. {dynasor-2.2 → dynasor-2.4}/dynasor/__init__.py +5 -1
  4. {dynasor-2.2 → dynasor-2.4}/dynasor/cli/main.py +17 -6
  5. {dynasor-2.2 → dynasor-2.4}/dynasor/core/reciprocal.py +1 -1
  6. {dynasor-2.2 → dynasor-2.4}/dynasor/core/rho_j_q_numba.py +18 -19
  7. dynasor-2.4/dynasor/core/time_averager.py +103 -0
  8. {dynasor-2.2 → dynasor-2.4}/dynasor/correlation_functions.py +129 -74
  9. {dynasor-2.2 → dynasor-2.4}/dynasor/logging_tools.py +11 -17
  10. dynasor-2.4/dynasor/modes/__init__.py +16 -0
  11. dynasor-2.4/dynasor/modes/atoms.py +178 -0
  12. dynasor-2.4/dynasor/modes/band.py +107 -0
  13. dynasor-2.4/dynasor/modes/complex_coordinate.py +130 -0
  14. dynasor-2.4/dynasor/modes/mode_projector.py +525 -0
  15. dynasor-2.4/dynasor/modes/project_modes.py +90 -0
  16. dynasor-2.4/dynasor/modes/qpoint.py +112 -0
  17. dynasor-2.4/dynasor/modes/tools.py +231 -0
  18. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/__init__.py +0 -2
  19. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/atomic_weighting.py +37 -17
  20. dynasor-2.4/dynasor/post_processing/average_runs.py +90 -0
  21. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/electron_scattering_factors.py +33 -24
  22. dynasor-2.4/dynasor/post_processing/form-factors/neutron_scattering_lengths.json +1 -0
  23. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/neutron_scattering_lengths.py +21 -6
  24. dynasor-2.4/dynasor/post_processing/spherical_average.py +309 -0
  25. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/weights.py +30 -11
  26. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/x_ray_form_factors.py +16 -9
  27. {dynasor-2.2 → dynasor-2.4}/dynasor/qpoints/lattice.py +28 -26
  28. {dynasor-2.2 → dynasor-2.4}/dynasor/qpoints/spherical_qpoints.py +56 -33
  29. dynasor-2.4/dynasor/qpoints/tools.py +165 -0
  30. dynasor-2.4/dynasor/sample.py +425 -0
  31. dynasor-2.4/dynasor/tools/acfs.py +277 -0
  32. {dynasor-2.2 → dynasor-2.4}/dynasor/tools/damped_harmonic_oscillator.py +38 -15
  33. dynasor-2.4/dynasor/tools/structures.py +308 -0
  34. dynasor-2.4/dynasor/trajectory/abstract_trajectory_reader.py +59 -0
  35. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/ase_trajectory_reader.py +5 -12
  36. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/atomic_indices.py +5 -3
  37. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/extxyz_trajectory_reader.py +52 -40
  38. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/lammps_trajectory_reader.py +5 -12
  39. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/mdanalysis_trajectory_reader.py +15 -16
  40. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/trajectory.py +47 -35
  41. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/trajectory_frame.py +32 -32
  42. dynasor-2.4/dynasor/units.py +42 -0
  43. {dynasor-2.2 → dynasor-2.4}/dynasor.egg-info/PKG-INFO +28 -8
  44. {dynasor-2.2 → dynasor-2.4}/dynasor.egg-info/SOURCES.txt +11 -1
  45. dynasor-2.4/dynasor.egg-info/requires.txt +20 -0
  46. {dynasor-2.2 → dynasor-2.4}/pyproject.toml +25 -2
  47. dynasor-2.4/tests/test_SED.py +185 -0
  48. dynasor-2.4/tests/test_average_independent_samples.py +144 -0
  49. {dynasor-2.2 → dynasor-2.4}/tests/test_cli.py +33 -1
  50. dynasor-2.4/tests/test_compute_Sqw_with_too_long_window.py +26 -0
  51. {dynasor-2.2 → dynasor-2.4}/tests/test_dho.py +13 -0
  52. dynasor-2.4/tests/test_dynasor_API.py +317 -0
  53. {dynasor-2.2 → dynasor-2.4}/tests/test_integration.py +21 -19
  54. {dynasor-2.2 → dynasor-2.4}/tests/test_logging.py +2 -2
  55. {dynasor-2.2 → dynasor-2.4}/tests/test_normalization.py +11 -2
  56. dynasor-2.4/tests/test_numba.py +256 -0
  57. {dynasor-2.2 → dynasor-2.4}/tests/test_qpoints.py +90 -0
  58. dynasor-2.4/tests/test_sample_class.py +303 -0
  59. dynasor-2.4/tests/test_scattering_factors.py +295 -0
  60. dynasor-2.4/tests/test_spherical_average.py +263 -0
  61. dynasor-2.4/tests/test_structures.py +112 -0
  62. dynasor-2.4/tests/test_time_averager.py +190 -0
  63. dynasor-2.4/tests/test_tools.py +222 -0
  64. {dynasor-2.2 → dynasor-2.4}/tests/test_trajectory_and_window_iterator.py +35 -2
  65. dynasor-2.4/tests/test_utils.py +0 -0
  66. {dynasor-2.2 → dynasor-2.4}/tests/test_weighting.py +113 -44
  67. {dynasor-2.2 → dynasor-2.4}/tests/test_weights.py +21 -1
  68. dynasor-2.2/dynasor/core/time_averager.py +0 -44
  69. dynasor-2.2/dynasor/post_processing/average_runs.py +0 -61
  70. dynasor-2.2/dynasor/post_processing/filon.py +0 -148
  71. dynasor-2.2/dynasor/post_processing/form-factors/neutron_scattering_lengths.json +0 -1
  72. dynasor-2.2/dynasor/post_processing/spherical_average.py +0 -225
  73. dynasor-2.2/dynasor/qpoints/tools.py +0 -247
  74. dynasor-2.2/dynasor/sample.py +0 -204
  75. dynasor-2.2/dynasor/tools/acfs.py +0 -117
  76. dynasor-2.2/dynasor/tools/structures.py +0 -102
  77. dynasor-2.2/dynasor/trajectory/abstract_trajectory_reader.py +0 -38
  78. dynasor-2.2/dynasor/units.py +0 -42
  79. dynasor-2.2/dynasor.egg-info/requires.txt +0 -5
  80. dynasor-2.2/tests/test_SED.py +0 -98
  81. dynasor-2.2/tests/test_average_independent_samples.py +0 -86
  82. dynasor-2.2/tests/test_dynasor_API.py +0 -154
  83. dynasor-2.2/tests/test_numba.py +0 -40
  84. dynasor-2.2/tests/test_sample_class.py +0 -196
  85. dynasor-2.2/tests/test_spherical_average.py +0 -139
  86. dynasor-2.2/tests/test_time_averager.py +0 -33
  87. dynasor-2.2/tests/test_tools.py +0 -91
  88. dynasor-2.2/tests/test_utils.py +0 -23
  89. {dynasor-2.2 → dynasor-2.4}/LICENSE +0 -0
  90. {dynasor-2.2 → dynasor-2.4}/dynasor/cli/__init__.py +0 -0
  91. {dynasor-2.2 → dynasor-2.4}/dynasor/core/__init__.py +0 -0
  92. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/form-factors/compton-parameters-waasmaier-kirfel-1995.json +0 -0
  93. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/form-factors/electron-parameters-ions-peng-1998.json +0 -0
  94. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/form-factors/electron-parameters-kmax2-peng-1996.json +0 -0
  95. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/form-factors/electron-parameters-kmax6-peng-1996.json +0 -0
  96. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/form-factors/x-ray-parameters-itcc-2006.json +0 -0
  97. {dynasor-2.2 → dynasor-2.4}/dynasor/post_processing/form-factors/x-ray-parameters-waasmaier-kirfel-1995.json +0 -0
  98. {dynasor-2.2 → dynasor-2.4}/dynasor/qpoints/__init__.py +0 -0
  99. {dynasor-2.2 → dynasor-2.4}/dynasor/tools/__init__.py +0 -0
  100. {dynasor-2.2 → dynasor-2.4}/dynasor/trajectory/__init__.py +0 -0
  101. {dynasor-2.2 → dynasor-2.4}/dynasor.egg-info/dependency_links.txt +0 -0
  102. {dynasor-2.2 → dynasor-2.4}/dynasor.egg-info/entry_points.txt +0 -0
  103. {dynasor-2.2 → dynasor-2.4}/dynasor.egg-info/top_level.txt +0 -0
  104. {dynasor-2.2 → dynasor-2.4}/setup.cfg +0 -0
  105. {dynasor-2.2 → dynasor-2.4}/tests/test_lattice.py +0 -0
  106. {dynasor-2.2 → dynasor-2.4}/tests/test_parse_gromacs_index_file.py +0 -0
  107. {dynasor-2.2 → dynasor-2.4}/tests/test_regression_vs_old_cmdline_results.py +0 -0
  108. {dynasor-2.2 → dynasor-2.4}/tests/test_trajectory_frame.py +0 -0
  109. {dynasor-2.2 → dynasor-2.4}/tests/test_units.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dynasor
3
- Version: 2.2
3
+ Version: 2.4
4
4
  Summary: Dynamical structure factors and correlation functions from molecular dynamics trajectories
5
5
  Author: The dynasor developer team
6
6
  Maintainer: The dynasor developer team
@@ -30,6 +30,19 @@ Requires-Dist: mdanalysis
30
30
  Requires-Dist: numba>=0.55
31
31
  Requires-Dist: numpy>=1.18
32
32
  Requires-Dist: pandas>=2.2
33
+ Requires-Dist: scipy
34
+ Provides-Extra: test
35
+ Requires-Dist: coverage; extra == "test"
36
+ Requires-Dist: flake8; extra == "test"
37
+ Requires-Dist: phonopy; extra == "test"
38
+ Requires-Dist: pytest; extra == "test"
39
+ Requires-Dist: xdoctest; extra == "test"
40
+ Provides-Extra: documentation
41
+ Requires-Dist: pydata-sphinx-theme; extra == "documentation"
42
+ Requires-Dist: nbsphinx; extra == "documentation"
43
+ Requires-Dist: sphinx-autodoc-typehints; extra == "documentation"
44
+ Requires-Dist: sphinx-design; extra == "documentation"
45
+ Requires-Dist: sphinx-sitemap; extra == "documentation"
33
46
  Dynamic: license-file
34
47
 
35
48
  dynasor
@@ -38,27 +51,34 @@ dynasor
38
51
  **dynasor** is a tool for calculating total and partial dynamic structure factors as well as related correlation functions from molecular dynamics (MD) simulations.
39
52
  By analyzing these functions one can access the dynamics of a system without resorting to perturbative approaches.
40
53
  Moreover by combining in particular the structure factor with the cross sections (or form factors) of, e.g., neutrons, X-rays or electrons, one can predict experimental spectra.
41
- The main input consists of a trajectory from a MD simulation, i.e., a file containing snapshots of the particle coordinates and optionally velocities, that correspond to consecutively and equally spaced points in (simulation) time.
54
+ The main input consists of a trajectory from an MD simulation, i.e., a file containing snapshots of the particle coordinates and optionally velocities that correspond to consecutive, equally spaced points in simulation time.
42
55
 
43
- **dynasor** provides both python and a command line interface.
56
+ **dynasor** provides both a Python interface and a command-line interface.
44
57
  The following snippet illustrates how one can calculate dynamic structure factors using the former.
45
58
 
46
59
  .. code-block:: python
47
60
 
61
+ from dynasor import Trajectory, compute_dynamic_structure_factors
62
+ from dynasor.qpoints import get_spherical_qpoints
63
+
48
64
  traj = Trajectory('dump.xyz', trajectory_format='extxyz')
49
- q_points = generate_spherical_qpoints(traj.cell, q_max=20)
65
+ q_points = get_spherical_qpoints(traj.cell, q_max=20)
50
66
  sample = compute_dynamic_structure_factors(traj, q_points=q_points, dt=5, window_size=100)
51
- sample.write_to_npy('test.npy')
67
+ sample.write_to_npz('test.npz')
52
68
 
53
69
  **dynasor** can be installed via `pip <https://pypi.org/project/dynasor/>`_ or `conda <https://anaconda.org/conda-forge/dynasor>`_.
54
- Please consult the `installation section of the user guide <https://dynasor.materialsmodeling.org/installation.html>`_ for details.
70
+ Please consult the `installation section of the user guide <https://dynasor.materialsmodeling.org/get_started/installation.html>`_ for details.
55
71
 
56
- The full documentation can be found in the `user guide <http://dynasor.materialsmodeling.org/>`_.
72
+ The full documentation can be found in the `user guide <https://dynasor.materialsmodeling.org/>`_.
57
73
  For questions and help please use the `dynasor discussion forum on matsci.org <https://matsci.org/dynasor>`_.
58
74
  **dynasor** and its development are hosted on `gitlab <https://gitlab.com/materials-modeling/dynasor>`_.
59
75
 
60
- When using **dynasor** in your research please cite the following paper:
76
+ When using **dynasor** in your research please cite the following papers:
61
77
 
62
78
  | *Dynasor – A tool for extracting dynamical structure factors and current correlation functions from molecular dynamics simulations*
63
79
  | Erik Fransson, Mattias Slabanja, Paul Erhart, and Göran Wahnström
64
80
  | Advanced Theory and Simulations **4**, 2000240 (2021); DOI:`10.1002/adts.202000240 <https://doi.org/10.1002/adts.202000240>`_
81
+
82
+ | *Dynasor 2: From simulation to experiment through correlation functions*
83
+ | Esmée Berger, Erik Fransson, Fredrik Eriksson, Eric Lindgren, Göran Wahnström, Thomas Holm Rod, and Paul Erhart
84
+ | Computer Physics Communications **316**, 109759 (2025); DOI: `10.1016/j.cpc.2025.109759 <https://doi.org/10.1016/j.cpc.2025.109759>`_
@@ -4,27 +4,34 @@ dynasor
4
4
  **dynasor** is a tool for calculating total and partial dynamic structure factors as well as related correlation functions from molecular dynamics (MD) simulations.
5
5
  By analyzing these functions one can access the dynamics of a system without resorting to perturbative approaches.
6
6
  Moreover by combining in particular the structure factor with the cross sections (or form factors) of, e.g., neutrons, X-rays or electrons, one can predict experimental spectra.
7
- The main input consists of a trajectory from a MD simulation, i.e., a file containing snapshots of the particle coordinates and optionally velocities, that correspond to consecutively and equally spaced points in (simulation) time.
7
+ The main input consists of a trajectory from an MD simulation, i.e., a file containing snapshots of the particle coordinates and optionally velocities that correspond to consecutive, equally spaced points in simulation time.
8
8
 
9
- **dynasor** provides both python and a command line interface.
9
+ **dynasor** provides both a Python interface and a command-line interface.
10
10
  The following snippet illustrates how one can calculate dynamic structure factors using the former.
11
11
 
12
12
  .. code-block:: python
13
13
 
14
+ from dynasor import Trajectory, compute_dynamic_structure_factors
15
+ from dynasor.qpoints import get_spherical_qpoints
16
+
14
17
  traj = Trajectory('dump.xyz', trajectory_format='extxyz')
15
- q_points = generate_spherical_qpoints(traj.cell, q_max=20)
18
+ q_points = get_spherical_qpoints(traj.cell, q_max=20)
16
19
  sample = compute_dynamic_structure_factors(traj, q_points=q_points, dt=5, window_size=100)
17
- sample.write_to_npy('test.npy')
20
+ sample.write_to_npz('test.npz')
18
21
 
19
22
  **dynasor** can be installed via `pip <https://pypi.org/project/dynasor/>`_ or `conda <https://anaconda.org/conda-forge/dynasor>`_.
20
- Please consult the `installation section of the user guide <https://dynasor.materialsmodeling.org/installation.html>`_ for details.
23
+ Please consult the `installation section of the user guide <https://dynasor.materialsmodeling.org/get_started/installation.html>`_ for details.
21
24
 
22
- The full documentation can be found in the `user guide <http://dynasor.materialsmodeling.org/>`_.
25
+ The full documentation can be found in the `user guide <https://dynasor.materialsmodeling.org/>`_.
23
26
  For questions and help please use the `dynasor discussion forum on matsci.org <https://matsci.org/dynasor>`_.
24
27
  **dynasor** and its development are hosted on `gitlab <https://gitlab.com/materials-modeling/dynasor>`_.
25
28
 
26
- When using **dynasor** in your research please cite the following paper:
29
+ When using **dynasor** in your research please cite the following papers:
27
30
 
28
31
  | *Dynasor – A tool for extracting dynamical structure factors and current correlation functions from molecular dynamics simulations*
29
32
  | Erik Fransson, Mattias Slabanja, Paul Erhart, and Göran Wahnström
30
33
  | Advanced Theory and Simulations **4**, 2000240 (2021); DOI:`10.1002/adts.202000240 <https://doi.org/10.1002/adts.202000240>`_
34
+
35
+ | *Dynasor 2: From simulation to experiment through correlation functions*
36
+ | Esmée Berger, Erik Fransson, Fredrik Eriksson, Eric Lindgren, Göran Wahnström, Thomas Holm Rod, and Paul Erhart
37
+ | Computer Physics Communications **316**, 109759 (2025); DOI: `10.1016/j.cpc.2025.109759 <https://doi.org/10.1016/j.cpc.2025.109759>`_
@@ -15,8 +15,10 @@ from .qpoints import (
15
15
  )
16
16
  from .sample import read_sample_from_npz
17
17
  from .trajectory import Trajectory
18
+ from .modes.mode_projector import ModeProjector
19
+ from .modes.project_modes import project_modes
18
20
 
19
- __version__ = '2.2'
21
+ __version__ = '2.4'
20
22
  __all__ = [
21
23
  'compute_dynamic_structure_factors',
22
24
  'compute_spectral_energy_density',
@@ -25,4 +27,6 @@ __all__ = [
25
27
  'get_supercell_qpoints_along_path',
26
28
  'read_sample_from_npz',
27
29
  'Trajectory',
30
+ 'ModeProjector',
31
+ 'project_modes',
28
32
  ]
@@ -11,24 +11,35 @@ from dynasor.correlation_functions import compute_dynamic_structure_factors
11
11
  from dynasor.post_processing import get_spherically_averaged_sample_binned
12
12
 
13
13
 
14
+ def _parse_q_direction(value):
15
+ message = 'q-direction must contain three comma-separated numbers'
16
+ try:
17
+ direction = np.asarray(value.split(','), dtype=float)
18
+ except ValueError as error:
19
+ raise argparse.ArgumentTypeError(message) from error
20
+ if direction.size != 3:
21
+ raise argparse.ArgumentTypeError(message)
22
+ return direction
23
+
24
+
14
25
  def main():
15
26
 
16
27
  parser = argparse.ArgumentParser(
17
28
  description='dynasor is a simple tool for calculating total and partial dynamic structure'
18
29
  ' factors as well as current correlation functions from molecular dynamics simulations.'
19
- ' The main input consists of a trajectory output from a MD simulation, i.e., a file'
30
+ ' The main input consists of trajectory output from an MD simulation, i.e., a file'
20
31
  ' containing snapshots of the particle coordinates and optionally velocities that'
21
32
  ' correspond to consecutive, equally spaced points in (simulation) time.'
22
33
  '\n'
23
34
  ' Dynasor has recently been updated. Some of the old options have new names and'
24
35
  ' some new options have been added. If your script has stopped working, check the'
25
36
  ' options with "dynasor --help". In addition, we would like to let you know that'
26
- ' dynasor now has a Python interface, which gives you acces to more'
37
+ ' dynasor now has a Python interface, which gives you access to more'
27
38
  ' functionality and options.')
28
39
 
29
40
  iogroup = parser.add_argument_group(
30
41
  'Input/output options',
31
- 'Options controlling input and output, files and fileformats.')
42
+ 'Options controlling input and output, files and file formats.')
32
43
  iogroup.add_argument(
33
44
  '-f', '--trajectory', type=str, metavar='TRAJECTORY_FILE',
34
45
  help='Molecular dynamics trajectory file to be analyzed.'
@@ -88,7 +99,7 @@ def main():
88
99
 
89
100
  qline = parser.add_argument_group('Line-style q-space sampling')
90
101
  qline.add_argument(
91
- '--q-direction', metavar='QDIRECTION',
102
+ '--q-direction', metavar='QDIRECTION', type=_parse_q_direction,
92
103
  help='Direction along which to sample. QPOINTS points will be evenly placed between'
93
104
  ' 0,0,0 and QDIRECTION. Given as three comma separated values.')
94
105
  defval = 100
@@ -184,11 +195,11 @@ def main():
184
195
 
185
196
  # setup q-points
186
197
  if args.q_sampling == 'line':
187
- q_dir = np.array(args.q_direction)
198
+ q_dir = args.q_direction
188
199
  n_qpoints = args.q_points
189
200
  q_points = np.array([i * q_dir for i in np.linspace(0, 1, n_qpoints)])
190
201
  elif args.q_sampling == 'isotropic':
191
- q_points = get_spherical_qpoints(traj.cell, args.q_max, args.max_q_points)
202
+ q_points = get_spherical_qpoints(traj.cell, q_max=args.q_max, max_points=args.max_q_points)
192
203
 
193
204
  # run dynasor calculation
194
205
  sample = compute_dynamic_structure_factors(
@@ -28,7 +28,7 @@ def calc_rho_q(x, q):
28
28
 
29
29
 
30
30
  def calc_rho_j_q(x, v, q):
31
- """As calc_rho_q, but calculate also velocities in q-space
31
+ """As calc_rho_q, but calculate also velocities in q-space.
32
32
  """
33
33
  assert x.shape == v.shape
34
34
 
@@ -20,29 +20,28 @@ import numba
20
20
  # Calling this instead of manually inlining it actually incurs a small
21
21
  # performance hit (<10%) with current numba (2023). It increases readability
22
22
  # though and will probably sort itself out with later numba versions
23
- @numba.njit(fastmath=True, nogil=True)
23
+ @numba.njit(fastmath=True, nogil=True) # pragma: no cover
24
24
  def dot(a, b):
25
25
  return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
26
26
 
27
27
 
28
28
  # fastmath True makes the summation fast and also speeds up exponentiation
29
- # nogil releases the python GIL, probably not neccesary here
30
- @numba.njit(fastmath=True, nogil=True)
29
+ # nogil releases the Python GIL, although it is probably not necessary here
30
+ @numba.njit(fastmath=True, nogil=True) # pragma: no cover
31
31
  def rho_q_single(x: np.ndarray,
32
32
  q: np.ndarray) -> complex:
33
- """Calculates the density at a single q-point
33
+ """Calculates the density at a single q-point.
34
34
 
35
35
  Parameters
36
36
  ----------
37
37
  x
38
- positions as a (N, 3) array
38
+ Positions as a `(N, 3)` array.
39
39
  q
40
- single q point as a with shape (3,)
40
+ Single q point as a with shape `(3,)`.
41
41
 
42
42
  Returns
43
43
  -------
44
- rho
45
- complex density at the specified q-point
44
+ Complex density at the specified q-point.
46
45
  """
47
46
  Nx = len(x)
48
47
 
@@ -57,20 +56,20 @@ def rho_q_single(x: np.ndarray,
57
56
 
58
57
 
59
58
  # parallel enables the numba.prange directive
60
- @numba.njit(fastmath=True, nogil=True, parallel=True)
59
+ @numba.njit(fastmath=True, nogil=True, parallel=True) # pragma: no cover
61
60
  def rho_q(x: np.ndarray, q: np.ndarray, rho: np.ndarray):
62
- """Calculates the fourier transformed density
61
+ """Calculates the fourier transformed density.
63
62
 
64
63
  The parallelization is over q-points. The density is calculated in-place.
65
64
 
66
65
  Parameters
67
66
  ----------
68
67
  x
69
- the positions as a float array with shape (``Nx``, 3)
68
+ The positions as a float array with shape `(Nx, 3)`.
70
69
  q
71
- the q points as a float array with shape (``Nq``, 3)
70
+ The q-points as a float array with shape `(Nq, 3)`.
72
71
  rho
73
- density as a complex array of length ``Nq``
72
+ Density as a complex array of length `Nq`.
74
73
  """
75
74
 
76
75
  Nx = len(x)
@@ -85,7 +84,7 @@ def rho_q(x: np.ndarray, q: np.ndarray, rho: np.ndarray):
85
84
  rho[i] = rho_q_single(x, q[i])
86
85
 
87
86
 
88
- @numba.njit(fastmath=True, parallel=True, nogil=True)
87
+ @numba.njit(fastmath=True, parallel=True, nogil=True) # pragma: no cover
89
88
  def rho_j_q(x: np.ndarray, v: np.ndarray, q: np.ndarray,
90
89
  rho: np.ndarray, j_q: np.ndarray):
91
90
  """Calculates the fourier transformed density and current.
@@ -95,15 +94,15 @@ def rho_j_q(x: np.ndarray, v: np.ndarray, q: np.ndarray,
95
94
  Parameters
96
95
  ----------
97
96
  x
98
- the positions as a float array with shape (``Nx``, 3)
97
+ The positions as a float array with shape `(Nx, 3)`.
99
98
  v
100
- the velocities as a float array with shape (``Nx``, 3)
99
+ The velocities as a float array with shape `(Nx, 3)`.
101
100
  q
102
- the q points as a float array with shape (``Nq``, 3)
101
+ The q-points as a float array with shape `(Nq, 3)`.
103
102
  rho
104
- density as a complex array of length ``Nq``
103
+ Density as a complex array of length `Nq`.
105
104
  j_q
106
- current as a complex array with shape (``Nq``, 3)
105
+ Current as a complex array with shape `(Nq, 3)`.
107
106
  """
108
107
 
109
108
  Nx = len(x)
@@ -0,0 +1,103 @@
1
+ import numpy as np
2
+ from numpy.typing import NDArray
3
+
4
+
5
+ def truncate_nans(data):
6
+ """
7
+ Truncate trailing time columns that contain NaN values.
8
+
9
+ The function assumes that the last axis of the array corresponds to
10
+ time and removes all columns from the first occurrence of a NaN
11
+ (in any row) to the end of the array.
12
+
13
+ This guarantees that the returned array contains **no NaN values**,
14
+ even if this means discarding some valid data points that appear
15
+ after a NaN in another row.
16
+
17
+ Parameters
18
+ ----------
19
+ data : array_like, shape (N, T)
20
+ Input array where rows represent independent signals (e.g. q-points)
21
+ and the last axis represents time.
22
+
23
+ Returns
24
+ -------
25
+ ndarray
26
+ Array truncated along the time axis such that no NaN values remain.
27
+ The returned array has the same number of rows as the input but may
28
+ have fewer time columns.
29
+
30
+ Notes
31
+ -----
32
+ Example::
33
+
34
+ [[1.0, 0.8, 0.7, 0.6, 0.5, 0.3, nan],
35
+ [1.0, 0.8, 0.7, 0.6, 0.5, nan, nan]]
36
+
37
+ becomes::
38
+
39
+ [[1.0, 0.8, 0.7, 0.6, 0.5],
40
+ [1.0, 0.8, 0.7, 0.6, 0.5]]
41
+
42
+ because the first NaN appears in column 5.
43
+ """
44
+
45
+ arr = np.asarray(data)
46
+ assert arr.ndim == 2
47
+
48
+ # Determine which time columns contain any NaN values
49
+ column_has_nan = np.any(np.isnan(arr), axis=0)
50
+
51
+ # Find the first column containing a NaN
52
+ nan_indices = np.where(column_has_nan)[0]
53
+
54
+ # No NaNs present, return array unchanged
55
+ if len(nan_indices) == 0:
56
+ return arr
57
+
58
+ # NaNs were found, Keep only the column without NaNs
59
+ first_nan_column = nan_indices[0]
60
+ return arr[:, :first_nan_column]
61
+
62
+
63
+ class TimeAverager:
64
+ """Naive special purpose averager class used in dynasor to collect and time-average arrays
65
+ obtained from sliding time-window averaging.
66
+
67
+ It assists with keeping track of how many data samples have been added to each slot.
68
+
69
+ It will time-average arrays of shape ``(Nq, time_window)`` where ``Ǹq`` is the
70
+ number of q-points and ``time_window`` is the size of the time window.
71
+
72
+ Parameters
73
+ ----------
74
+ time_window
75
+ Size of the time window in which the time-average happens.
76
+ array_length
77
+ Length of the array to be averaged for each time-lag, i.e., number of q-points.
78
+ """
79
+
80
+ def __init__(self, time_window: int, array_length: int):
81
+ assert time_window >= 1
82
+ self._time_window = time_window
83
+ self._array_length = array_length
84
+
85
+ self._counts = np.zeros(time_window, dtype=int)
86
+ self._arrays = [np.zeros(array_length) for _ in range(time_window)]
87
+
88
+ def add_sample(self, time_lag: int, sample: np.ndarray):
89
+ assert len(sample) == self._array_length
90
+ self._counts[time_lag] += 1
91
+ self._arrays[time_lag] += sample
92
+
93
+ def get_average_at_timelag(self, time_lag: int):
94
+ if self._counts[time_lag] == 0:
95
+ array = np.full((self._array_length, ), np.nan)
96
+ return array
97
+ return self._arrays[time_lag] / self._counts[time_lag]
98
+
99
+ def get_average_all(self) -> NDArray[float]:
100
+ """
101
+ Returns an averaged array of shape ``(array_length, time_window)``.
102
+ """
103
+ return np.array([self.get_average_at_timelag(t) for t in range(self._time_window)]).T