reflectorch 1.3.0__py3-none-any.whl → 1.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 reflectorch might be problematic. Click here for more details.
- reflectorch/__init__.py +17 -17
- reflectorch/data_generation/__init__.py +128 -126
- reflectorch/data_generation/dataset.py +210 -210
- reflectorch/data_generation/likelihoods.py +80 -80
- reflectorch/data_generation/noise.py +470 -470
- reflectorch/data_generation/priors/__init__.py +60 -60
- reflectorch/data_generation/priors/base.py +55 -55
- reflectorch/data_generation/priors/exp_subprior_sampler.py +298 -298
- reflectorch/data_generation/priors/independent_priors.py +195 -195
- reflectorch/data_generation/priors/multilayer_models.py +311 -311
- reflectorch/data_generation/priors/multilayer_structures.py +104 -104
- reflectorch/data_generation/priors/no_constraints.py +206 -206
- reflectorch/data_generation/priors/parametric_models.py +841 -841
- reflectorch/data_generation/priors/parametric_subpriors.py +369 -369
- reflectorch/data_generation/priors/params.py +252 -252
- reflectorch/data_generation/priors/sampler_strategies.py +369 -369
- reflectorch/data_generation/priors/scaler_mixin.py +65 -65
- reflectorch/data_generation/priors/subprior_sampler.py +371 -371
- reflectorch/data_generation/priors/utils.py +118 -118
- reflectorch/data_generation/process_data.py +41 -41
- reflectorch/data_generation/q_generator.py +280 -246
- reflectorch/data_generation/reflectivity/__init__.py +102 -102
- reflectorch/data_generation/reflectivity/abeles.py +97 -97
- reflectorch/data_generation/reflectivity/kinematical.py +70 -70
- reflectorch/data_generation/reflectivity/memory_eff.py +105 -105
- reflectorch/data_generation/reflectivity/numpy_implementations.py +120 -120
- reflectorch/data_generation/reflectivity/smearing.py +138 -138
- reflectorch/data_generation/reflectivity/smearing_pointwise.py +109 -109
- reflectorch/data_generation/scale_curves.py +112 -112
- reflectorch/data_generation/smearing.py +98 -98
- reflectorch/data_generation/utils.py +223 -222
- reflectorch/extensions/jupyter/__init__.py +11 -6
- reflectorch/extensions/jupyter/api.py +85 -0
- reflectorch/extensions/jupyter/callbacks.py +34 -34
- reflectorch/extensions/jupyter/components.py +758 -0
- reflectorch/extensions/jupyter/custom_select.py +268 -0
- reflectorch/extensions/jupyter/log_widget.py +241 -0
- reflectorch/extensions/jupyter/model_selection.py +495 -0
- reflectorch/extensions/jupyter/plotly_plot_manager.py +329 -0
- reflectorch/extensions/jupyter/widget.py +625 -0
- reflectorch/extensions/matplotlib/__init__.py +5 -5
- reflectorch/extensions/matplotlib/losses.py +32 -32
- reflectorch/extensions/refnx/refnx_conversion.py +76 -76
- reflectorch/inference/__init__.py +28 -24
- reflectorch/inference/inference_model.py +847 -851
- reflectorch/inference/input_interface.py +239 -0
- reflectorch/inference/loading_data.py +37 -0
- reflectorch/inference/multilayer_fitter.py +171 -171
- reflectorch/inference/multilayer_inference_model.py +193 -193
- reflectorch/inference/plotting.py +524 -98
- reflectorch/inference/preprocess_exp/__init__.py +6 -6
- reflectorch/inference/preprocess_exp/attenuation.py +36 -36
- reflectorch/inference/preprocess_exp/cut_with_q_ratio.py +31 -31
- reflectorch/inference/preprocess_exp/footprint.py +81 -81
- reflectorch/inference/preprocess_exp/interpolation.py +19 -16
- reflectorch/inference/preprocess_exp/normalize.py +21 -21
- reflectorch/inference/preprocess_exp/preprocess.py +121 -121
- reflectorch/inference/query_matcher.py +81 -81
- reflectorch/inference/record_time.py +43 -43
- reflectorch/inference/sampler_solution.py +56 -56
- reflectorch/inference/scipy_fitter.py +272 -248
- reflectorch/inference/torch_fitter.py +87 -87
- reflectorch/ml/__init__.py +32 -32
- reflectorch/ml/basic_trainer.py +292 -292
- reflectorch/ml/callbacks.py +80 -80
- reflectorch/ml/dataloaders.py +26 -26
- reflectorch/ml/loggers.py +55 -55
- reflectorch/ml/schedulers.py +355 -355
- reflectorch/ml/trainers.py +200 -191
- reflectorch/ml/utils.py +2 -2
- reflectorch/models/__init__.py +15 -14
- reflectorch/models/activations.py +50 -50
- reflectorch/models/encoders/__init__.py +19 -17
- reflectorch/models/encoders/conv_encoder.py +218 -218
- reflectorch/models/encoders/conv_res_net.py +115 -115
- reflectorch/models/encoders/fno.py +133 -133
- reflectorch/models/encoders/integral_kernel_embedding.py +390 -0
- reflectorch/models/networks/__init__.py +14 -14
- reflectorch/models/networks/mlp_networks.py +434 -428
- reflectorch/models/networks/residual_net.py +156 -156
- reflectorch/paths.py +29 -27
- reflectorch/runs/__init__.py +31 -31
- reflectorch/runs/config.py +25 -25
- reflectorch/runs/slurm_utils.py +93 -93
- reflectorch/runs/train.py +78 -78
- reflectorch/runs/utils.py +404 -401
- reflectorch/test_config.py +4 -4
- reflectorch/train.py +4 -4
- reflectorch/train_on_cluster.py +4 -4
- reflectorch/utils.py +98 -68
- {reflectorch-1.3.0.dist-info → reflectorch-1.5.0.dist-info}/METADATA +129 -125
- reflectorch-1.5.0.dist-info/RECORD +96 -0
- {reflectorch-1.3.0.dist-info → reflectorch-1.5.0.dist-info}/WHEEL +1 -1
- {reflectorch-1.3.0.dist-info → reflectorch-1.5.0.dist-info}/licenses/LICENSE.txt +20 -20
- reflectorch-1.3.0.dist-info/RECORD +0 -86
- {reflectorch-1.3.0.dist-info → reflectorch-1.5.0.dist-info}/top_level.txt +0 -0
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
import torch
|
|
4
|
-
from torch import Tensor
|
|
5
|
-
|
|
6
|
-
from reflectorch.data_generation.reflectivity.abeles import abeles_compiled, abeles
|
|
7
|
-
from reflectorch.data_generation.reflectivity.memory_eff import abeles_memory_eff
|
|
8
|
-
from reflectorch.data_generation.reflectivity.numpy_implementations import (
|
|
9
|
-
kinematical_approximation_np,
|
|
10
|
-
abeles_np,
|
|
11
|
-
)
|
|
12
|
-
from reflectorch.data_generation.reflectivity.smearing import abeles_constant_smearing
|
|
13
|
-
from reflectorch.data_generation.reflectivity.smearing_pointwise import abeles_pointwise_smearing
|
|
14
|
-
from reflectorch.data_generation.reflectivity.kinematical import kinematical_approximation
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def reflectivity(
|
|
18
|
-
q: Tensor,
|
|
19
|
-
thickness: Tensor,
|
|
20
|
-
roughness: Tensor,
|
|
21
|
-
sld: Tensor,
|
|
22
|
-
dq: Tensor = None,
|
|
23
|
-
gauss_num: int = 51,
|
|
24
|
-
constant_dq: bool = False,
|
|
25
|
-
log: bool = False,
|
|
26
|
-
q_shift: Tensor = 0.0,
|
|
27
|
-
r_scale: Tensor = 1.0,
|
|
28
|
-
background: Tensor = 0.0,
|
|
29
|
-
solvent_vf = None,
|
|
30
|
-
solvent_mode = 'fronting',
|
|
31
|
-
abeles_func = None,
|
|
32
|
-
**abeles_kwargs
|
|
33
|
-
):
|
|
34
|
-
"""Function which computes the reflectivity curves from thin film parameters.
|
|
35
|
-
By default it uses the fast implementation of the Abeles matrix formalism.
|
|
36
|
-
|
|
37
|
-
Args:
|
|
38
|
-
q (Tensor): tensor of momentum transfer (q) values with shape [batch_size, n_points] or [n_points]
|
|
39
|
-
thickness (Tensor): tensor containing the layer thicknesses (ordered from top to bottom) with shape [batch_size, n_layers]
|
|
40
|
-
roughness (Tensor): tensor containing the interlayer roughnesses (ordered from top to bottom) with shape [batch_size, n_layers + 1]
|
|
41
|
-
sld (Tensor): tensor containing the layer SLDs (real or complex; ordered from top to bottom) with shape
|
|
42
|
-
[batch_size, n_layers + 1] (excluding ambient SLD which is assumed to be 0) or [batch_size, n_layers + 2] (including ambient SLD; only for the default ``abeles_func='abeles'``)
|
|
43
|
-
dq (Tensor, optional): tensor of resolutions used for curve smearing with shape [batch_size, 1].
|
|
44
|
-
Either dq if ``constant_dq`` is ``True`` or dq/q if ``constant_dq`` is ``False``. Defaults to None.
|
|
45
|
-
gauss_num (int, optional): the number of gaussians for curve smearing. Defaults to 51.
|
|
46
|
-
constant_dq (bool, optional): if ``True`` the smearing is constant (constant dq at each point in the curve)
|
|
47
|
-
otherwise the smearing is linear (constant dq/q at each point in the curve). Defaults to False.
|
|
48
|
-
log (bool, optional): if True the base 10 logarithm of the reflectivity curves is returned. Defaults to False.
|
|
49
|
-
q_shift (float or Tensor, optional): misalignment in q.
|
|
50
|
-
r_scale (float or Tensor, optional): normalization factor (scales reflectivity).
|
|
51
|
-
background (float or Tensor, optional): background intensity.
|
|
52
|
-
abeles_func (Callable, optional): a function implementing the simulation of the reflectivity curves, if different than the default Abeles matrix implementation ('abeles'). Defaults to None.
|
|
53
|
-
abeles_kwargs: Additional arguments specific to the chosen `abeles_func`.
|
|
54
|
-
Returns:
|
|
55
|
-
Tensor: the computed reflectivity curves
|
|
56
|
-
"""
|
|
57
|
-
abeles_func = abeles_func or abeles
|
|
58
|
-
q = torch.atleast_2d(q) + q_shift
|
|
59
|
-
q = torch.clamp(q, min=0.0)
|
|
60
|
-
|
|
61
|
-
if solvent_vf is not None:
|
|
62
|
-
num_layers = thickness.shape[-1]
|
|
63
|
-
if solvent_mode == 'fronting':
|
|
64
|
-
assert sld.shape[-1] == num_layers + 2
|
|
65
|
-
assert solvent_vf.shape[-1] == num_layers
|
|
66
|
-
solvent_sld = sld[..., [0]]
|
|
67
|
-
idx = slice(1, num_layers)
|
|
68
|
-
sld[..., idx] = solvent_vf * solvent_sld + (1.0 - solvent_vf) * sld[..., idx]
|
|
69
|
-
elif solvent_mode == 'backing':
|
|
70
|
-
solvent_sld = sld[..., [-1]]
|
|
71
|
-
idx = slice(1, num_layers) if sld.shape[-1] == num_layers + 2 else slice(0, num_layers)
|
|
72
|
-
sld[..., idx] = solvent_vf * solvent_sld + (1.0 - solvent_vf) * sld[..., idx]
|
|
73
|
-
else:
|
|
74
|
-
raise NotImplementedError
|
|
75
|
-
|
|
76
|
-
if dq is None:
|
|
77
|
-
reflectivity_curves = abeles_func(q, thickness, roughness, sld, **abeles_kwargs)
|
|
78
|
-
else:
|
|
79
|
-
if dq.shape[-1] > 1:
|
|
80
|
-
reflectivity_curves = abeles_pointwise_smearing(
|
|
81
|
-
q=q, dq=dq, thickness=thickness, roughness=roughness, sld=sld,
|
|
82
|
-
abeles_func=abeles_func, gauss_num=gauss_num,
|
|
83
|
-
**abeles_kwargs,
|
|
84
|
-
)
|
|
85
|
-
else:
|
|
86
|
-
reflectivity_curves = abeles_constant_smearing(
|
|
87
|
-
q, thickness, roughness, sld,
|
|
88
|
-
dq=dq, gauss_num=gauss_num, constant_dq=constant_dq, abeles_func=abeles_func,
|
|
89
|
-
**abeles_kwargs,
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
if isinstance(r_scale, Tensor):
|
|
93
|
-
r_scale = r_scale.view(-1, *[1] * (reflectivity_curves.dim() - 1))
|
|
94
|
-
if isinstance(background, Tensor):
|
|
95
|
-
background = background.view(-1, *[1] * (reflectivity_curves.dim() - 1))
|
|
96
|
-
|
|
97
|
-
reflectivity_curves = reflectivity_curves * r_scale + background
|
|
98
|
-
|
|
99
|
-
if log:
|
|
100
|
-
reflectivity_curves = torch.log10(reflectivity_curves)
|
|
101
|
-
|
|
102
|
-
return reflectivity_curves
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
from torch import Tensor
|
|
5
|
+
|
|
6
|
+
from reflectorch.data_generation.reflectivity.abeles import abeles_compiled, abeles
|
|
7
|
+
from reflectorch.data_generation.reflectivity.memory_eff import abeles_memory_eff
|
|
8
|
+
from reflectorch.data_generation.reflectivity.numpy_implementations import (
|
|
9
|
+
kinematical_approximation_np,
|
|
10
|
+
abeles_np,
|
|
11
|
+
)
|
|
12
|
+
from reflectorch.data_generation.reflectivity.smearing import abeles_constant_smearing
|
|
13
|
+
from reflectorch.data_generation.reflectivity.smearing_pointwise import abeles_pointwise_smearing
|
|
14
|
+
from reflectorch.data_generation.reflectivity.kinematical import kinematical_approximation
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def reflectivity(
|
|
18
|
+
q: Tensor,
|
|
19
|
+
thickness: Tensor,
|
|
20
|
+
roughness: Tensor,
|
|
21
|
+
sld: Tensor,
|
|
22
|
+
dq: Tensor = None,
|
|
23
|
+
gauss_num: int = 51,
|
|
24
|
+
constant_dq: bool = False,
|
|
25
|
+
log: bool = False,
|
|
26
|
+
q_shift: Tensor = 0.0,
|
|
27
|
+
r_scale: Tensor = 1.0,
|
|
28
|
+
background: Tensor = 0.0,
|
|
29
|
+
solvent_vf = None,
|
|
30
|
+
solvent_mode = 'fronting',
|
|
31
|
+
abeles_func = None,
|
|
32
|
+
**abeles_kwargs
|
|
33
|
+
):
|
|
34
|
+
"""Function which computes the reflectivity curves from thin film parameters.
|
|
35
|
+
By default it uses the fast implementation of the Abeles matrix formalism.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
q (Tensor): tensor of momentum transfer (q) values with shape [batch_size, n_points] or [n_points]
|
|
39
|
+
thickness (Tensor): tensor containing the layer thicknesses (ordered from top to bottom) with shape [batch_size, n_layers]
|
|
40
|
+
roughness (Tensor): tensor containing the interlayer roughnesses (ordered from top to bottom) with shape [batch_size, n_layers + 1]
|
|
41
|
+
sld (Tensor): tensor containing the layer SLDs (real or complex; ordered from top to bottom) with shape
|
|
42
|
+
[batch_size, n_layers + 1] (excluding ambient SLD which is assumed to be 0) or [batch_size, n_layers + 2] (including ambient SLD; only for the default ``abeles_func='abeles'``)
|
|
43
|
+
dq (Tensor, optional): tensor of resolutions used for curve smearing with shape [batch_size, 1].
|
|
44
|
+
Either dq if ``constant_dq`` is ``True`` or dq/q if ``constant_dq`` is ``False``. Defaults to None.
|
|
45
|
+
gauss_num (int, optional): the number of gaussians for curve smearing. Defaults to 51.
|
|
46
|
+
constant_dq (bool, optional): if ``True`` the smearing is constant (constant dq at each point in the curve)
|
|
47
|
+
otherwise the smearing is linear (constant dq/q at each point in the curve). Defaults to False.
|
|
48
|
+
log (bool, optional): if True the base 10 logarithm of the reflectivity curves is returned. Defaults to False.
|
|
49
|
+
q_shift (float or Tensor, optional): misalignment in q.
|
|
50
|
+
r_scale (float or Tensor, optional): normalization factor (scales reflectivity).
|
|
51
|
+
background (float or Tensor, optional): background intensity.
|
|
52
|
+
abeles_func (Callable, optional): a function implementing the simulation of the reflectivity curves, if different than the default Abeles matrix implementation ('abeles'). Defaults to None.
|
|
53
|
+
abeles_kwargs: Additional arguments specific to the chosen `abeles_func`.
|
|
54
|
+
Returns:
|
|
55
|
+
Tensor: the computed reflectivity curves
|
|
56
|
+
"""
|
|
57
|
+
abeles_func = abeles_func or abeles
|
|
58
|
+
q = torch.atleast_2d(q) + q_shift
|
|
59
|
+
q = torch.clamp(q, min=0.0)
|
|
60
|
+
|
|
61
|
+
if solvent_vf is not None:
|
|
62
|
+
num_layers = thickness.shape[-1]
|
|
63
|
+
if solvent_mode == 'fronting':
|
|
64
|
+
assert sld.shape[-1] == num_layers + 2
|
|
65
|
+
assert solvent_vf.shape[-1] == num_layers
|
|
66
|
+
solvent_sld = sld[..., [0]]
|
|
67
|
+
idx = slice(1, num_layers)
|
|
68
|
+
sld[..., idx] = solvent_vf * solvent_sld + (1.0 - solvent_vf) * sld[..., idx]
|
|
69
|
+
elif solvent_mode == 'backing':
|
|
70
|
+
solvent_sld = sld[..., [-1]]
|
|
71
|
+
idx = slice(1, num_layers) if sld.shape[-1] == num_layers + 2 else slice(0, num_layers)
|
|
72
|
+
sld[..., idx] = solvent_vf * solvent_sld + (1.0 - solvent_vf) * sld[..., idx]
|
|
73
|
+
else:
|
|
74
|
+
raise NotImplementedError
|
|
75
|
+
|
|
76
|
+
if dq is None:
|
|
77
|
+
reflectivity_curves = abeles_func(q, thickness, roughness, sld, **abeles_kwargs)
|
|
78
|
+
else:
|
|
79
|
+
if dq.shape[-1] > 1:
|
|
80
|
+
reflectivity_curves = abeles_pointwise_smearing(
|
|
81
|
+
q=q, dq=dq, thickness=thickness, roughness=roughness, sld=sld,
|
|
82
|
+
abeles_func=abeles_func, gauss_num=gauss_num,
|
|
83
|
+
**abeles_kwargs,
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
reflectivity_curves = abeles_constant_smearing(
|
|
87
|
+
q, thickness, roughness, sld,
|
|
88
|
+
dq=dq, gauss_num=gauss_num, constant_dq=constant_dq, abeles_func=abeles_func,
|
|
89
|
+
**abeles_kwargs,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if isinstance(r_scale, Tensor):
|
|
93
|
+
r_scale = r_scale.view(-1, *[1] * (reflectivity_curves.dim() - 1))
|
|
94
|
+
if isinstance(background, Tensor):
|
|
95
|
+
background = background.view(-1, *[1] * (reflectivity_curves.dim() - 1))
|
|
96
|
+
|
|
97
|
+
reflectivity_curves = reflectivity_curves * r_scale + background
|
|
98
|
+
|
|
99
|
+
if log:
|
|
100
|
+
reflectivity_curves = torch.log10(reflectivity_curves)
|
|
101
|
+
|
|
102
|
+
return reflectivity_curves
|
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
import math
|
|
3
|
-
from functools import reduce
|
|
4
|
-
|
|
5
|
-
import torch
|
|
6
|
-
from torch import Tensor
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def abeles(
|
|
10
|
-
q: Tensor,
|
|
11
|
-
thickness: Tensor,
|
|
12
|
-
roughness: Tensor,
|
|
13
|
-
sld: Tensor,
|
|
14
|
-
):
|
|
15
|
-
"""Simulates reflectivity curves for SLD profiles with box model parameterization using the Abeles matrix method
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
q (Tensor): tensor of momentum transfer (q) values with shape [batch_size, n_points] or [n_points]
|
|
19
|
-
thickness (Tensor): tensor containing the layer thicknesses (ordered from top to bottom) with shape [batch_size, n_layers]
|
|
20
|
-
roughness (Tensor): tensor containing the interlayer roughnesses (ordered from top to bottom) with shape [batch_size, n_layers + 1]
|
|
21
|
-
sld (Tensor): tensor containing the layer SLDs (real or complex; ordered from top to bottom). The tensor shape should be one of the following:
|
|
22
|
-
- [batch_size, n_layers + 1]: in this case, the ambient SLD is not included but assumed to be 0
|
|
23
|
-
- [batch_size, n_layers + 2]: this shape includes the ambient SLD as the first element in the tensor
|
|
24
|
-
|
|
25
|
-
Returns:
|
|
26
|
-
Tensor: tensor containing the simulated reflectivity curves with shape [batch_size, n_points]
|
|
27
|
-
"""
|
|
28
|
-
c_dtype = torch.complex128 if q.dtype is torch.float64 else torch.complex64
|
|
29
|
-
|
|
30
|
-
batch_size, num_layers = thickness.shape
|
|
31
|
-
|
|
32
|
-
if sld.shape[-1] == num_layers + 1:
|
|
33
|
-
# add zero ambient sld
|
|
34
|
-
sld = torch.cat([torch.zeros(batch_size, 1).to(sld), sld], -1)
|
|
35
|
-
if sld.shape[-1] != num_layers + 2:
|
|
36
|
-
raise ValueError(
|
|
37
|
-
"Number of SLD values does not equal to num_layers + 2 (substrate + ambient)."
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
sld = sld[:, None]
|
|
41
|
-
|
|
42
|
-
# add zero thickness for ambient layer:
|
|
43
|
-
thickness = torch.cat([torch.zeros(batch_size, 1).to(thickness), thickness], -1)[
|
|
44
|
-
:, None
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
roughness = roughness[:, None] ** 2
|
|
48
|
-
|
|
49
|
-
sld = (sld - sld[..., :1]) * 1e-6 + 1e-36j
|
|
50
|
-
|
|
51
|
-
k_z0 = (q / 2).to(c_dtype)
|
|
52
|
-
|
|
53
|
-
if k_z0.dim() == 1:
|
|
54
|
-
k_z0.unsqueeze_(0)
|
|
55
|
-
|
|
56
|
-
if k_z0.dim() == 2:
|
|
57
|
-
k_z0.unsqueeze_(-1)
|
|
58
|
-
|
|
59
|
-
k_n = torch.sqrt(k_z0**2 - 4 * math.pi * sld)
|
|
60
|
-
|
|
61
|
-
# k_n.shape - (batch, q, layers)
|
|
62
|
-
|
|
63
|
-
k_n, k_np1 = k_n[..., :-1], k_n[..., 1:]
|
|
64
|
-
|
|
65
|
-
beta = 1j * thickness * k_n
|
|
66
|
-
|
|
67
|
-
exp_beta = torch.exp(beta)
|
|
68
|
-
exp_m_beta = torch.exp(-beta)
|
|
69
|
-
|
|
70
|
-
rn = (k_n - k_np1) / (k_n + k_np1) * torch.exp(-2 * k_n * k_np1 * roughness)
|
|
71
|
-
|
|
72
|
-
c_matrices = torch.stack(
|
|
73
|
-
[
|
|
74
|
-
torch.stack([exp_beta, rn * exp_m_beta], -1),
|
|
75
|
-
torch.stack([rn * exp_beta, exp_m_beta], -1),
|
|
76
|
-
],
|
|
77
|
-
-1,
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
c_matrices = [c.squeeze(-3) for c in c_matrices.split(1, -3)]
|
|
81
|
-
|
|
82
|
-
m = reduce(torch.matmul, c_matrices)
|
|
83
|
-
|
|
84
|
-
r = (m[..., 1, 0] / m[..., 0, 0]).abs() ** 2
|
|
85
|
-
r = torch.clamp_max_(r, 1.0)
|
|
86
|
-
|
|
87
|
-
return r
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
# @torch.jit.script # commented so far due to complex numbers issue
|
|
91
|
-
def abeles_compiled(
|
|
92
|
-
q: Tensor,
|
|
93
|
-
thickness: Tensor,
|
|
94
|
-
roughness: Tensor,
|
|
95
|
-
sld: Tensor,
|
|
96
|
-
):
|
|
97
|
-
return abeles(q, thickness, roughness, sld)
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import math
|
|
3
|
+
from functools import reduce
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
from torch import Tensor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def abeles(
|
|
10
|
+
q: Tensor,
|
|
11
|
+
thickness: Tensor,
|
|
12
|
+
roughness: Tensor,
|
|
13
|
+
sld: Tensor,
|
|
14
|
+
):
|
|
15
|
+
"""Simulates reflectivity curves for SLD profiles with box model parameterization using the Abeles matrix method
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
q (Tensor): tensor of momentum transfer (q) values with shape [batch_size, n_points] or [n_points]
|
|
19
|
+
thickness (Tensor): tensor containing the layer thicknesses (ordered from top to bottom) with shape [batch_size, n_layers]
|
|
20
|
+
roughness (Tensor): tensor containing the interlayer roughnesses (ordered from top to bottom) with shape [batch_size, n_layers + 1]
|
|
21
|
+
sld (Tensor): tensor containing the layer SLDs (real or complex; ordered from top to bottom). The tensor shape should be one of the following:
|
|
22
|
+
- [batch_size, n_layers + 1]: in this case, the ambient SLD is not included but assumed to be 0
|
|
23
|
+
- [batch_size, n_layers + 2]: this shape includes the ambient SLD as the first element in the tensor
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Tensor: tensor containing the simulated reflectivity curves with shape [batch_size, n_points]
|
|
27
|
+
"""
|
|
28
|
+
c_dtype = torch.complex128 if q.dtype is torch.float64 else torch.complex64
|
|
29
|
+
|
|
30
|
+
batch_size, num_layers = thickness.shape
|
|
31
|
+
|
|
32
|
+
if sld.shape[-1] == num_layers + 1:
|
|
33
|
+
# add zero ambient sld
|
|
34
|
+
sld = torch.cat([torch.zeros(batch_size, 1).to(sld), sld], -1)
|
|
35
|
+
if sld.shape[-1] != num_layers + 2:
|
|
36
|
+
raise ValueError(
|
|
37
|
+
"Number of SLD values does not equal to num_layers + 2 (substrate + ambient)."
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
sld = sld[:, None]
|
|
41
|
+
|
|
42
|
+
# add zero thickness for ambient layer:
|
|
43
|
+
thickness = torch.cat([torch.zeros(batch_size, 1).to(thickness), thickness], -1)[
|
|
44
|
+
:, None
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
roughness = roughness[:, None] ** 2
|
|
48
|
+
|
|
49
|
+
sld = (sld - sld[..., :1]) * 1e-6 + 1e-36j
|
|
50
|
+
|
|
51
|
+
k_z0 = (q / 2).to(c_dtype)
|
|
52
|
+
|
|
53
|
+
if k_z0.dim() == 1:
|
|
54
|
+
k_z0.unsqueeze_(0)
|
|
55
|
+
|
|
56
|
+
if k_z0.dim() == 2:
|
|
57
|
+
k_z0.unsqueeze_(-1)
|
|
58
|
+
|
|
59
|
+
k_n = torch.sqrt(k_z0**2 - 4 * math.pi * sld)
|
|
60
|
+
|
|
61
|
+
# k_n.shape - (batch, q, layers)
|
|
62
|
+
|
|
63
|
+
k_n, k_np1 = k_n[..., :-1], k_n[..., 1:]
|
|
64
|
+
|
|
65
|
+
beta = 1j * thickness * k_n
|
|
66
|
+
|
|
67
|
+
exp_beta = torch.exp(beta)
|
|
68
|
+
exp_m_beta = torch.exp(-beta)
|
|
69
|
+
|
|
70
|
+
rn = (k_n - k_np1) / (k_n + k_np1) * torch.exp(-2 * k_n * k_np1 * roughness)
|
|
71
|
+
|
|
72
|
+
c_matrices = torch.stack(
|
|
73
|
+
[
|
|
74
|
+
torch.stack([exp_beta, rn * exp_m_beta], -1),
|
|
75
|
+
torch.stack([rn * exp_beta, exp_m_beta], -1),
|
|
76
|
+
],
|
|
77
|
+
-1,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
c_matrices = [c.squeeze(-3) for c in c_matrices.split(1, -3)]
|
|
81
|
+
|
|
82
|
+
m = reduce(torch.matmul, c_matrices)
|
|
83
|
+
|
|
84
|
+
r = (m[..., 1, 0] / m[..., 0, 0]).abs() ** 2
|
|
85
|
+
r = torch.clamp_max_(r, 1.0)
|
|
86
|
+
|
|
87
|
+
return r
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# @torch.jit.script # commented so far due to complex numbers issue
|
|
91
|
+
def abeles_compiled(
|
|
92
|
+
q: Tensor,
|
|
93
|
+
thickness: Tensor,
|
|
94
|
+
roughness: Tensor,
|
|
95
|
+
sld: Tensor,
|
|
96
|
+
):
|
|
97
|
+
return abeles(q, thickness, roughness, sld)
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
import torch
|
|
4
|
-
from torch import Tensor
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def kinematical_approximation(
|
|
8
|
-
q: Tensor,
|
|
9
|
-
thickness: Tensor,
|
|
10
|
-
roughness: Tensor,
|
|
11
|
-
sld: Tensor,
|
|
12
|
-
*,
|
|
13
|
-
apply_fresnel: bool = True,
|
|
14
|
-
log: bool = False,
|
|
15
|
-
):
|
|
16
|
-
"""Simulates reflectivity curves for SLD profiles with box model parameterization using the kinematical approximation
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
q (Tensor): tensor of momentum transfer (q) values with shape [batch_size, n_points] or [n_points]
|
|
20
|
-
thickness (Tensor): tensor containing the layer thicknesses (ordered from top to bottom) with shape [batch_size, n_layers]
|
|
21
|
-
roughness (Tensor): tensor containing the interlayer roughnesses (ordered from top to bottom) with shape [batch_size, n_layers + 1]
|
|
22
|
-
sld (Tensor): tensor containing the layer SLDs (real or complex; ordered from top to bottom) with shape [batch_size, n_layers + 1].
|
|
23
|
-
It includes the substrate but excludes the ambient medium which is assumed to have an SLD of 0.
|
|
24
|
-
apply_fresnel (bool, optional): whether to use the Fresnel coefficient in the computation. Defaults to ``True``.
|
|
25
|
-
log (bool, optional): if True the base 10 logarithm of the reflectivity curves is returned. Defaults to ``False``.
|
|
26
|
-
|
|
27
|
-
Returns:
|
|
28
|
-
Tensor: tensor containing the simulated reflectivity curves with shape [batch_size, n_points]
|
|
29
|
-
"""
|
|
30
|
-
c_dtype = torch.complex128 if q.dtype is torch.float64 else torch.complex64
|
|
31
|
-
|
|
32
|
-
batch_size, num_layers = thickness.shape
|
|
33
|
-
|
|
34
|
-
q = q.to(c_dtype)
|
|
35
|
-
|
|
36
|
-
if q.dim() == 1:
|
|
37
|
-
q.unsqueeze_(0)
|
|
38
|
-
|
|
39
|
-
if q.dim() == 2:
|
|
40
|
-
q.unsqueeze_(-1)
|
|
41
|
-
|
|
42
|
-
sld = sld * 1e-6 + 1e-30j
|
|
43
|
-
|
|
44
|
-
drho = torch.cat([sld[..., 0][..., None], sld[..., 1:] - sld[..., :-1]], -1)[:, None]
|
|
45
|
-
thickness = torch.cumsum(torch.cat([torch.zeros(batch_size, 1).to(thickness), thickness], -1), -1)[:, None]
|
|
46
|
-
roughness = roughness[:, None]
|
|
47
|
-
|
|
48
|
-
r = (drho * torch.exp(- (roughness * q) ** 2 / 2 + 1j * (q * thickness))).sum(-1).abs().float() ** 2
|
|
49
|
-
|
|
50
|
-
if apply_fresnel:
|
|
51
|
-
|
|
52
|
-
substrate_sld = sld[:, -1:]
|
|
53
|
-
|
|
54
|
-
rf = _get_fresnel_reflectivity(q, substrate_sld[:, None])
|
|
55
|
-
|
|
56
|
-
r = torch.clamp_max_(r * rf / substrate_sld.real ** 2, 1.)
|
|
57
|
-
|
|
58
|
-
if log:
|
|
59
|
-
r = torch.log10(r)
|
|
60
|
-
|
|
61
|
-
return r
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def _get_fresnel_reflectivity(q, substrate_slds):
|
|
65
|
-
_RE_CONST = 0.28174103675406496 # 2/sqrt(16*pi)
|
|
66
|
-
|
|
67
|
-
q_c = torch.sqrt(substrate_slds + 0j) / _RE_CONST * 2
|
|
68
|
-
q_prime = torch.sqrt(q ** 2 - q_c ** 2 + 0j)
|
|
69
|
-
r_f = ((q - q_prime) / (q + q_prime)).abs().float() ** 2
|
|
70
|
-
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
from torch import Tensor
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def kinematical_approximation(
|
|
8
|
+
q: Tensor,
|
|
9
|
+
thickness: Tensor,
|
|
10
|
+
roughness: Tensor,
|
|
11
|
+
sld: Tensor,
|
|
12
|
+
*,
|
|
13
|
+
apply_fresnel: bool = True,
|
|
14
|
+
log: bool = False,
|
|
15
|
+
):
|
|
16
|
+
"""Simulates reflectivity curves for SLD profiles with box model parameterization using the kinematical approximation
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
q (Tensor): tensor of momentum transfer (q) values with shape [batch_size, n_points] or [n_points]
|
|
20
|
+
thickness (Tensor): tensor containing the layer thicknesses (ordered from top to bottom) with shape [batch_size, n_layers]
|
|
21
|
+
roughness (Tensor): tensor containing the interlayer roughnesses (ordered from top to bottom) with shape [batch_size, n_layers + 1]
|
|
22
|
+
sld (Tensor): tensor containing the layer SLDs (real or complex; ordered from top to bottom) with shape [batch_size, n_layers + 1].
|
|
23
|
+
It includes the substrate but excludes the ambient medium which is assumed to have an SLD of 0.
|
|
24
|
+
apply_fresnel (bool, optional): whether to use the Fresnel coefficient in the computation. Defaults to ``True``.
|
|
25
|
+
log (bool, optional): if True the base 10 logarithm of the reflectivity curves is returned. Defaults to ``False``.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Tensor: tensor containing the simulated reflectivity curves with shape [batch_size, n_points]
|
|
29
|
+
"""
|
|
30
|
+
c_dtype = torch.complex128 if q.dtype is torch.float64 else torch.complex64
|
|
31
|
+
|
|
32
|
+
batch_size, num_layers = thickness.shape
|
|
33
|
+
|
|
34
|
+
q = q.to(c_dtype)
|
|
35
|
+
|
|
36
|
+
if q.dim() == 1:
|
|
37
|
+
q.unsqueeze_(0)
|
|
38
|
+
|
|
39
|
+
if q.dim() == 2:
|
|
40
|
+
q.unsqueeze_(-1)
|
|
41
|
+
|
|
42
|
+
sld = sld * 1e-6 + 1e-30j
|
|
43
|
+
|
|
44
|
+
drho = torch.cat([sld[..., 0][..., None], sld[..., 1:] - sld[..., :-1]], -1)[:, None]
|
|
45
|
+
thickness = torch.cumsum(torch.cat([torch.zeros(batch_size, 1).to(thickness), thickness], -1), -1)[:, None]
|
|
46
|
+
roughness = roughness[:, None]
|
|
47
|
+
|
|
48
|
+
r = (drho * torch.exp(- (roughness * q) ** 2 / 2 + 1j * (q * thickness))).sum(-1).abs().float() ** 2
|
|
49
|
+
|
|
50
|
+
if apply_fresnel:
|
|
51
|
+
|
|
52
|
+
substrate_sld = sld[:, -1:]
|
|
53
|
+
|
|
54
|
+
rf = _get_fresnel_reflectivity(q, substrate_sld[:, None])
|
|
55
|
+
|
|
56
|
+
r = torch.clamp_max_(r * rf / substrate_sld.real ** 2, 1.)
|
|
57
|
+
|
|
58
|
+
if log:
|
|
59
|
+
r = torch.log10(r)
|
|
60
|
+
|
|
61
|
+
return r
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _get_fresnel_reflectivity(q, substrate_slds):
|
|
65
|
+
_RE_CONST = 0.28174103675406496 # 2/sqrt(16*pi)
|
|
66
|
+
|
|
67
|
+
q_c = torch.sqrt(substrate_slds + 0j) / _RE_CONST * 2
|
|
68
|
+
q_prime = torch.sqrt(q ** 2 - q_c ** 2 + 0j)
|
|
69
|
+
r_f = ((q - q_prime) / (q + q_prime)).abs().float() ** 2
|
|
70
|
+
|
|
71
71
|
return r_f.squeeze(-1)
|