reflectorch 1.0.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 reflectorch might be problematic. Click here for more details.

Files changed (83) hide show
  1. reflectorch/__init__.py +23 -0
  2. reflectorch/data_generation/__init__.py +130 -0
  3. reflectorch/data_generation/dataset.py +196 -0
  4. reflectorch/data_generation/likelihoods.py +86 -0
  5. reflectorch/data_generation/noise.py +371 -0
  6. reflectorch/data_generation/priors/__init__.py +66 -0
  7. reflectorch/data_generation/priors/base.py +61 -0
  8. reflectorch/data_generation/priors/exp_subprior_sampler.py +304 -0
  9. reflectorch/data_generation/priors/independent_priors.py +201 -0
  10. reflectorch/data_generation/priors/multilayer_models.py +311 -0
  11. reflectorch/data_generation/priors/multilayer_structures.py +110 -0
  12. reflectorch/data_generation/priors/no_constraints.py +212 -0
  13. reflectorch/data_generation/priors/parametric_models.py +767 -0
  14. reflectorch/data_generation/priors/parametric_subpriors.py +354 -0
  15. reflectorch/data_generation/priors/params.py +258 -0
  16. reflectorch/data_generation/priors/sampler_strategies.py +306 -0
  17. reflectorch/data_generation/priors/scaler_mixin.py +65 -0
  18. reflectorch/data_generation/priors/subprior_sampler.py +377 -0
  19. reflectorch/data_generation/priors/utils.py +124 -0
  20. reflectorch/data_generation/process_data.py +47 -0
  21. reflectorch/data_generation/q_generator.py +232 -0
  22. reflectorch/data_generation/reflectivity/__init__.py +56 -0
  23. reflectorch/data_generation/reflectivity/abeles.py +81 -0
  24. reflectorch/data_generation/reflectivity/kinematical.py +58 -0
  25. reflectorch/data_generation/reflectivity/memory_eff.py +92 -0
  26. reflectorch/data_generation/reflectivity/numpy_implementations.py +120 -0
  27. reflectorch/data_generation/reflectivity/smearing.py +123 -0
  28. reflectorch/data_generation/scale_curves.py +118 -0
  29. reflectorch/data_generation/smearing.py +67 -0
  30. reflectorch/data_generation/utils.py +154 -0
  31. reflectorch/extensions/__init__.py +6 -0
  32. reflectorch/extensions/jupyter/__init__.py +12 -0
  33. reflectorch/extensions/jupyter/callbacks.py +40 -0
  34. reflectorch/extensions/matplotlib/__init__.py +11 -0
  35. reflectorch/extensions/matplotlib/losses.py +38 -0
  36. reflectorch/inference/__init__.py +22 -0
  37. reflectorch/inference/inference_model.py +734 -0
  38. reflectorch/inference/multilayer_fitter.py +171 -0
  39. reflectorch/inference/multilayer_inference_model.py +193 -0
  40. reflectorch/inference/preprocess_exp/__init__.py +7 -0
  41. reflectorch/inference/preprocess_exp/attenuation.py +36 -0
  42. reflectorch/inference/preprocess_exp/cut_with_q_ratio.py +31 -0
  43. reflectorch/inference/preprocess_exp/footprint.py +81 -0
  44. reflectorch/inference/preprocess_exp/interpolation.py +16 -0
  45. reflectorch/inference/preprocess_exp/normalize.py +21 -0
  46. reflectorch/inference/preprocess_exp/preprocess.py +121 -0
  47. reflectorch/inference/record_time.py +43 -0
  48. reflectorch/inference/sampler_solution.py +56 -0
  49. reflectorch/inference/scipy_fitter.py +171 -0
  50. reflectorch/inference/torch_fitter.py +87 -0
  51. reflectorch/ml/__init__.py +37 -0
  52. reflectorch/ml/basic_trainer.py +286 -0
  53. reflectorch/ml/callbacks.py +86 -0
  54. reflectorch/ml/dataloaders.py +27 -0
  55. reflectorch/ml/loggers.py +38 -0
  56. reflectorch/ml/schedulers.py +246 -0
  57. reflectorch/ml/trainers.py +126 -0
  58. reflectorch/ml/utils.py +9 -0
  59. reflectorch/models/__init__.py +22 -0
  60. reflectorch/models/activations.py +50 -0
  61. reflectorch/models/encoders/__init__.py +27 -0
  62. reflectorch/models/encoders/conv_encoder.py +211 -0
  63. reflectorch/models/encoders/conv_res_net.py +119 -0
  64. reflectorch/models/encoders/fno.py +127 -0
  65. reflectorch/models/encoders/transformers.py +56 -0
  66. reflectorch/models/networks/__init__.py +18 -0
  67. reflectorch/models/networks/mlp_networks.py +256 -0
  68. reflectorch/models/networks/residual_net.py +131 -0
  69. reflectorch/paths.py +33 -0
  70. reflectorch/runs/__init__.py +35 -0
  71. reflectorch/runs/config.py +31 -0
  72. reflectorch/runs/slurm_utils.py +99 -0
  73. reflectorch/runs/train.py +85 -0
  74. reflectorch/runs/utils.py +300 -0
  75. reflectorch/test_config.py +4 -0
  76. reflectorch/train.py +4 -0
  77. reflectorch/train_on_cluster.py +4 -0
  78. reflectorch/utils.py +74 -0
  79. reflectorch-1.0.0.dist-info/LICENSE.txt +621 -0
  80. reflectorch-1.0.0.dist-info/METADATA +115 -0
  81. reflectorch-1.0.0.dist-info/RECORD +83 -0
  82. reflectorch-1.0.0.dist-info/WHEEL +5 -0
  83. reflectorch-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,306 @@
1
+ import torch
2
+ from torch import Tensor
3
+
4
+ from reflectorch.data_generation.utils import (
5
+ uniform_sampler,
6
+ logdist_sampler,
7
+ )
8
+
9
+ from reflectorch.data_generation.priors.utils import get_max_allowed_roughness
10
+
11
+
12
+ class SamplerStrategy(object):
13
+ """Base class for sampler strategies"""
14
+ def sample(self, batch_size: int,
15
+ total_min_bounds: Tensor,
16
+ total_max_bounds: Tensor,
17
+ total_min_delta: Tensor,
18
+ total_max_delta: Tensor,
19
+ ):
20
+ raise NotImplementedError
21
+
22
+
23
+ class BasicSamplerStrategy(SamplerStrategy):
24
+ """Sampler strategy with no constraints on the values of the parameters
25
+
26
+ Args:
27
+ logdist (bool, optional): if True the relative widths of the subprior intervals are sampled uniformly on a logarithmic scale instead of uniformly. Defaults to False.
28
+ """
29
+ def __init__(self, logdist: bool = False):
30
+ if logdist:
31
+ self.widths_sampler_func = logdist_sampler
32
+ else:
33
+ self.widths_sampler_func = uniform_sampler
34
+
35
+ def sample(self, batch_size: int,
36
+ total_min_bounds: Tensor,
37
+ total_max_bounds: Tensor,
38
+ total_min_delta: Tensor,
39
+ total_max_delta: Tensor,
40
+ ):
41
+ """
42
+ Args:
43
+ batch_size (int): the batch size
44
+ total_min_bounds (Tensor): mimimum values of the parameters
45
+ total_max_bounds (Tensor): maximum values of the parameters
46
+ total_min_delta (Tensor): minimum widths of the subprior intervals
47
+ total_max_delta (Tensor): maximum widths of the subprior intervals
48
+
49
+ Returns:
50
+ tuple(Tensor): samples the values of the parameters and their prior bounds (params, min_bounds, max_bounds). The widths W of the subprior interval are sampled first, then the centers C of the subprior interval, such that the prior bounds are C-W/2 and C+W/2, then the parameters are sampled from [C-W/2, C+W/2] )
51
+ """
52
+ return basic_sampler(
53
+ batch_size,
54
+ total_min_bounds,
55
+ total_max_bounds,
56
+ total_min_delta,
57
+ total_max_delta,
58
+ self.widths_sampler_func,
59
+ )
60
+
61
+
62
+ class ConstrainedRoughnessSamplerStrategy(BasicSamplerStrategy):
63
+ """Sampler strategy where the roughnesses are constrained not to exceed a fraction of the two neighboring thicknesses
64
+
65
+ Args:
66
+ thickness_mask (Tensor): indices in the tensors which correspond to thicknesses
67
+ roughness_mask (Tensor): indices in the tensors which correspond to roughnesses
68
+ logdist (bool, optional): if ``True`` the relative widths of the subprior intervals are sampled uniformly on a logarithmic scale instead of uniformly. Defaults to False.
69
+ max_thickness_share (float, optional): fraction of the layer thickness that the roughness should not exceed. Defaults to 0.5.
70
+ """
71
+ def __init__(self,
72
+ thickness_mask: Tensor,
73
+ roughness_mask: Tensor,
74
+ logdist: bool = False,
75
+ max_thickness_share: float = 0.5,
76
+ ):
77
+ super().__init__(logdist=logdist)
78
+ self.thickness_mask = thickness_mask
79
+ self.roughness_mask = roughness_mask
80
+ self.max_thickness_share = max_thickness_share
81
+
82
+ def sample(self, batch_size: int,
83
+ total_min_bounds: Tensor,
84
+ total_max_bounds: Tensor,
85
+ total_min_delta: Tensor,
86
+ total_max_delta: Tensor,
87
+ ):
88
+ """
89
+ Args:
90
+ batch_size (int): the batch size
91
+ total_min_bounds (Tensor): mimimum values of the parameters
92
+ total_max_bounds (Tensor): maximum values of the parameters
93
+ total_min_delta (Tensor): minimum widths of the subprior intervals
94
+ total_max_delta (Tensor): maximum widths of the subprior intervals
95
+
96
+ Returns:
97
+ tuple(Tensor): samples the values of the parameters and their prior bounds *(params, min_bounds, max_bounds)*, the roughnesses being constrained. The widths **W** of the subprior interval are sampled first, then the centers **C** of the subprior interval, such that the prior bounds are **C** - **W** / 2 and **C** + **W** / 2, then the parameters are sampled from [**C** - **W** / 2, **C** + **W** / 2] )
98
+ """
99
+ device = total_min_bounds.device
100
+ return constrained_roughness_sampler(
101
+ batch_size,
102
+ total_min_bounds,
103
+ total_max_bounds,
104
+ total_min_delta,
105
+ total_max_delta,
106
+ thickness_mask=self.thickness_mask.to(device),
107
+ roughness_mask=self.roughness_mask.to(device),
108
+ widths_sampler_func=self.widths_sampler_func,
109
+ coef=self.max_thickness_share,
110
+ )
111
+
112
+ class ConstrainedRoughnessAndImgSldSamplerStrategy(BasicSamplerStrategy):
113
+ """Sampler strategy where the roughnesses are constrained not to exceed a fraction of the two neighboring thicknesses, and the imaginary slds are constrained not to exceed a fraction of the real slds
114
+
115
+ Args:
116
+ thickness_mask (Tensor): indices in the tensors which correspond to thicknesses
117
+ roughness_mask (Tensor): indices in the tensors which correspond to roughnesses
118
+ sld_mask (Tensor): indices in the tensors which correspond to real slds
119
+ isld_mask (Tensor): indices in the tensors which correspond to imaginary slds
120
+ logdist (bool, optional): if ``True`` the relative widths of the subprior intervals are sampled uniformly on a logarithmic scale instead of uniformly. Defaults to False.
121
+ max_thickness_share (float, optional): fraction of the layer thickness that the roughness should not exceed. Defaults to 0.5
122
+ max_sld_share (float, optional): fraction of the real sld that the imaginary sld should not exceed. Defaults to 0.2.
123
+ """
124
+ def __init__(self,
125
+ thickness_mask: Tensor,
126
+ roughness_mask: Tensor,
127
+ sld_mask: Tensor,
128
+ isld_mask: Tensor,
129
+ logdist: bool = False,
130
+ max_thickness_share: float = 0.5,
131
+ max_sld_share: float = 0.2,
132
+ ):
133
+ super().__init__(logdist=logdist)
134
+ self.thickness_mask = thickness_mask
135
+ self.roughness_mask = roughness_mask
136
+ self.sld_mask = sld_mask
137
+ self.isld_mask = isld_mask
138
+ self.max_thickness_share = max_thickness_share
139
+ self.max_sld_share = max_sld_share
140
+
141
+ def sample(self, batch_size: int,
142
+ total_min_bounds: Tensor,
143
+ total_max_bounds: Tensor,
144
+ total_min_delta: Tensor,
145
+ total_max_delta: Tensor,
146
+ ):
147
+ """
148
+ Args:
149
+ batch_size (int): the batch size
150
+ total_min_bounds (Tensor): mimimum values of the parameters
151
+ total_max_bounds (Tensor): maximum values of the parameters
152
+ total_min_delta (Tensor): minimum widths of the subprior intervals
153
+ total_max_delta (Tensor): maximum widths of the subprior intervals
154
+
155
+ Returns:
156
+ tuple(Tensor): samples the values of the parameters and their prior bounds *(params, min_bounds, max_bounds)*, the roughnesses and imaginary slds being constrained. The widths **W** of the subprior interval are sampled first, then the centers **C** of the subprior interval, such that the prior bounds are **C** - **W** /2 and **C** + **W** / 2, then the parameters are sampled from [**C** - **W** / 2, **C** + **W** / 2] )
157
+ """
158
+ device = total_min_bounds.device
159
+ return constrained_roughness_and_isld_sampler(
160
+ batch_size,
161
+ total_min_bounds,
162
+ total_max_bounds,
163
+ total_min_delta,
164
+ total_max_delta,
165
+ thickness_mask=self.thickness_mask.to(device),
166
+ roughness_mask=self.roughness_mask.to(device),
167
+ sld_mask=self.sld_mask.to(device),
168
+ isld_mask=self.isld_mask.to(device),
169
+ widths_sampler_func=self.widths_sampler_func,
170
+ coef_roughness=self.max_thickness_share,
171
+ coef_isld=self.max_sld_share,
172
+ )
173
+
174
+ def basic_sampler(
175
+ batch_size: int,
176
+ total_min_bounds: Tensor,
177
+ total_max_bounds: Tensor,
178
+ total_min_delta: Tensor,
179
+ total_max_delta: Tensor,
180
+ widths_sampler_func,
181
+ ):
182
+
183
+ delta_vector = total_max_bounds - total_min_bounds
184
+
185
+ prior_widths = widths_sampler_func(
186
+ total_min_delta, total_max_delta,
187
+ batch_size, delta_vector.shape[1],
188
+ device=total_min_bounds.device, dtype=total_min_bounds.dtype
189
+ )
190
+
191
+ prior_centers = uniform_sampler(
192
+ total_min_bounds + prior_widths / 2, total_max_bounds - prior_widths / 2,
193
+ *prior_widths.shape,
194
+ device=total_min_bounds.device, dtype=total_min_bounds.dtype
195
+ )
196
+
197
+ min_bounds, max_bounds = prior_centers - prior_widths / 2, prior_centers + prior_widths / 2
198
+
199
+ params = torch.rand(
200
+ *min_bounds.shape,
201
+ device=min_bounds.device,
202
+ dtype=min_bounds.dtype
203
+ ) * (max_bounds - min_bounds) + min_bounds
204
+
205
+ return params, min_bounds, max_bounds
206
+
207
+
208
+ def constrained_roughness_sampler(
209
+ batch_size: int,
210
+ total_min_bounds: Tensor,
211
+ total_max_bounds: Tensor,
212
+ total_min_delta: Tensor,
213
+ total_max_delta: Tensor,
214
+ thickness_mask: Tensor,
215
+ roughness_mask: Tensor,
216
+ widths_sampler_func,
217
+ coef: float = 0.5,
218
+ ):
219
+ params, min_bounds, max_bounds = basic_sampler(
220
+ batch_size, total_min_bounds, total_max_bounds, total_min_delta, total_max_delta,
221
+ widths_sampler_func=widths_sampler_func,
222
+ )
223
+
224
+ max_roughness = torch.minimum(
225
+ get_max_allowed_roughness(thicknesses=params[..., thickness_mask], coef=coef),
226
+ total_max_bounds[..., roughness_mask]
227
+ )
228
+ min_roughness = total_min_bounds[..., roughness_mask]
229
+
230
+ assert torch.all(min_roughness <= max_roughness)
231
+
232
+ min_roughness_delta = total_min_delta[..., roughness_mask]
233
+ max_roughness_delta = torch.minimum(total_max_delta[..., roughness_mask], max_roughness - min_roughness)
234
+
235
+ roughnesses, min_r_bounds, max_r_bounds = basic_sampler(
236
+ batch_size, min_roughness, max_roughness,
237
+ min_roughness_delta, max_roughness_delta,
238
+ widths_sampler_func=widths_sampler_func
239
+ )
240
+
241
+ min_bounds[..., roughness_mask], max_bounds[..., roughness_mask] = min_r_bounds, max_r_bounds
242
+ params[..., roughness_mask] = roughnesses
243
+
244
+ return params, min_bounds, max_bounds
245
+
246
+ def constrained_roughness_and_isld_sampler(
247
+ batch_size: int,
248
+ total_min_bounds: Tensor,
249
+ total_max_bounds: Tensor,
250
+ total_min_delta: Tensor,
251
+ total_max_delta: Tensor,
252
+ thickness_mask: Tensor,
253
+ roughness_mask: Tensor,
254
+ sld_mask: Tensor,
255
+ isld_mask: Tensor,
256
+ widths_sampler_func,
257
+ coef_roughness: float = 0.5,
258
+ coef_isld: float = 0.2,
259
+ ):
260
+ params, min_bounds, max_bounds = basic_sampler(
261
+ batch_size, total_min_bounds, total_max_bounds, total_min_delta, total_max_delta,
262
+ widths_sampler_func=widths_sampler_func,
263
+ )
264
+
265
+ max_roughness = torch.minimum(
266
+ get_max_allowed_roughness(thicknesses=params[..., thickness_mask], coef=coef_roughness),
267
+ total_max_bounds[..., roughness_mask]
268
+ )
269
+ min_roughness = total_min_bounds[..., roughness_mask]
270
+
271
+ assert torch.all(min_roughness <= max_roughness)
272
+
273
+ min_roughness_delta = total_min_delta[..., roughness_mask]
274
+ max_roughness_delta = torch.minimum(total_max_delta[..., roughness_mask], max_roughness - min_roughness)
275
+
276
+ roughnesses, min_r_bounds, max_r_bounds = basic_sampler(
277
+ batch_size, min_roughness, max_roughness,
278
+ min_roughness_delta, max_roughness_delta,
279
+ widths_sampler_func=widths_sampler_func
280
+ )
281
+
282
+ min_bounds[..., roughness_mask], max_bounds[..., roughness_mask] = min_r_bounds, max_r_bounds
283
+ params[..., roughness_mask] = roughnesses
284
+
285
+ max_isld = torch.minimum(
286
+ params[..., sld_mask] * coef_isld,
287
+ total_max_bounds[..., isld_mask]
288
+ )
289
+ min_isld = total_min_bounds[..., isld_mask]
290
+
291
+ assert torch.all(min_isld <= max_isld)
292
+
293
+ min_isld_delta = total_min_delta[..., isld_mask]
294
+ max_isld_delta = torch.minimum(total_max_delta[..., isld_mask], max_isld - min_isld)
295
+
296
+ islds, min_isld_bounds, max_isld_bounds = basic_sampler(
297
+ batch_size, min_isld, max_isld,
298
+ min_isld_delta, max_isld_delta,
299
+ widths_sampler_func=widths_sampler_func
300
+ )
301
+
302
+ min_bounds[..., isld_mask], max_bounds[..., isld_mask] = min_isld_bounds, max_isld_bounds
303
+ params[..., isld_mask] = islds
304
+
305
+
306
+ return params, min_bounds, max_bounds
@@ -0,0 +1,65 @@
1
+ from typing import Tuple
2
+
3
+ import torch
4
+ from torch import Tensor
5
+
6
+
7
+ class ScalerMixin:
8
+ """Provides functionality to multiple inheritance classes for scaling the parameters to a specified range and restoring them to the original range."""
9
+ @staticmethod
10
+ def _get_delta_vector(min_vector: Tensor, max_vector: Tensor):
11
+ delta_vector = max_vector - min_vector
12
+ delta_vector[delta_vector == 0.] = 1.
13
+ return delta_vector
14
+
15
+ def _scale(self, params_t: Tensor, min_vector: Tensor, max_vector: Tensor):
16
+ """scale the parameters to a specific range
17
+ Args:
18
+ params_t (Tensor): the values of the parameters
19
+ min_vector (Tensor): minimum possible values of each parameter
20
+ max_vector (Tensor): maximum possible values of each parameter
21
+
22
+ Returns:
23
+ Tensor: the scaled parameters
24
+ """
25
+ if params_t.dim() == 2:
26
+ min_vector = torch.atleast_2d(min_vector)
27
+ max_vector = torch.atleast_2d(max_vector)
28
+
29
+ delta_vector = max_vector - min_vector
30
+ delta_vector[delta_vector == 0.] = 1.
31
+ scaled_params = (
32
+ params_t - min_vector
33
+ ) / self._get_delta_vector(min_vector, max_vector) * self._length + self._bias
34
+ return scaled_params
35
+
36
+ def _restore(self, scaled_params: Tensor, min_vector: Tensor, max_vector: Tensor):
37
+ """restores the parameters to their original range
38
+ Args:
39
+ scaled_params: (Tensor): the scaled parameters
40
+ min_vector (Tensor): minimum possible values of each parameter
41
+ max_vector (Tensor): maximum possible values of each parameter
42
+
43
+ Returns:
44
+ Tensor: the restored parameters
45
+ """
46
+ if scaled_params.dim() == 2:
47
+ min_vector = torch.atleast_2d(min_vector)
48
+ max_vector = torch.atleast_2d(max_vector)
49
+
50
+ params_t = (
51
+ scaled_params - self._bias
52
+ ) / self._length * self._get_delta_vector(min_vector, max_vector) + min_vector
53
+ return params_t
54
+
55
+ @property
56
+ def scaled_range(self) -> Tuple[float, float]:
57
+ return self._scaled_range
58
+
59
+ @scaled_range.setter
60
+ def scaled_range(self, scaled_range: Tuple[float, float]):
61
+ """sets the range used for scaling the parameters"""
62
+ self._scaled_range = scaled_range
63
+ self._length = scaled_range[1] - scaled_range[0]
64
+ self._init_bias = (scaled_range[0] + scaled_range[1]) / 2
65
+ self._bias = (self._init_bias - 0.5 * self._length)