Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ascale parameter #341

Merged
merged 20 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*.nxs
*.zip
**/processed/*
**/sed_config.yaml

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Single-Event DataFrame (SED) documentation
tutorial/3_metadata_collection_and_export_to_NeXus
tutorial/4_hextof_workflow.ipynb
tutorial/6_binning_with_time-stamped_data
tutorial/7_correcting_orthorhombic_symmetry
tutorial/8_jittering_tutorial

.. toctree::
Expand Down
4 changes: 2 additions & 2 deletions sed/calibrator/energy.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def calibrate(
binning = kwds.pop("binning", self.binning)

if method == "lmfit":
self.calibration = fit_energy_calibation(
self.calibration = fit_energy_calibration(
landmarks,
sign * biases,
binwidth,
Expand Down Expand Up @@ -2085,7 +2085,7 @@ def peakdetect1d(
return (np.asarray(max_peaks), np.asarray(min_peaks))


def fit_energy_calibation(
def fit_energy_calibration(
pos: Union[List[float], np.ndarray],
vals: Union[List[float], np.ndarray],
binwidth: float,
Expand Down
37 changes: 35 additions & 2 deletions sed/calibrator/momentum.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,10 @@ def add_features(
Direction for ordering the points. Defaults to "ccw".
symscores (bool, optional):
Option to calculate symmetry scores. Defaults to False.
rotsym (int, optional): Rotational symmetry of the data. Defaults to 6.
**kwds: Keyword arguments.

- **symtype** (str): Type of symmetry scores to calculte
if symscores is True.
if symscores is True. Defaults to "rotation".

Raises:
ValueError: Raised if the number of points does not match the rotsym.
Expand Down Expand Up @@ -601,6 +600,7 @@ def spline_warp_estimate(
use_center: bool = None,
fixed_center: bool = True,
interp_order: int = 1,
ascale: Union[float, list, tuple, np.ndarray] = None,
verbose: bool = True,
**kwds,
) -> np.ndarray:
Expand All @@ -618,6 +618,13 @@ def spline_warp_estimate(
interp_order (int, optional):
Order of interpolation (see ``scipy.ndimage.map_coordinates()``).
Defaults to 1.
ascale: (Union[float, np.ndarray], optional): Scale parameter determining a realtive
scale for each symmetry feature. If provided as single float, rotsym has to be 4.
This parameter describes the relative scaling between the two orthogonal symmetry
directions (for an orthorhombic system). This requires the correction points to be
located along the principal axes (X/Y points of the Brillouin zone). Otherwise, an
array with ``rotsym`` elements is expected, containing relative scales for each
feature. Defaults to an array of equal scales.
verbose (bool, optional): Option to report the used landmarks for correction.
Defaults to True.
**kwds: keyword arguments:
Expand All @@ -644,6 +651,7 @@ def spline_warp_estimate(
if self.pouter is not None:
self.pouter_ord = po.pointset_order(self.pouter)
self.correction["creation_date"] = datetime.now().timestamp()
self.correction["creation_date"] = datetime.now().timestamp()
else:
try:
features = np.asarray(
Expand All @@ -653,6 +661,9 @@ def spline_warp_estimate(
include_center = self.correction["include_center"]
if not include_center and len(features) > rotsym:
features = features[:rotsym, :]
ascale = self.correction.get("ascale", None)
if ascale is not None:
ascale = np.asarray(ascale)

if verbose:
if "creation_date" in self.correction:
Expand Down Expand Up @@ -680,6 +691,27 @@ def spline_warp_estimate(
else:
self.correction["creation_date"] = datetime.now().timestamp()

if ascale is not None:
if isinstance(ascale, (int, float, np.floating, np.integer)):
if self.rotsym != 4:
raise ValueError(
"Providing ascale as scalar number is only valid for 'rotsym'==4.",
)
self.ascale = np.array([1.0, ascale, 1.0, ascale])
elif isinstance(ascale, (tuple, list, np.ndarray)):
if len(ascale) != len(self.ascale):
raise ValueError(
f"ascale needs to be of length 'rotsym', but has length {len(ascale)}.",
)
self.ascale = np.asarray(ascale)
else:
raise TypeError(
(
"ascale needs to be a single number or a list/tuple/np.ndarray of length ",
f"'rotsym' ({self.rotsym})!",
),
)

if use_center is None:
try:
use_center = self.correction["use_center"]
Expand Down Expand Up @@ -753,6 +785,7 @@ def spline_warp_estimate(
)
else:
self.correction["feature_points"] = self.pouter_ord
self.correction["ascale"] = self.ascale

if self.slice is not None:
self.slice_corrected = corrected_image
Expand Down
2 changes: 1 addition & 1 deletion sed/core/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ def save_splinewarp(
continue
if key in ["use_center", "rotation_symmetry"]:
correction[key] = value
elif key == "center_point":
elif key in ["center_point", "ascale"]:
correction[key] = [float(i) for i in value]
elif key in ["outer_points", "feature_points"]:
correction[key] = []
Expand Down
41 changes: 41 additions & 0 deletions tests/calibrator/test_momentum.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,47 @@ def test_splinewarp(include_center: bool) -> None:
assert len(mc.ptargs) == len(mc.prefs)


def test_ascale() -> None:
"""Test the generation of the splinewarp etimate with ascale parameter."""
config = parse_config(
config={"core": {"loader": "mpes"}},
folder_config={},
user_config={},
system_config={},
)
mc = MomentumCorrector(config=config)
mc.load_data(
data=momentum_map,
bin_ranges=[(-256, 1792), (-256, 1792)],
)
features = np.array(
[
[203.2, 341.96],
[299.16, 345.32],
[350.25, 243.70],
[304.38, 149.88],
[199.52, 152.48],
[154.28, 242.27],
[248.29, 248.62],
],
)
mc.add_features(features=features, rotsym=6)
with pytest.raises(ValueError):
mc.spline_warp_estimate(ascale=1.3)
with pytest.raises(ValueError):
mc.spline_warp_estimate(ascale=[1.3, 1, 1.3, 1])
with pytest.raises(TypeError):
mc.spline_warp_estimate(ascale="invalid type") # type:ignore
mc.spline_warp_estimate(ascale=[1.3, 1, 1.3, 1, 1.3, 1])
assert mc.cdeform_field.shape == mc.rdeform_field.shape == mc.image.shape
assert len(mc.ptargs) == len(mc.prefs)
# test single value case
with pytest.raises(ValueError):
mc.add_features(features=features, rotsym=4)
mc.add_features(features=features[:5, :], rotsym=4)
mc.spline_warp_estimate(ascale=1.3)


def test_pose_correction() -> None:
"""Test the adjustment of the pose correction."""
config = parse_config(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"# The Scan directory\n",
"fdir = data_path + '/Scan049_1'\n",
"# create sed processor using the config file:\n",
"sp = sed.SedProcessor(folder=fdir, config=\"../sed/config/mpes_example_config.yaml\")"
"sp = sed.SedProcessor(folder=fdir, config=\"../sed/config/mpes_example_config.yaml\", verbose=True)"
]
},
{
Expand Down Expand Up @@ -113,7 +113,7 @@
"# axes = ['X', 'Y', 't', 'ADC']\n",
"# bins = [100, 100, 100, 100]\n",
"# ranges = [(0, 1800), (0, 1800), (130000, 140000), (0, 9000)]\n",
"# sp.viewEventHistogram(dfpid=1, axes=axes, bins=bins, ranges=ranges)\n",
"# sp.view_event_histogram(dfpid=1, axes=axes, bins=bins, ranges=ranges)\n",
"sp.view_event_histogram(dfpid=2)"
]
},
Expand Down Expand Up @@ -162,7 +162,6 @@
"#sp.define_features(features=features, rotation_symmetry=6, include_center=True, apply=True)\n",
"# Manual selection: Use a GUI tool to select peaks:\n",
"#sp.define_features(rotation_symmetry=6, include_center=True)\n",
"#sp.generate_splinewarp(rotation_symmetry=6, include_center=True, fwhm=10, sigma=12, sigma_radius=4)\n",
"# Autodetect: Uses the DAOStarFinder routine to locate maxima.\n",
"# Parameters are:\n",
"# fwhm: Full-width at half maximum of peaks.\n",
Expand Down Expand Up @@ -278,7 +277,7 @@
"point_a = [308, 345]\n",
"sp.calibrate_momentum_axes(point_a=point_a, k_distance = k_distance, apply=True)\n",
"#point_b = [247, 249]\n",
"#sp.calibrate_momentum_axes(point_a=point_a, point_b = point_b, k_coord_a = [.5, 1.1], k_coord_b = [1.3, 0], equiscale=False"
"#sp.calibrate_momentum_axes(point_a=point_a, point_b = point_b, k_coord_a = [.5, 1.1], k_coord_b = [0, 0], equiscale=False)"
]
},
{
Expand Down Expand Up @@ -464,7 +463,7 @@
"metadata": {},
"source": [
"#### 3. Step:\n",
"Next, the detected peak positions and bias voltages are used to determine the calibration function. This can be either done by fitting the functional form d^2/(t-t0)^2 via lmfit (\"lmfit\"), or using a polynomial approxiamtion (\"lstsq\" or \"lsqr\"). Here, one can also define a reference id, and a reference energy. Those define the absolute energy position of the feature used for calibration in the \"reference\" trace, at the bias voltage where the final measurement has been performed. The energy scale can be either \"kientic\" (decreasing energy with increasing TOF), or \"binding\" (increasing energy with increasing TOF).\n",
"Next, the detected peak positions and bias voltages are used to determine the calibration function. This can be either done by fitting the functional form d^2/(t-t0)^2 via lmfit (\"lmfit\"), or using a polynomial approxiamtion (\"lstsq\" or \"lsqr\"). Here, one can also define a reference id, and a reference energy. Those define the absolute energy position of the feature used for calibration in the \"reference\" trace, at the bias voltage where the final measurement has been performed. The energy scale can be either \"kinetic\" (decreasing energy with increasing TOF), or \"binding\" (increasing energy with increasing TOF).\n",
"\n",
"After calculating the calibration, all traces corrected with the calibration are plotted ontop of each other, the calibration function together with the extracted features is plotted."
]
Expand All @@ -481,7 +480,17 @@
"refid=4\n",
"Eref=-0.5\n",
"# the lmfit method uses a fit of (d/(t-t0))**2 to determine the energy calibration\n",
"sp.calibrate_energy_axis(ref_energy=Eref, ref_id=refid, energy_scale=\"kinetic\", method=\"lmfit\")"
"# limits and starting values for the fitting parameters can be provided as dictionaries\n",
"sp.calibrate_energy_axis(\n",
" ref_id=refid,\n",
" ref_energy=Eref,\n",
" method=\"lmfit\",\n",
" energy_scale='kinetic',\n",
" d={'value':1.0,'min': .7, 'max':1.2, 'vary':True},\n",
" t0={'value':8e-7, 'min': 1e-7, 'max': 1e-6, 'vary':True},\n",
" E0={'value': 0., 'min': -100, 'max': 0, 'vary': True},\n",
" verbose=True,\n",
")"
]
},
{
Expand Down
Loading