nabu 2023.2.1__py3-none-any.whl → 2024.1.0rc3__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.
Files changed (183) hide show
  1. doc/conf.py +1 -1
  2. doc/doc_config.py +32 -0
  3. nabu/__init__.py +2 -1
  4. nabu/app/bootstrap_stitching.py +1 -1
  5. nabu/app/cli_configs.py +122 -2
  6. nabu/app/composite_cor.py +27 -2
  7. nabu/app/correct_rot.py +70 -0
  8. nabu/app/create_distortion_map_from_poly.py +42 -18
  9. nabu/app/diag_to_pix.py +358 -0
  10. nabu/app/diag_to_rot.py +449 -0
  11. nabu/app/generate_header.py +4 -3
  12. nabu/app/histogram.py +2 -2
  13. nabu/app/multicor.py +6 -1
  14. nabu/app/parse_reconstruction_log.py +151 -0
  15. nabu/app/prepare_weights_double.py +83 -22
  16. nabu/app/reconstruct.py +5 -1
  17. nabu/app/reconstruct_helical.py +7 -0
  18. nabu/app/reduce_dark_flat.py +6 -3
  19. nabu/app/rotate.py +4 -4
  20. nabu/app/stitching.py +16 -2
  21. nabu/app/tests/test_reduce_dark_flat.py +18 -2
  22. nabu/app/validator.py +4 -4
  23. nabu/cuda/convolution.py +8 -376
  24. nabu/cuda/fft.py +4 -0
  25. nabu/cuda/kernel.py +4 -4
  26. nabu/cuda/medfilt.py +5 -158
  27. nabu/cuda/padding.py +5 -71
  28. nabu/cuda/processing.py +23 -2
  29. nabu/cuda/src/ElementOp.cu +78 -0
  30. nabu/cuda/src/backproj.cu +28 -2
  31. nabu/cuda/src/fourier_wavelets.cu +2 -2
  32. nabu/cuda/src/normalization.cu +23 -0
  33. nabu/cuda/src/padding.cu +2 -2
  34. nabu/cuda/src/transpose.cu +16 -0
  35. nabu/cuda/utils.py +39 -0
  36. nabu/estimation/alignment.py +10 -1
  37. nabu/estimation/cor.py +808 -38
  38. nabu/estimation/cor_sino.py +7 -9
  39. nabu/estimation/tests/test_cor.py +85 -3
  40. nabu/io/reader.py +26 -18
  41. nabu/io/tests/test_cast_volume.py +3 -3
  42. nabu/io/tests/test_detector_distortion.py +3 -3
  43. nabu/io/tiffwriter_zmm.py +2 -2
  44. nabu/io/utils.py +14 -4
  45. nabu/io/writer.py +5 -3
  46. nabu/misc/fftshift.py +6 -0
  47. nabu/misc/histogram.py +5 -285
  48. nabu/misc/histogram_cuda.py +8 -104
  49. nabu/misc/kernel_base.py +3 -121
  50. nabu/misc/padding_base.py +5 -69
  51. nabu/misc/processing_base.py +3 -107
  52. nabu/misc/rotation.py +5 -62
  53. nabu/misc/rotation_cuda.py +5 -65
  54. nabu/misc/transpose.py +6 -0
  55. nabu/misc/unsharp.py +3 -78
  56. nabu/misc/unsharp_cuda.py +5 -52
  57. nabu/misc/unsharp_opencl.py +8 -85
  58. nabu/opencl/fft.py +6 -0
  59. nabu/opencl/kernel.py +21 -6
  60. nabu/opencl/padding.py +5 -72
  61. nabu/opencl/processing.py +27 -5
  62. nabu/opencl/src/backproj.cl +3 -3
  63. nabu/opencl/src/fftshift.cl +65 -12
  64. nabu/opencl/src/padding.cl +2 -2
  65. nabu/opencl/src/roll.cl +96 -0
  66. nabu/opencl/src/transpose.cl +16 -0
  67. nabu/pipeline/config_validators.py +63 -3
  68. nabu/pipeline/dataset_validator.py +2 -2
  69. nabu/pipeline/estimators.py +193 -35
  70. nabu/pipeline/fullfield/chunked.py +34 -17
  71. nabu/pipeline/fullfield/chunked_cuda.py +7 -5
  72. nabu/pipeline/fullfield/computations.py +48 -13
  73. nabu/pipeline/fullfield/nabu_config.py +13 -13
  74. nabu/pipeline/fullfield/processconfig.py +10 -5
  75. nabu/pipeline/fullfield/reconstruction.py +1 -2
  76. nabu/pipeline/helical/fbp.py +5 -0
  77. nabu/pipeline/helical/filtering.py +12 -9
  78. nabu/pipeline/helical/gridded_accumulator.py +179 -33
  79. nabu/pipeline/helical/helical_chunked_regridded.py +262 -151
  80. nabu/pipeline/helical/helical_chunked_regridded_cuda.py +4 -11
  81. nabu/pipeline/helical/helical_reconstruction.py +56 -18
  82. nabu/pipeline/helical/span_strategy.py +1 -1
  83. nabu/pipeline/helical/tests/test_accumulator.py +4 -0
  84. nabu/pipeline/params.py +23 -2
  85. nabu/pipeline/processconfig.py +3 -8
  86. nabu/pipeline/tests/test_chunk_reader.py +78 -0
  87. nabu/pipeline/tests/test_estimators.py +120 -2
  88. nabu/pipeline/utils.py +25 -0
  89. nabu/pipeline/writer.py +2 -0
  90. nabu/preproc/ccd_cuda.py +9 -7
  91. nabu/preproc/ctf.py +21 -26
  92. nabu/preproc/ctf_cuda.py +25 -25
  93. nabu/preproc/double_flatfield.py +14 -2
  94. nabu/preproc/double_flatfield_cuda.py +7 -11
  95. nabu/preproc/flatfield_cuda.py +23 -27
  96. nabu/preproc/phase.py +19 -24
  97. nabu/preproc/phase_cuda.py +21 -21
  98. nabu/preproc/shift_cuda.py +58 -28
  99. nabu/preproc/tests/test_ctf.py +5 -5
  100. nabu/preproc/tests/test_double_flatfield.py +2 -2
  101. nabu/preproc/tests/test_vshift.py +13 -2
  102. nabu/processing/__init__.py +0 -0
  103. nabu/processing/convolution_cuda.py +375 -0
  104. nabu/processing/fft_base.py +163 -0
  105. nabu/processing/fft_cuda.py +256 -0
  106. nabu/processing/fft_opencl.py +54 -0
  107. nabu/processing/fftshift.py +134 -0
  108. nabu/processing/histogram.py +286 -0
  109. nabu/processing/histogram_cuda.py +103 -0
  110. nabu/processing/kernel_base.py +126 -0
  111. nabu/processing/medfilt_cuda.py +159 -0
  112. nabu/processing/muladd.py +29 -0
  113. nabu/processing/muladd_cuda.py +68 -0
  114. nabu/processing/padding_base.py +71 -0
  115. nabu/processing/padding_cuda.py +75 -0
  116. nabu/processing/padding_opencl.py +77 -0
  117. nabu/processing/processing_base.py +123 -0
  118. nabu/processing/roll_opencl.py +64 -0
  119. nabu/processing/rotation.py +63 -0
  120. nabu/processing/rotation_cuda.py +66 -0
  121. nabu/processing/tests/__init__.py +0 -0
  122. nabu/processing/tests/test_fft.py +268 -0
  123. nabu/processing/tests/test_fftshift.py +71 -0
  124. nabu/{misc → processing}/tests/test_histogram.py +2 -4
  125. nabu/{cuda → processing}/tests/test_medfilt.py +1 -1
  126. nabu/processing/tests/test_muladd.py +54 -0
  127. nabu/{cuda → processing}/tests/test_padding.py +119 -75
  128. nabu/processing/tests/test_roll.py +63 -0
  129. nabu/{misc → processing}/tests/test_rotation.py +3 -2
  130. nabu/processing/tests/test_transpose.py +72 -0
  131. nabu/{misc → processing}/tests/test_unsharp.py +41 -8
  132. nabu/processing/transpose.py +126 -0
  133. nabu/processing/unsharp.py +79 -0
  134. nabu/processing/unsharp_cuda.py +53 -0
  135. nabu/processing/unsharp_opencl.py +75 -0
  136. nabu/reconstruction/fbp.py +34 -10
  137. nabu/reconstruction/fbp_base.py +35 -16
  138. nabu/reconstruction/fbp_opencl.py +7 -12
  139. nabu/reconstruction/filtering.py +2 -2
  140. nabu/reconstruction/filtering_cuda.py +13 -14
  141. nabu/reconstruction/filtering_opencl.py +3 -4
  142. nabu/reconstruction/projection.py +2 -0
  143. nabu/reconstruction/rings.py +158 -1
  144. nabu/reconstruction/rings_cuda.py +218 -58
  145. nabu/reconstruction/sinogram_cuda.py +16 -12
  146. nabu/reconstruction/tests/test_deringer.py +116 -14
  147. nabu/reconstruction/tests/test_fbp.py +22 -31
  148. nabu/reconstruction/tests/test_filtering.py +11 -2
  149. nabu/resources/dataset_analyzer.py +89 -26
  150. nabu/resources/nxflatfield.py +2 -2
  151. nabu/resources/tests/test_nxflatfield.py +1 -1
  152. nabu/resources/utils.py +9 -2
  153. nabu/stitching/alignment.py +184 -0
  154. nabu/stitching/config.py +241 -39
  155. nabu/stitching/definitions.py +6 -0
  156. nabu/stitching/frame_composition.py +4 -2
  157. nabu/stitching/overlap.py +99 -3
  158. nabu/stitching/sample_normalization.py +60 -0
  159. nabu/stitching/slurm_utils.py +10 -10
  160. nabu/stitching/tests/test_alignment.py +99 -0
  161. nabu/stitching/tests/test_config.py +16 -1
  162. nabu/stitching/tests/test_overlap.py +68 -2
  163. nabu/stitching/tests/test_sample_normalization.py +49 -0
  164. nabu/stitching/tests/test_slurm_utils.py +5 -5
  165. nabu/stitching/tests/test_utils.py +3 -33
  166. nabu/stitching/tests/test_z_stitching.py +391 -22
  167. nabu/stitching/utils.py +144 -202
  168. nabu/stitching/z_stitching.py +309 -126
  169. nabu/testutils.py +18 -0
  170. nabu/thirdparty/tomocupy_remove_stripe.py +586 -0
  171. nabu/utils.py +32 -6
  172. {nabu-2023.2.1.dist-info → nabu-2024.1.0rc3.dist-info}/LICENSE +1 -1
  173. {nabu-2023.2.1.dist-info → nabu-2024.1.0rc3.dist-info}/METADATA +5 -5
  174. nabu-2024.1.0rc3.dist-info/RECORD +296 -0
  175. {nabu-2023.2.1.dist-info → nabu-2024.1.0rc3.dist-info}/WHEEL +1 -1
  176. {nabu-2023.2.1.dist-info → nabu-2024.1.0rc3.dist-info}/entry_points.txt +5 -1
  177. nabu/conftest.py +0 -14
  178. nabu/opencl/fftshift.py +0 -92
  179. nabu/opencl/tests/test_fftshift.py +0 -55
  180. nabu/opencl/tests/test_padding.py +0 -84
  181. nabu-2023.2.1.dist-info/RECORD +0 -252
  182. /nabu/cuda/src/{fftshift.cu → dfi_fftshift.cu} +0 -0
  183. {nabu-2023.2.1.dist-info → nabu-2024.1.0rc3.dist-info}/top_level.txt +0 -0
nabu/opencl/processing.py CHANGED
@@ -1,16 +1,24 @@
1
- import numpy as np
2
- from ..misc.processing_base import ProcessingBase
1
+ from ..processing.processing_base import ProcessingBase
2
+ from ..utils import MissingComponentError
3
3
  from .utils import get_opencl_context, __has_pyopencl__
4
4
 
5
5
  if __has_pyopencl__:
6
+ from .kernel import OpenCLKernel
6
7
  import pyopencl as cl
7
8
  import pyopencl.array as parray
9
+ from pyopencl.tools import dtype_to_ctype
10
+
11
+ OpenCLArray = parray.Array
12
+ else:
13
+ OpenCLArray = MissingComponentError("pyopencl")
14
+ dtype_to_ctype = MissingComponentError("pyopencl")
8
15
 
9
16
 
10
17
  class OpenCLProcessing(ProcessingBase):
11
- _array_class = parray.Array
18
+ array_class = OpenCLArray
19
+ dtype_to_ctype = dtype_to_ctype
12
20
 
13
- def __init__(self, ctx=None, device_type="all", queue=None, **kwargs):
21
+ def __init__(self, ctx=None, device_type="all", queue=None, profile=False, **kwargs):
14
22
  """
15
23
  Initialie a OpenCLProcessing instance.
16
24
 
@@ -31,10 +39,24 @@ class OpenCLProcessing(ProcessingBase):
31
39
  else:
32
40
  self.ctx = ctx
33
41
  if queue is None:
34
- queue = cl.CommandQueue(self.ctx)
42
+ queue_init_kwargs = {}
43
+ if profile:
44
+ queue_init_kwargs = {"properties": cl.command_queue_properties.PROFILING_ENABLE}
45
+ queue = cl.CommandQueue(self.ctx, **queue_init_kwargs)
35
46
  self.queue = queue
36
47
 
37
48
  # TODO push_context, pop_context ?
38
49
 
39
50
  def _allocate_array_mem(self, shape, dtype):
40
51
  return parray.zeros(self.queue, shape, dtype)
52
+
53
+ def kernel(self, kernel_name, filename=None, src=None, automation_params=None, **build_kwargs):
54
+ return OpenCLKernel(
55
+ kernel_name,
56
+ None,
57
+ queue=self.queue,
58
+ filename=filename,
59
+ src=src,
60
+ automation_params=automation_params,
61
+ **build_kwargs,
62
+ )
@@ -17,7 +17,7 @@ static inline float linear_interpolation(global float* arr, int Nx, float x, int
17
17
  if (x < 0 || x >= Nx) return 0.0f; // texture address mode CLAMP_TO_EDGE
18
18
  int xm = (int) floor(x);
19
19
  int xp = (int) ceil(x);
20
- if (xm == xp) return arr[y*Nx+xm];
20
+ if ((xm == xp) || (xp >= Nx)) return arr[y*Nx+xm];
21
21
  else return (arr[y*Nx+xm] * (xp - x)) + (arr[y*Nx+xp] * (x - xm));
22
22
  }
23
23
 
@@ -35,8 +35,8 @@ kernel void backproj(
35
35
  float axis_position,
36
36
  int n_x,
37
37
  int n_y,
38
- int offset_x,
39
- int offset_y,
38
+ float offset_x,
39
+ float offset_y,
40
40
  global float* d_cos,
41
41
  global float* d_msin,
42
42
  #ifdef DO_AXIS_CORRECTION
@@ -1,24 +1,77 @@
1
1
  #include <pyopencl-complex.h>
2
- typedef cfloat_t complex;
3
2
 
3
+ #ifndef DTYPE
4
+ #define DTYPE float
5
+ #endif
4
6
 
5
- /*
6
- In-place one-dimensional fftshift, along fast (horizontal) dimension.
7
+
8
+ static inline void swap(global DTYPE* arr, size_t idx, size_t idx2) {
9
+ DTYPE tmp = arr[idx];
10
+ arr[idx] = arr[idx2];
11
+ arr[idx2] = tmp;
12
+ }
13
+
14
+
15
+ /*
16
+ In-place one-dimensional fftshift, along horizontal dimension.
7
17
  The array can be 1D or 2D.
18
+
19
+ direction > 0 means fftshift, direction < 0 means ifftshift.
20
+
21
+ It works for even-sized arrays.
22
+ Odd-sized arrays need an additional step (see roll.cl: roll_forward_x)
23
+
8
24
  */
9
- __kernel void fftshift1(
10
- __global DTYPE* array,
25
+
26
+ __kernel void fftshift_x_inplace(
27
+ __global DTYPE* arr,
11
28
  int Nx,
12
- int Ny
29
+ int Ny,
30
+ int direction
13
31
  ) {
14
32
  int x = get_global_id(0), y = get_global_id(1);
15
- int N2 = Nx >> 1;
16
- int N2b = Nx - N2;
17
- if (x >= N2b || y >= Ny) return;
18
- DTYPE tmp = array[y*Nx + x];
19
- if (x < N2) array[y*Nx + x] = array[y*Nx + N2b + x]
20
- array[y*Nx + N2 + x] = tmp
33
+
34
+ int shift = Nx / 2;
35
+ if (x >= shift) return;
36
+
37
+ // (i)fftshift on odd-sized arrays cannot be done in-place in one step - need another kernel after this one
38
+ if ((Nx & 1) && (direction > 0)) shift++;
39
+ size_t idx = y * Nx + x;
40
+ size_t idx_out = y * Nx + ((x + shift) % Nx);
41
+ swap(arr, idx, idx_out);
42
+ }
43
+
44
+
45
+ #ifdef DTYPE_OUT
46
+
47
+ /*
48
+ Out-of-place fftshift, possibly with type casting - useful for eg. fft(ifftshift(array))
49
+ */
50
+ __kernel void fftshift_x(global DTYPE* arr, global DTYPE_OUT* dst, int Nx, int Ny, int direction) {
51
+
52
+ int x = get_global_id(0), y = get_global_id(1);
53
+ if (x >= Nx || y >= Ny) return;
54
+
55
+ int shift = Nx / 2;
56
+ if ((Nx & 1) && (direction < 0)) shift++;
57
+
58
+ size_t idx = y * Nx + x;
59
+ size_t idx_out = y * Nx + ((x + shift) % Nx);
60
+
61
+ DTYPE_OUT out_item;
62
+ #ifdef CAST_TO_COMPLEX
63
+ out_item = cfloat_new(arr[idx], 0);
64
+ #else
65
+ #ifdef CAST_TO_REAL
66
+ out_item = cfloat_real(arr[idx]);
67
+ #else
68
+ out_item = (DTYPE_OUT) arr[idx];
69
+ #endif
70
+ #endif
71
+ dst[idx_out] = out_item;
72
+
21
73
  }
22
74
 
75
+ #endif
23
76
 
24
77
 
@@ -13,8 +13,8 @@ __kernel void coordinate_transform(
13
13
  uint y = get_global_id(1);
14
14
  if ((x >= Nx_padded) || (y >= Ny_padded)) return;
15
15
  uint idx = y*Nx_padded + x;
16
- int x2 = cols_inds[idx];
17
- int y2 = rows_inds[idx];
16
+ int x2 = cols_inds[x];
17
+ int y2 = rows_inds[y];
18
18
  array_out[idx] = array_in[y2*Nx + x2];
19
19
  }
20
20
 
@@ -0,0 +1,96 @@
1
+ #include <pyopencl-complex.h>
2
+
3
+
4
+ static inline void swap(global DTYPE* arr, size_t idx, size_t idx2) {
5
+ DTYPE tmp = arr[idx];
6
+ arr[idx] = arr[idx2];
7
+ arr[idx2] = tmp;
8
+ }
9
+
10
+
11
+ /*
12
+ This code should work but it not used yet.
13
+ The first intent was to have an in-place fftshift for odd-sized arrays:
14
+ fftshift_odd = fftshift_even followed by roll(-1) on second half of the array
15
+ ifft_odd = fftshift_even followed by roll(1) on second half of the array
16
+
17
+ Roll elements (as in numpy.roll(arr, 1)) of an array, in-place.
18
+ Needs to be launched with a large horizontal work group.
19
+ */
20
+ __kernel void roll_forward_x(
21
+ __global DTYPE* array,
22
+ int Nx,
23
+ int Ny,
24
+ int offset_x,
25
+ __local DTYPE* shmem
26
+ ) {
27
+
28
+ int Nx_tot = Nx;
29
+ if (offset_x > 0) {
30
+ Nx_tot = Nx;
31
+ Nx -= offset_x;
32
+ }
33
+
34
+ int x = get_global_id(0), y = get_global_id(1);
35
+ if ((x >= Nx / 2) || (y >= Ny)) return;
36
+
37
+ __global DTYPE* arr = array + y * Nx_tot + offset_x;
38
+
39
+ int lid = get_local_id(0);
40
+ int wg_size = get_local_size(0);
41
+
42
+ int n_steps = (int) ceil((Nx - (Nx & 1)) * 1.0f / (2*wg_size));
43
+
44
+ DTYPE previous, current, write_on_first;
45
+ int offset = 0;
46
+
47
+ for (int step = 0; step < n_steps; step++) {
48
+
49
+ int idx = 2*lid + 1;
50
+ if (offset + idx >= Nx) break;
51
+
52
+ previous = arr[offset + idx - 1];
53
+ current = arr[offset + idx];
54
+ arr[offset + idx] = previous;
55
+
56
+ if ((step == n_steps - 1) && (offset + idx + 1 >= Nx - 1)) {
57
+ if (Nx & 1) write_on_first = arr[offset + idx + 1];
58
+ else write_on_first = current;
59
+ }
60
+
61
+ barrier(CLK_LOCAL_MEM_FENCE);
62
+
63
+ if ((step > 0) && (lid == 0)) arr[offset + idx - 1] = shmem[0];
64
+ if ((lid == wg_size - 1) && (step < n_steps - 1)) shmem[0] = current;
65
+ else if (offset + idx + 1 <= Nx - 1) arr[offset + idx + 1] = current;
66
+
67
+ if ((step == n_steps - 1) && (offset + idx + 1 >= Nx - 1)) arr[0] = write_on_first;
68
+
69
+ barrier(CLK_LOCAL_MEM_FENCE);
70
+
71
+ offset += 2 * wg_size;
72
+ }
73
+
74
+ }
75
+
76
+
77
+ __kernel void revert_array_x(
78
+ __global DTYPE* array,
79
+ int Nx,
80
+ int Ny,
81
+ int offset_x
82
+ ) {
83
+ int x = get_global_id(0), y = get_global_id(1);
84
+
85
+ int Nx_tot = Nx;
86
+ if (offset_x > 0) {
87
+ Nx_tot = Nx;
88
+ Nx -= offset_x;
89
+ }
90
+
91
+ if ((x >= Nx / 2) || (y >= Ny)) return;
92
+
93
+ size_t idx = y * Nx_tot + offset_x + x;
94
+ size_t idx2 = y * Nx_tot + offset_x + (Nx - 1 - x); // Nx ?
95
+ swap(array, idx, idx2);
96
+ }
@@ -0,0 +1,16 @@
1
+ #ifndef SRC_DTYPE
2
+ #define SRC_DTYPE float
3
+ #endif
4
+ #ifndef DST_DTYPE
5
+ #define DST_DTYPE float
6
+ #endif
7
+
8
+ #include <pyopencl-complex.h>
9
+
10
+ __kernel void transpose(__global SRC_DTYPE* src, __global DST_DTYPE* dst, int src_width, int src_height) {
11
+ // coordinates for "dst"
12
+ uint x = get_global_id(0);
13
+ uint y = get_global_id(1);
14
+ if ((x >= src_height) || (y >= src_width)) return;
15
+ dst[y*src_height + x] = (DST_DTYPE) src[x*src_width + y];
16
+ }
@@ -1,7 +1,7 @@
1
1
  import os
2
2
 
3
3
  path = os.path
4
- from ..utils import is_writeable
4
+ from ..utils import check_supported, is_writeable
5
5
  from .params import *
6
6
 
7
7
  """
@@ -63,15 +63,32 @@ def convert_to_bool(val):
63
63
  if not error:
64
64
  res = val_int > 0
65
65
  else:
66
- if val.lower() in ["yes", "true"]:
66
+ if val.lower() in ["yes", "true", "y"]:
67
67
  res = True
68
68
  error = None
69
- if val.lower() in ["no", "false"]:
69
+ if val.lower() in ["no", "false", "n"]:
70
70
  res = False
71
71
  error = None
72
72
  return res, error
73
73
 
74
74
 
75
+ def str2bool(val):
76
+ """This is an interface to convert_to_bool and it is meant
77
+ to work as a class: in argparse interface the type argument can be set to float, int .. in general to a class.
78
+ The argument value is then created, at parsing time, by typecasting the input string to the given class.
79
+ A possibly occuring exception then trigger, in case, the display explanation provided by the argparse library.
80
+ All what this methods does is simply trying to convert an argument into a bool, and return it,
81
+ or generate an exception if there is a problem
82
+ """
83
+ import argparse
84
+
85
+ res, error = convert_to_bool(val)
86
+ if error:
87
+ raise argparse.ArgumentTypeError(error)
88
+ else:
89
+ return res
90
+
91
+
75
92
  def convert_to_bool_noerr(val):
76
93
  res, err = convert_to_bool(val)
77
94
  if err is not None:
@@ -226,6 +243,20 @@ def binning_validator(val):
226
243
  return max(1, val_int)
227
244
 
228
245
 
246
+ @validator
247
+ def projections_subsampling_validator(val):
248
+ val = val.strip()
249
+ err_msg = "projections_subsampling: expected one positive integer or two integers in the format step:begin"
250
+ if ":" not in val:
251
+ val += ":0"
252
+ step, begin = val.split(":")
253
+ step_int, error1 = convert_to_int(step)
254
+ begin_int, error2 = convert_to_int(begin)
255
+ if error1 is not None or error2 is not None or step_int <= 0 or begin_int < 0:
256
+ raise ValueError(err_msg)
257
+ return step_int, begin_int
258
+
259
+
229
260
  @validator
230
261
  def optional_file_name_validator(val):
231
262
  if len(val) > 0:
@@ -524,6 +555,35 @@ def logging_validator(val):
524
555
  return name_range_checker(val, set(log_levels.values()), "logging level", replacements=log_levels)
525
556
 
526
557
 
558
+ @validator
559
+ def exclude_projections_validator(val):
560
+ val = val.strip()
561
+ if val == "":
562
+ return None
563
+ if path.isfile(val):
564
+ # previous/default behavior
565
+ return {"type": "indices", "file": val}
566
+ if "=" not in val:
567
+ raise ValueError(
568
+ "exclude_projections: expected either 'angles=angles_file.txt' or 'indices=indices_file.txt' or 'angular_range=[a,b]'"
569
+ )
570
+ excl_type, excl_val = val.split("=")
571
+ excl_type = excl_type.strip()
572
+ excl_val = excl_val.strip()
573
+ check_supported(excl_type, exclude_projections_type.keys(), "exclude_projections type")
574
+ if excl_type == "angular_range":
575
+
576
+ def _get_range(range_val):
577
+ for c in ["(", ")", "[", "]"]:
578
+ range_val = range_val.replace(c, "")
579
+ r_min, r_max = range_val.split(",")
580
+ return (float(r_min), float(r_max))
581
+
582
+ return {"type": "angular_range", "range": _get_range(excl_val)}
583
+ else:
584
+ return {"type": excl_type, "file": excl_val}
585
+
586
+
527
587
  @validator
528
588
  def no_validator(val):
529
589
  return val
@@ -157,7 +157,7 @@ class DatasetValidatorBase:
157
157
  """
158
158
  dataset_cfg = self.nabu_config["dataset"]
159
159
  self.binning = (dataset_cfg["binning"], dataset_cfg["binning_z"])
160
- subsampling_factor = dataset_cfg["projections_subsampling"]
160
+ subsampling_factor, subsampling_begin = dataset_cfg["projections_subsampling"]
161
161
  self.subsampling_factor = subsampling_factor or 1
162
162
 
163
163
  if self.binning != (1, 1):
@@ -207,5 +207,5 @@ class DatasetValidatorBase:
207
207
  # TODO automatically compute binning/subsampling factors as a function of lowest memory (GPU)
208
208
  self.nabu_config["dataset"]["binning"] = 2
209
209
  self.nabu_config["dataset"]["binning_z"] = 2
210
- self.nabu_config["dataset"]["projections_subsampling"] = 2
210
+ self.nabu_config["dataset"]["projections_subsampling"] = 2, 0
211
211
  # TODO handle other modes