From 0c96559aea34887524b4a42c9fec64d286be360f Mon Sep 17 00:00:00 2001 From: Simon Heybrock Date: Thu, 19 Oct 2023 11:35:05 +0200 Subject: [PATCH 01/18] Begin rewrite to Sciline --- src/essreflectometry/amor/beamline.py | 6 +- src/essreflectometry/amor/conversions.py | 6 +- src/essreflectometry/amor/load.py | 22 ++-- .../reflectometry/conversions.py | 120 ++++++++++-------- src/essreflectometry/reflectometry/types.py | 53 ++++++++ 5 files changed, 136 insertions(+), 71 deletions(-) create mode 100644 src/essreflectometry/reflectometry/types.py diff --git a/src/essreflectometry/amor/beamline.py b/src/essreflectometry/amor/beamline.py index 2599c79..be4e94d 100644 --- a/src/essreflectometry/amor/beamline.py +++ b/src/essreflectometry/amor/beamline.py @@ -10,6 +10,8 @@ @log_call( instrument='amor', message='Constructing AMOR beamline from default parameters' ) +BeamlineParams = NewType('Beamline', dict) + def make_beamline( sample_rotation: sc.Variable, beam_size: sc.Variable = None, @@ -20,7 +22,7 @@ def make_beamline( chopper_phase: sc.Variable = None, chopper_1_position: sc.Variable = None, chopper_2_position: sc.Variable = None, -) -> dict: +) -> BeamlineParams: """ Amor beamline components. @@ -91,7 +93,7 @@ def make_beamline( position=chopper_1_position, ) ) - return beamline + return BeamlineParams(beamline) @log_call(instrument='amor', level='DEBUG') diff --git a/src/essreflectometry/amor/conversions.py b/src/essreflectometry/amor/conversions.py index 8623faf..3a643a2 100644 --- a/src/essreflectometry/amor/conversions.py +++ b/src/essreflectometry/amor/conversions.py @@ -1,8 +1,10 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +from typing import NewType import scipp as sc from ..reflectometry.conversions import specular_reflection as spec_relf_graph +from ..reflectometry.types import SpecularReflectionCoordTransformGraph def incident_beam( @@ -22,10 +24,10 @@ def incident_beam( return sample_position - chopper_midpoint -def specular_reflection() -> dict: +def specular_reflection() -> SpecularReflectionCoordTransformGraph: """ Generate a coordinate transformation graph for Amor reflectometry. """ graph = spec_relf_graph() graph['incident_beam'] = incident_beam - return graph + return SpecularReflectionCoordTransformGraph(graph) diff --git a/src/essreflectometry/amor/load.py b/src/essreflectometry/amor/load.py index 42f27a5..5042977 100644 --- a/src/essreflectometry/amor/load.py +++ b/src/essreflectometry/amor/load.py @@ -2,13 +2,14 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from datetime import datetime from pathlib import Path -from typing import Any, Optional, Union +from typing import Any, Optional, Union, NewType, TypeVar import scipp as sc import scippnexus as snx from ..logging import get_logger -from .beamline import make_beamline +from .beamline import make_beamline, BeamlineParams +from .types import Run, Raw, Filename def _tof_correction(data: sc.DataArray, dim: str = 'tof') -> sc.DataArray: @@ -83,19 +84,13 @@ def _load_nexus_entry(filename: Union[str, Path]) -> sc.DataGroup: return f['entry'][()] -def load( - filename: Union[str, Path], - orso: Optional[Any] = None, - beamline: Optional[dict] = None, -) -> sc.DataArray: +def load(filename: Filename[Run], beamline: BeamlineParams) -> Raw[Run]: """Load a single Amor data file. Parameters ---------- filename: Path of the file to load. - orso: - The orso object to be populated by additional information from the loaded file. beamline: A dict defining the beamline parameters. @@ -124,16 +119,15 @@ def load( ) # Add beamline parameters - beamline = make_beamline() if beamline is None else beamline for key, value in beamline.items(): data.coords[key] = value - if orso is not None: - populate_orso(orso=orso, data=full_data, filename=filename) - data.attrs['orso'] = sc.scalar(orso) + # if orso is not None: + # populate_orso(orso=orso, data=full_data, filename=filename) + # data.attrs['orso'] = sc.scalar(orso) # Perform tof correction and fold two pulses - return _tof_correction(data) + return Raw[Run](_tof_correction(data)) def populate_orso(orso: Any, data: sc.DataGroup, filename: str) -> Any: diff --git a/src/essreflectometry/reflectometry/conversions.py b/src/essreflectometry/reflectometry/conversions.py index bbabb27..169cc9e 100644 --- a/src/essreflectometry/reflectometry/conversions.py +++ b/src/essreflectometry/reflectometry/conversions.py @@ -4,6 +4,15 @@ from scipp.constants import h, m_n, pi from scippneutron._utils import elem_dtype, elem_unit from scippneutron.conversion.graph import beamline, tof +from .types import ( + ThetaBins, + WavelengthBins, + SpecularReflectionCoordTransformGraph, + ThetaData, + WavelengthData, + Run, + Raw, +) from . import orso @@ -86,7 +95,7 @@ def reflectometry_q(wavelength: sc.Variable, theta: sc.Variable) -> sc.Variable: return c * sc.sin(theta.astype(dtype, copy=False)) / wavelength -def specular_reflection() -> dict: +def specular_reflection() -> SpecularReflectionCoordTransformGraph: """ Generate a coordinate transformation graph for specular reflection reflectometry. @@ -101,12 +110,14 @@ def specular_reflection() -> dict: "theta": theta, "Q": reflectometry_q, } - return graph + return SpecularReflectionCoordTransformGraph(graph) def tof_to_wavelength( - data_array: sc.DataArray, wavelength_edges: sc.Variable = None, graph: dict = None -) -> sc.DataArray: + data_array: Raw[Run], + wavelength_edges: WavelengthBins, + graph: SpecularReflectionCoordTransformGraph, +) -> WavelengthData[Run]: """ Use :code:`transform_coords` to convert from ToF to wavelength, cutoff high and low limits for wavelength, and add necessary ORSO metadata. @@ -126,32 +137,33 @@ def tof_to_wavelength( : New data array with wavelength dimension. """ - graph = graph if graph is not None else specular_reflection() data_array_wav = data_array.transform_coords(["wavelength"], graph=graph) - if wavelength_edges is not None: - data_array_wav = data_array_wav.bin({wavelength_edges.dim: wavelength_edges}) - try: - from orsopy import fileio - - unit = data_array_wav.coords['wavelength'].unit - # This insures that when the unit is Å it is written as - # angstrom in the ORSO object. - if unit == 'angstrom': - unit = 'angstrom' - orso_measurement = data_array_wav.attrs['orso'].value.data_source.measurement - orso_measurement.instrument_settings.wavelength = fileio.base.ValueRange( - float(data_array_wav.coords['wavelength'].min().value), - float(data_array_wav.coords['wavelength'].max().value), - unit, - ) - except ImportError: - orso.not_found_warning() - return data_array_wav + data_array_wav = data_array_wav.bin({wavelength_edges.dim: wavelength_edges}) + # TODO + # try: + # from orsopy import fileio + + # unit = data_array_wav.coords['wavelength'].unit + # # This insures that when the unit is Å it is written as + # # angstrom in the ORSO object. + # if unit == 'angstrom': + # unit = 'angstrom' + # orso_measurement = data_array_wav.attrs['orso'].value.data_source.measurement + # orso_measurement.instrument_settings.wavelength = fileio.base.ValueRange( + # float(data_array_wav.coords['wavelength'].min().value), + # float(data_array_wav.coords['wavelength'].max().value), + # unit, + # ) + # except ImportError: + # orso.not_found_warning() + return WavelengthData[Run](data_array_wav) def wavelength_to_theta( - data_array: sc.DataArray, theta_edges: sc.Variable = None, graph: dict = None -) -> sc.DataArray: + data_array: WavelengthData[Run], + theta_edges: ThetaBins, + graph: SpecularReflectionCoordTransformGraph, +) -> ThetaData[Run]: """ Use :code:`transform_coords` to find the theta values for the events and potentially add ORSO metadata. @@ -171,34 +183,33 @@ def wavelength_to_theta( : New data array with theta coordinate. """ - graph = graph if graph is not None else specular_reflection() data_array_theta = data_array.transform_coords(['theta'], graph=graph) - if theta_edges is not None: - data_array_theta = data_array_theta.bin({theta_edges.dim: theta_edges}) - try: - from orsopy import fileio - - orso_measurement = data_array_theta.attrs['orso'].value.data_source.measurement - orso_measurement.instrument_settings.incident_angle = fileio.base.ValueRange( - float(data_array_theta.coords['theta'].min().value), - float(data_array_theta.coords['theta'].max().value), - data_array_theta.bins.coords['theta'].min().unit, - ) - import inspect - - # Determine if 'gravity' is in the graph and if to add the gravity correction - if any( - [ - 'gravity' in i.parameters.keys() - for i in map(inspect.signature, graph.values()) - ] - ): - data_array_theta.attrs['orso'].value.reduction.corrections += [ - 'gravity correction' - ] - except ImportError: - orso.not_found_warning() - return data_array_theta + data_array_theta = data_array_theta.bin({theta_edges.dim: theta_edges}) + # TODO + # try: + # from orsopy import fileio + + # orso_measurement = data_array_theta.attrs['orso'].value.data_source.measurement + # orso_measurement.instrument_settings.incident_angle = fileio.base.ValueRange( + # float(data_array_theta.coords['theta'].min().value), + # float(data_array_theta.coords['theta'].max().value), + # data_array_theta.bins.coords['theta'].min().unit, + # ) + # import inspect + + # # Determine if 'gravity' is in the graph and if to add the gravity correction + # if any( + # [ + # 'gravity' in i.parameters.keys() + # for i in map(inspect.signature, graph.values()) + # ] + # ): + # data_array_theta.attrs['orso'].value.reduction.corrections += [ + # 'gravity correction' + # ] + # except ImportError: + # orso.not_found_warning() + return ThetaData[Run](data_array_theta) def theta_to_q( @@ -249,3 +260,6 @@ def sum_bins(data_array: sc.DataArray): 'angular_resolution' ].max('detector_number') return data_array_summed + + +providers = [specular_reflection, tof_to_wavelength, wavelength_to_theta] diff --git a/src/essreflectometry/reflectometry/types.py b/src/essreflectometry/reflectometry/types.py new file mode 100644 index 0000000..e8da97e --- /dev/null +++ b/src/essreflectometry/reflectometry/types.py @@ -0,0 +1,53 @@ +from typing import NewType, TypeVar + +import sciline +import scipp as sc + +Reference = NewType('Reference', str) +Sample = NewType('Sample', str) +Run = TypeVar('Run', Reference, Sample) + + +class Filename(sciline.Scope[Run, str], str): + """Filename of the raw data""" + + +class Raw(sciline.Scope[Run, sc.DataArray], sc.DataArray): + """Raw data""" + + +class WavelengthData(sciline.Scope[Run, sc.DataArray], sc.DataArray): + """Raw data transformed to wavelength""" + + +class ThetaData(sciline.Scope[Run, sc.DataArray], sc.DataArray): + """Wavelength data transformed to theta""" + + +class Experiment(sciline.Scope[Run, sc.DataArray], sc.DataArray): + """Experiment data with added coordinates: + wavelength, incidence angle, and momentum transfer""" + + +class FootprintCorrected(sciline.Scope[Run, sc.DataArray], sc.DataArray): + """Experiment data corrected by footprint on sample""" + + +CalibratedReference = NewType('CalibratedReference', sc.DataArray) +WithQResolution = NewType('WithQResolution', sc.DataArray) +Normalized = NewType('Normalized', sc.DataArray) +CountsByMomentumTransfer = NewType('CountsByMomentumTransfer', sc.DataArray) + +''' Parameters for the workflow ''' +MomentumTransferBins = NewType('MomentumTransferBins', sc.Variable) +WavelengthBins = NewType('WavelengthBins', sc.Variable) +ThetaBins = NewType('ThetaBins', sc.Variable) + + +class Rotation(sciline.Scope[Run, sc.Variable], sc.Variable): + """The rotation of the sample / the reference sample""" + + +SpecularReflectionCoordTransformGraph = NewType( + 'SpecularReflectionCoordTransformGraph', dict +) From dfac0bc253642f0d69db86c32ae29ec263039abc Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Thu, 19 Oct 2023 14:02:38 +0200 Subject: [PATCH 02/18] Continue adapting the amor procedures to sciline --- src/essreflectometry/amor/beamline.py | 23 +++++++++---------- src/essreflectometry/amor/load.py | 9 ++++---- .../reflectometry/conversions.py | 14 +++++------ src/essreflectometry/reflectometry/types.py | 6 ++++- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/essreflectometry/amor/beamline.py b/src/essreflectometry/amor/beamline.py index be4e94d..2027968 100644 --- a/src/essreflectometry/amor/beamline.py +++ b/src/essreflectometry/amor/beamline.py @@ -5,24 +5,23 @@ from ..choppers import make_chopper from ..logging import log_call +from ..reflectometry.types import BeamlineParams, Run, SampleRotation @log_call( instrument='amor', message='Constructing AMOR beamline from default parameters' ) -BeamlineParams = NewType('Beamline', dict) - def make_beamline( - sample_rotation: sc.Variable, - beam_size: sc.Variable = None, - sample_size: sc.Variable = None, - detector_spatial_resolution: sc.Variable = None, - gravity: sc.Variable = None, - chopper_frequency: sc.Variable = None, - chopper_phase: sc.Variable = None, - chopper_1_position: sc.Variable = None, - chopper_2_position: sc.Variable = None, -) -> BeamlineParams: + sample_rotation: SampleRotation[Run], +) -> BeamlineParams[Run]: + beam_size: sc.Variable = None + sample_size: sc.Variable = None + detector_spatial_resolution: sc.Variable = None + gravity: sc.Variable = None + chopper_frequency: sc.Variable = None + chopper_phase: sc.Variable = None + chopper_1_position: sc.Variable = None + chopper_2_position: sc.Variable = None """ Amor beamline components. diff --git a/src/essreflectometry/amor/load.py b/src/essreflectometry/amor/load.py index 5042977..8363f8c 100644 --- a/src/essreflectometry/amor/load.py +++ b/src/essreflectometry/amor/load.py @@ -2,14 +2,14 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from datetime import datetime from pathlib import Path -from typing import Any, Optional, Union, NewType, TypeVar +from typing import Any, Union import scipp as sc import scippnexus as snx from ..logging import get_logger -from .beamline import make_beamline, BeamlineParams -from .types import Run, Raw, Filename +from ..reflectometry.types import BeamlineParams, Filename, Raw, Run +from .data import get_path def _tof_correction(data: sc.DataArray, dim: str = 'tof') -> sc.DataArray: @@ -84,7 +84,7 @@ def _load_nexus_entry(filename: Union[str, Path]) -> sc.DataGroup: return f['entry'][()] -def load(filename: Filename[Run], beamline: BeamlineParams) -> Raw[Run]: +def load(filename: Filename[Run], beamline: BeamlineParams[Run]) -> Raw[Run]: """Load a single Amor data file. Parameters @@ -99,6 +99,7 @@ def load(filename: Filename[Run], beamline: BeamlineParams) -> Raw[Run]: : Data array object for Amor dataset. """ + filename = get_path("sample.nxs") get_logger('amor').info( "Loading '%s' as an Amor NeXus file", filename.filename if hasattr(filename, 'filename') else filename, diff --git a/src/essreflectometry/reflectometry/conversions.py b/src/essreflectometry/reflectometry/conversions.py index 169cc9e..d3ad917 100644 --- a/src/essreflectometry/reflectometry/conversions.py +++ b/src/essreflectometry/reflectometry/conversions.py @@ -4,18 +4,18 @@ from scipp.constants import h, m_n, pi from scippneutron._utils import elem_dtype, elem_unit from scippneutron.conversion.graph import beamline, tof + +# from . import orso from .types import ( - ThetaBins, - WavelengthBins, + Raw, + Run, SpecularReflectionCoordTransformGraph, + ThetaBins, ThetaData, + WavelengthBins, WavelengthData, - Run, - Raw, ) -from . import orso - def theta( gravity: sc.Variable, @@ -262,4 +262,4 @@ def sum_bins(data_array: sc.DataArray): return data_array_summed -providers = [specular_reflection, tof_to_wavelength, wavelength_to_theta] +providers = [tof_to_wavelength, wavelength_to_theta] diff --git a/src/essreflectometry/reflectometry/types.py b/src/essreflectometry/reflectometry/types.py index e8da97e..ff9e797 100644 --- a/src/essreflectometry/reflectometry/types.py +++ b/src/essreflectometry/reflectometry/types.py @@ -44,10 +44,14 @@ class FootprintCorrected(sciline.Scope[Run, sc.DataArray], sc.DataArray): ThetaBins = NewType('ThetaBins', sc.Variable) -class Rotation(sciline.Scope[Run, sc.Variable], sc.Variable): +class SampleRotation(sciline.Scope[Run, sc.Variable], sc.Variable): """The rotation of the sample / the reference sample""" +class BeamlineParams(sciline.Scope[Run, dict], dict): + """Parameters describing the beamline""" + + SpecularReflectionCoordTransformGraph = NewType( 'SpecularReflectionCoordTransformGraph', dict ) From b3426ad332b558d84c8562c09af4402c6e0395bc Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Thu, 19 Oct 2023 14:03:15 +0200 Subject: [PATCH 03/18] docs: amor example --- docs/examples/amor.ipynb | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 docs/examples/amor.ipynb diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb new file mode 100644 index 0000000..1df5392 --- /dev/null +++ b/docs/examples/amor.ipynb @@ -0,0 +1,80 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "import scipp as sc\n", + "import sciline\n", + "from essreflectometry.amor.load import load\n", + "from essreflectometry.amor.beamline import make_beamline\n", + "from essreflectometry.amor.conversions import specular_reflection\n", + "from essreflectometry.reflectometry.conversions import providers\n", + "from essreflectometry.reflectometry.types import (\n", + " ThetaBins, WavelengthBins, Sample, SampleRotation, Filename,\n", + " ThetaData, WavelengthData,\n", + ")\n", + "\n", + "\n", + "\n", + "\n", + "pipeline = sciline.Pipeline(\n", + " [load, make_beamline, specular_reflection] + providers,\n", + " params={\n", + " ThetaBins: sc.linspace(dim='theta', start=0, stop=np.pi/2, num=200, unit='rad'),\n", + " WavelengthBins: sc.array(dims=['wavelength'], values=[2.4, 16.0], unit='angstrom'),\n", + " SampleRotation[Sample]: sc.scalar(0.7989, unit='deg'),\n", + " Filename[Sample]: \"sample.nxs\",\n", + " }\n", + ")\n", + "\n", + "pipeline.visualize(ThetaData[Sample])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pipeline.compute(WavelengthData[Sample])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(pipeline.compute(WavelengthData[Sample])\n", + " .bins.concat('detector_number').hist(wavelength=200)\n", + " .plot())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "essreflectometry", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From be891e0a8c02e0ced5796781ed5f03c52894dce4 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Thu, 19 Oct 2023 16:05:53 +0200 Subject: [PATCH 04/18] Continue adapting amor to sciline --- docs/examples/amor.ipynb | 26 +++++++---- src/essreflectometry/amor/calibrations.py | 29 ++++++------ src/essreflectometry/amor/normalize.py | 45 +++++++++++-------- src/essreflectometry/amor/resolution.py | 36 +++++++++++++++ .../reflectometry/conversions.py | 21 +++++---- .../reflectometry/corrections.py | 19 ++++---- src/essreflectometry/reflectometry/types.py | 28 +++++++++--- 7 files changed, 142 insertions(+), 62 deletions(-) diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb index 1df5392..e01f8c4 100644 --- a/docs/examples/amor.ipynb +++ b/docs/examples/amor.ipynb @@ -13,26 +13,34 @@ "from essreflectometry.amor.load import load\n", "from essreflectometry.amor.beamline import make_beamline\n", "from essreflectometry.amor.conversions import specular_reflection\n", + "from essreflectometry.amor.resolution import add_resolutions, compute_resolution\n", + "from essreflectometry.amor.normalize import normalize_by_supermirror\n", + "from essreflectometry.amor.calibrations import supermirror_calibration\n", + "from essreflectometry.reflectometry.corrections import footprint_correction, normalize_by_counts\n", "from essreflectometry.reflectometry.conversions import providers\n", "from essreflectometry.reflectometry.types import (\n", - " ThetaBins, WavelengthBins, Sample, SampleRotation, Filename,\n", - " ThetaData, WavelengthData,\n", + " ThetaBins, WavelengthBins, Sample, Reference, Sample, SampleRotation, Filename,\n", + " ThetaData, WavelengthData, HistogrammedByQ, QDataWithResolutions, QData, QBins, NormalizedIOverQ\n", ")\n", "\n", "\n", - "\n", - "\n", "pipeline = sciline.Pipeline(\n", - " [load, make_beamline, specular_reflection] + providers,\n", + " [load, make_beamline, specular_reflection, footprint_correction,\n", + " add_resolutions, compute_resolution, normalize_by_counts, supermirror_calibration, normalize_by_supermirror]\n", + " + providers,\n", " params={\n", - " ThetaBins: sc.linspace(dim='theta', start=0, stop=np.pi/2, num=200, unit='rad'),\n", + " ThetaBins: sc.linspace(dim='theta', start=0, stop=np.pi/2, num=2, unit='rad'),\n", " WavelengthBins: sc.array(dims=['wavelength'], values=[2.4, 16.0], unit='angstrom'),\n", + " QBins: sc.geomspace(dim='Q', start=0.008, stop=0.075, num=200, unit='1/angstrom'),\n", + "\n", " SampleRotation[Sample]: sc.scalar(0.7989, unit='deg'),\n", " Filename[Sample]: \"sample.nxs\",\n", + " SampleRotation[Reference]: sc.scalar(0.8389, unit='deg'),\n", + " Filename[Reference]: \"reference.nxs\",\n", " }\n", ")\n", "\n", - "pipeline.visualize(ThetaData[Sample])" + "pipeline.visualize(NormalizedIOverQ)" ] }, { @@ -41,7 +49,7 @@ "metadata": {}, "outputs": [], "source": [ - "pipeline.compute(WavelengthData[Sample])" + "pipeline.compute(HistogrammedByQ[QData[Reference]])" ] }, { @@ -50,7 +58,7 @@ "metadata": {}, "outputs": [], "source": [ - "(pipeline.compute(WavelengthData[Sample])\n", + "(pipeline.compute(WithResolution)\n", " .bins.concat('detector_number').hist(wavelength=200)\n", " .plot())" ] diff --git a/src/essreflectometry/amor/calibrations.py b/src/essreflectometry/amor/calibrations.py index fd3d149..3d308b6 100644 --- a/src/essreflectometry/amor/calibrations.py +++ b/src/essreflectometry/amor/calibrations.py @@ -2,15 +2,17 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import scipp as sc -from ..reflectometry import orso +# from ..reflectometry import orso +from ..reflectometry.types import CalibratedReference, HistogrammedByQ, QData, Reference def supermirror_calibration( - data_array: sc.DataArray, - m_value: sc.Variable = None, - critical_edge: sc.Variable = None, - alpha: sc.Variable = None, -) -> sc.Variable: + data_array: HistogrammedByQ[QData[Reference]], +) -> CalibratedReference: + # TODO + m_value: sc.Variable = None + critical_edge: sc.Variable = None + alpha: sc.Variable = None """ Calibrate supermirror measurements @@ -38,13 +40,14 @@ def supermirror_calibration( alpha = sc.scalar(0.25 / 0.088, unit=sc.units.angstrom) calibration = calibration_factor(data_array, m_value, critical_edge, alpha) data_array_cal = data_array * calibration - try: - data_array_cal.attrs['orso'].value.reduction.corrections += [ - 'supermirror calibration' - ] - except KeyError: - orso.not_found_warning() - return data_array_cal + # TODO + # try: + # data_array_cal.attrs['orso'].value.reduction.corrections += [ + # 'supermirror calibration' + # ] + # except KeyError: + # orso.not_found_warning() + return CalibratedReference(data_array_cal) def calibration_factor( diff --git a/src/essreflectometry/amor/normalize.py b/src/essreflectometry/amor/normalize.py index ceead34..fbb626e 100644 --- a/src/essreflectometry/amor/normalize.py +++ b/src/essreflectometry/amor/normalize.py @@ -2,12 +2,20 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import scipp as sc -from ..reflectometry import orso +# from ..reflectometry import orso +from ..reflectometry.types import ( + CalibratedReference, + HistogrammedByQ, + NormalizedData, + NormalizedIOverQ, + QDataWithResolutions, +) def normalize_by_supermirror( - sample: sc.DataArray, supermirror: sc.DataArray -) -> sc.DataArray: + sample: NormalizedData[HistogrammedByQ[QDataWithResolutions]], + supermirror: NormalizedData[CalibratedReference], +) -> NormalizedIOverQ: """ Normalize the sample measurement by the (ideally calibrated) supermirror. @@ -26,19 +34,20 @@ def normalize_by_supermirror( """ normalized = sample / supermirror normalized.masks['no_reference_neutrons'] = (supermirror == sc.scalar(0)).data - try: - normalized.attrs['orso'] = sample.attrs['orso'] - normalized.attrs['orso'].value.reduction.corrections = list( - set( - sample.attrs['orso'].value.reduction.corrections - + supermirror.attrs['orso'].value.reduction.corrections - ) - ) - normalized.attrs[ - 'orso' - ].value.data_source.measurement.reference = supermirror.attrs[ - 'orso' - ].value.data_source.measurement.data_files - except KeyError: - orso.not_found_warning() + # TODO + # try: + # normalized.attrs['orso'] = sample.attrs['orso'] + # normalized.attrs['orso'].value.reduction.corrections = list( + # set( + # sample.attrs['orso'].value.reduction.corrections + # + supermirror.attrs['orso'].value.reduction.corrections + # ) + # ) + # normalized.attrs[ + # 'orso' + # ].value.data_source.measurement.reference = supermirror.attrs[ + # 'orso' + # ].value.data_source.measurement.data_files + # except KeyError: + # orso.not_found_warning() return normalized diff --git a/src/essreflectometry/amor/resolution.py b/src/essreflectometry/amor/resolution.py index 7591a8e..d663852 100644 --- a/src/essreflectometry/amor/resolution.py +++ b/src/essreflectometry/amor/resolution.py @@ -2,9 +2,45 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import scipp as sc +from ..reflectometry.types import ( + FootprintCorrected, + QData, + QDataWithResolutions, + Resolutions, + Sample, +) from .tools import fwhm_to_std +def compute_resolution(da: FootprintCorrected[Sample]) -> Resolutions: + return Resolutions( + { + 'wavelength_resolution': wavelength_resolution( + chopper_1_position=da.coords['source_chopper_1'].value['position'], + chopper_2_position=da.coords['source_chopper_2'].value['position'], + pixel_position=da.coords['position'], + ), + 'angular_resolution': angular_resolution( + pixel_position=da.coords['position'], + theta=da.bins.coords['theta'], + detector_spatial_resolution=da.coords['detector_spatial_resolution'], + ), + 'sample_size_resolution': sample_size_resolution( + pixel_position=da.coords['position'], + sample_size=da.coords['sample_size'], + ), + } + ) + + +def add_resolutions( + da: QData[Sample], resolutions: Resolutions +) -> QDataWithResolutions: + for coord, value in resolutions.items(): + da.coords[coord] = value + return QDataWithResolutions(da) + + def wavelength_resolution( chopper_1_position: sc.Variable, chopper_2_position: sc.Variable, diff --git a/src/essreflectometry/reflectometry/conversions.py b/src/essreflectometry/reflectometry/conversions.py index d3ad917..acd58a3 100644 --- a/src/essreflectometry/reflectometry/conversions.py +++ b/src/essreflectometry/reflectometry/conversions.py @@ -7,6 +7,11 @@ # from . import orso from .types import ( + CorrectedQData, + FootprintCorrected, + HistogrammedByQ, + QBins, + QData, Raw, Run, SpecularReflectionCoordTransformGraph, @@ -213,8 +218,10 @@ def wavelength_to_theta( def theta_to_q( - data_array: sc.DataArray, q_edges: sc.Variable = None, graph: dict = None -) -> sc.DataArray: + data_array: FootprintCorrected[Run], + q_edges: QBins, + graph: SpecularReflectionCoordTransformGraph, +) -> QData[Run]: """ Convert from theta to Q and if necessary bin in Q. @@ -233,14 +240,12 @@ def theta_to_q( : New data array with theta coordinate. """ - graph = graph if graph is not None else specular_reflection() data_array_q = data_array.transform_coords(["Q"], graph=graph) - if q_edges is not None: - data_array_q = data_array_q.bin({q_edges.dim: q_edges}) - return data_array_q + data_array_q = data_array_q.bin({q_edges.dim: q_edges}) + return QData[Run](data_array_q) -def sum_bins(data_array: sc.DataArray): +def sum_bins(data_array: CorrectedQData) -> HistogrammedByQ[CorrectedQData]: """ Sum the event bins and propagate the maximum resolution, where available. @@ -262,4 +267,4 @@ def sum_bins(data_array: sc.DataArray): return data_array_summed -providers = [tof_to_wavelength, wavelength_to_theta] +providers = [tof_to_wavelength, wavelength_to_theta, theta_to_q, sum_bins] diff --git a/src/essreflectometry/reflectometry/corrections.py b/src/essreflectometry/reflectometry/corrections.py index a8833c5..22de22b 100644 --- a/src/essreflectometry/reflectometry/corrections.py +++ b/src/essreflectometry/reflectometry/corrections.py @@ -5,9 +5,10 @@ from ..amor.tools import fwhm_to_std from . import orso +from .types import FootprintCorrected, Normalizable, NormalizedData, Run, ThetaData -def footprint_correction(data_array: sc.DataArray) -> sc.DataArray: +def footprint_correction(data_array: ThetaData[Run]) -> FootprintCorrected[Run]: """ Perform the footprint correction on the data array that has a :code:`beam_size` and binned :code:`theta` values. @@ -29,16 +30,16 @@ def footprint_correction(data_array: sc.DataArray) -> sc.DataArray: fwhm_to_std(data_array.coords['sample_size'] / size_of_beam_on_sample) ) data_array_fp_correction = data_array / footprint_scale.squeeze() - try: - data_array_fp_correction.attrs['orso'].value.reduction.corrections += [ - 'footprint correction' - ] - except KeyError: - orso.not_found_warning() - return data_array_fp_correction + # try: + # data_array_fp_correction.attrs['orso'].value.reduction.corrections += [ + # 'footprint correction' + # ] + # except KeyError: + # orso.not_found_warning() + return FootprintCorrected[Run](data_array_fp_correction) -def normalize_by_counts(data_array: sc.DataArray) -> sc.DataArray: +def normalize_by_counts(data_array: Normalizable) -> NormalizedData[Normalizable]: """ Normalize the bin-summed data by the total number of counts. If the data has variances, a check is performed to ensure that the counts in each diff --git a/src/essreflectometry/reflectometry/types.py b/src/essreflectometry/reflectometry/types.py index ff9e797..b5ea793 100644 --- a/src/essreflectometry/reflectometry/types.py +++ b/src/essreflectometry/reflectometry/types.py @@ -24,9 +24,8 @@ class ThetaData(sciline.Scope[Run, sc.DataArray], sc.DataArray): """Wavelength data transformed to theta""" -class Experiment(sciline.Scope[Run, sc.DataArray], sc.DataArray): - """Experiment data with added coordinates: - wavelength, incidence angle, and momentum transfer""" +class QData(sciline.Scope[Run, sc.DataArray], sc.DataArray): + """Theta data transformed to momentum transfer""" class FootprintCorrected(sciline.Scope[Run, sc.DataArray], sc.DataArray): @@ -34,12 +33,12 @@ class FootprintCorrected(sciline.Scope[Run, sc.DataArray], sc.DataArray): CalibratedReference = NewType('CalibratedReference', sc.DataArray) -WithQResolution = NewType('WithQResolution', sc.DataArray) +Resolutions = NewType('Resolutions', dict) Normalized = NewType('Normalized', sc.DataArray) CountsByMomentumTransfer = NewType('CountsByMomentumTransfer', sc.DataArray) ''' Parameters for the workflow ''' -MomentumTransferBins = NewType('MomentumTransferBins', sc.Variable) +QBins = NewType('QBins', sc.Variable) WavelengthBins = NewType('WavelengthBins', sc.Variable) ThetaBins = NewType('ThetaBins', sc.Variable) @@ -55,3 +54,22 @@ class BeamlineParams(sciline.Scope[Run, dict], dict): SpecularReflectionCoordTransformGraph = NewType( 'SpecularReflectionCoordTransformGraph', dict ) + +QDataWithResolutions = NewType('QDataWithResolutions', sc.DataArray) +CorrectedQData = TypeVar('CorrectedQData', QData[Reference], QDataWithResolutions) + + +class HistogrammedByQ(sciline.Scope[CorrectedQData, sc.DataArray], sc.DataArray): + """Histogrammmed by Q. Either reference data or sample data with resolutions.""" + + +Normalizable = TypeVar( + 'Normalizable', HistogrammedByQ[QDataWithResolutions], CalibratedReference +) + + +class NormalizedData(sciline.Scope[Normalizable, sc.DataArray], sc.DataArray): + """Normalized histogramm by Q.""" + + +NormalizedIOverQ = NewType('NormalizedIOverQ', sc.DataArray) From de67273d300a30396a13598391709fa32d32d27c Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Fri, 20 Oct 2023 09:45:05 +0200 Subject: [PATCH 05/18] fix --- src/essreflectometry/amor/load.py | 11 ++++-- src/essreflectometry/amor/resolution.py | 47 ++++++++----------------- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/essreflectometry/amor/load.py b/src/essreflectometry/amor/load.py index 8363f8c..7479ada 100644 --- a/src/essreflectometry/amor/load.py +++ b/src/essreflectometry/amor/load.py @@ -99,7 +99,7 @@ def load(filename: Filename[Run], beamline: BeamlineParams[Run]) -> Raw[Run]: : Data array object for Amor dataset. """ - filename = get_path("sample.nxs") + filename = get_path(filename) get_logger('amor').info( "Loading '%s' as an Amor NeXus file", filename.filename if hasattr(filename, 'filename') else filename, @@ -128,7 +128,14 @@ def load(filename: Filename[Run], beamline: BeamlineParams[Run]) -> Raw[Run]: # data.attrs['orso'] = sc.scalar(orso) # Perform tof correction and fold two pulses - return Raw[Run](_tof_correction(data)) + data = _tof_correction(data) + + # Ad-hoc correction described in + # https://scipp.github.io/ess/instruments/amor/amor_reduction.html + data.coords['position'].fields.y += data.coords['position'].fields.z * sc.tan( + 2.0 * data.coords['sample_rotation'] - (0.955 * sc.units.deg) + ) + return data def populate_orso(orso: Any, data: sc.DataGroup, filename: str) -> Any: diff --git a/src/essreflectometry/amor/resolution.py b/src/essreflectometry/amor/resolution.py index d663852..31bfaf7 100644 --- a/src/essreflectometry/amor/resolution.py +++ b/src/essreflectometry/amor/resolution.py @@ -2,42 +2,25 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import scipp as sc -from ..reflectometry.types import ( - FootprintCorrected, - QData, - QDataWithResolutions, - Resolutions, - Sample, -) +from ..reflectometry.types import QData, QDataWithResolutions, Sample from .tools import fwhm_to_std -def compute_resolution(da: FootprintCorrected[Sample]) -> Resolutions: - return Resolutions( - { - 'wavelength_resolution': wavelength_resolution( - chopper_1_position=da.coords['source_chopper_1'].value['position'], - chopper_2_position=da.coords['source_chopper_2'].value['position'], - pixel_position=da.coords['position'], - ), - 'angular_resolution': angular_resolution( - pixel_position=da.coords['position'], - theta=da.bins.coords['theta'], - detector_spatial_resolution=da.coords['detector_spatial_resolution'], - ), - 'sample_size_resolution': sample_size_resolution( - pixel_position=da.coords['position'], - sample_size=da.coords['sample_size'], - ), - } +def compute_resolution(da: QData[Sample]) -> QDataWithResolutions: + da.coords['wavelength_resolution'] = wavelength_resolution( + chopper_1_position=da.coords['source_chopper_1'].value['position'], + chopper_2_position=da.coords['source_chopper_2'].value['position'], + pixel_position=da.coords['position'], + ) + da.coords['angular_resolution'] = angular_resolution( + pixel_position=da.coords['position'], + theta=da.bins.coords['theta'], + detector_spatial_resolution=da.coords['detector_spatial_resolution'], + ) + da.coords['sample_size_resolution'] = sample_size_resolution( + pixel_position=da.coords['position'], + sample_size=da.coords['sample_size'], ) - - -def add_resolutions( - da: QData[Sample], resolutions: Resolutions -) -> QDataWithResolutions: - for coord, value in resolutions.items(): - da.coords[coord] = value return QDataWithResolutions(da) From 857827847e41820000d887be33ce822ac4282d58 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Fri, 20 Oct 2023 09:45:23 +0200 Subject: [PATCH 06/18] Update example --- docs/examples/amor.ipynb | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb index e01f8c4..cb96917 100644 --- a/docs/examples/amor.ipynb +++ b/docs/examples/amor.ipynb @@ -13,20 +13,20 @@ "from essreflectometry.amor.load import load\n", "from essreflectometry.amor.beamline import make_beamline\n", "from essreflectometry.amor.conversions import specular_reflection\n", - "from essreflectometry.amor.resolution import add_resolutions, compute_resolution\n", + "from essreflectometry.amor.resolution import compute_resolution\n", "from essreflectometry.amor.normalize import normalize_by_supermirror\n", "from essreflectometry.amor.calibrations import supermirror_calibration\n", "from essreflectometry.reflectometry.corrections import footprint_correction, normalize_by_counts\n", "from essreflectometry.reflectometry.conversions import providers\n", "from essreflectometry.reflectometry.types import (\n", - " ThetaBins, WavelengthBins, Sample, Reference, Sample, SampleRotation, Filename,\n", + " ThetaBins, WavelengthBins, Sample, Reference, Sample, SampleRotation, Filename, Raw, BeamlineParams,\n", " ThetaData, WavelengthData, HistogrammedByQ, QDataWithResolutions, QData, QBins, NormalizedIOverQ\n", ")\n", "\n", "\n", "pipeline = sciline.Pipeline(\n", " [load, make_beamline, specular_reflection, footprint_correction,\n", - " add_resolutions, compute_resolution, normalize_by_counts, supermirror_calibration, normalize_by_supermirror]\n", + " compute_resolution, normalize_by_counts, supermirror_calibration, normalize_by_supermirror]\n", " + providers,\n", " params={\n", " ThetaBins: sc.linspace(dim='theta', start=0, stop=np.pi/2, num=2, unit='rad'),\n", @@ -49,7 +49,8 @@ "metadata": {}, "outputs": [], "source": [ - "pipeline.compute(HistogrammedByQ[QData[Reference]])" + "normalized = pipeline.compute(NormalizedIOverQ)\n", + "normalized.plot(norm='log') + normalized.mean('detector_number').plot(norm='log')\n" ] }, { @@ -58,9 +59,25 @@ "metadata": {}, "outputs": [], "source": [ - "(pipeline.compute(WithResolution)\n", - " .bins.concat('detector_number').hist(wavelength=200)\n", - " .plot())" + "# Diagnostics plot\n", + "(pipeline.compute(ThetaData[Sample])\n", + " .bins.concat('detector_number')\n", + " .hist(\n", + " theta=sc.linspace(dim='theta', start=0.0, stop=1.2, num=165, unit='deg').to(unit='rad'),\n", + " wavelength=sc.linspace(dim='wavelength', start=0, stop=15.0, num=165, unit='angstrom'),\n", + " )\n", + " .plot())\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import plopp\n", + "\n", + "[]" ] } ], From 4f485b756f3f23850efe00e3716df666c8fb6ca0 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Mon, 23 Oct 2023 14:56:04 +0200 Subject: [PATCH 07/18] restructure the type system to avoid nested parameterized types --- docs/examples/amor.ipynb | 31 +++------ src/essreflectometry/amor/__init__.py | 18 ++++- src/essreflectometry/amor/beamline.py | 4 ++ src/essreflectometry/amor/calibrations.py | 11 +-- src/essreflectometry/amor/conversions.py | 4 +- src/essreflectometry/amor/load.py | 3 + src/essreflectometry/amor/normalize.py | 14 ++-- src/essreflectometry/amor/resolution.py | 67 +++++++++++++------ .../reflectometry/__init__.py | 8 +++ .../reflectometry/conversions.py | 55 ++++++++------- .../reflectometry/corrections.py | 30 ++++++--- src/essreflectometry/reflectometry/types.py | 54 ++++++++------- 12 files changed, 182 insertions(+), 117 deletions(-) diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb index cb96917..07e123b 100644 --- a/docs/examples/amor.ipynb +++ b/docs/examples/amor.ipynb @@ -6,33 +6,19 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", - "\n", "import scipp as sc\n", "import sciline\n", - "from essreflectometry.amor.load import load\n", - "from essreflectometry.amor.beamline import make_beamline\n", - "from essreflectometry.amor.conversions import specular_reflection\n", - "from essreflectometry.amor.resolution import compute_resolution\n", - "from essreflectometry.amor.normalize import normalize_by_supermirror\n", - "from essreflectometry.amor.calibrations import supermirror_calibration\n", - "from essreflectometry.reflectometry.corrections import footprint_correction, normalize_by_counts\n", - "from essreflectometry.reflectometry.conversions import providers\n", + "from essreflectometry.amor import providers as amor\n", + "from essreflectometry.reflectometry import providers as reflectometry\n", "from essreflectometry.reflectometry.types import (\n", - " ThetaBins, WavelengthBins, Sample, Reference, Sample, SampleRotation, Filename, Raw, BeamlineParams,\n", - " ThetaData, WavelengthData, HistogrammedByQ, QDataWithResolutions, QData, QBins, NormalizedIOverQ\n", + " Sample, Reference, Sample, SampleRotation, Filename,\n", + " ThetaData, QBins, NormalizedIOverQ, QStd\n", ")\n", "\n", - "\n", "pipeline = sciline.Pipeline(\n", - " [load, make_beamline, specular_reflection, footprint_correction,\n", - " compute_resolution, normalize_by_counts, supermirror_calibration, normalize_by_supermirror]\n", - " + providers,\n", + " amor + reflectometry,\n", " params={\n", - " ThetaBins: sc.linspace(dim='theta', start=0, stop=np.pi/2, num=2, unit='rad'),\n", - " WavelengthBins: sc.array(dims=['wavelength'], values=[2.4, 16.0], unit='angstrom'),\n", " QBins: sc.geomspace(dim='Q', start=0.008, stop=0.075, num=200, unit='1/angstrom'),\n", - "\n", " SampleRotation[Sample]: sc.scalar(0.7989, unit='deg'),\n", " Filename[Sample]: \"sample.nxs\",\n", " SampleRotation[Reference]: sc.scalar(0.8389, unit='deg'),\n", @@ -40,7 +26,7 @@ " }\n", ")\n", "\n", - "pipeline.visualize(NormalizedIOverQ)" + "pipeline.visualize((NormalizedIOverQ, QStd))" ] }, { @@ -75,9 +61,8 @@ "metadata": {}, "outputs": [], "source": [ - "import plopp\n", - "\n", - "[]" + "res = pipeline.compute((NormalizedIOverQ, QStd))\n", + "res[QStd].plot()" ] } ], diff --git a/src/essreflectometry/amor/__init__.py b/src/essreflectometry/amor/__init__.py index a74676e..c8bd3e1 100644 --- a/src/essreflectometry/amor/__init__.py +++ b/src/essreflectometry/amor/__init__.py @@ -1,7 +1,19 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) # flake8: noqa: F401 -from . import calibrations, conversions, data, normalize, resolution, tools -from .beamline import instrument_view_components, make_beamline +from itertools import chain + +from . import calibrations, conversions, load, normalize, resolution, tools +from .beamline import instrument_view_components from .instrument_view import instrument_view -from .load import load + +providers = list( + chain( + load.providers, + calibrations.providers, + conversions.providers, + normalize.providers, + resolution.providers, + beamline.providers, + ) +) diff --git a/src/essreflectometry/amor/beamline.py b/src/essreflectometry/amor/beamline.py index 2027968..0969afa 100644 --- a/src/essreflectometry/amor/beamline.py +++ b/src/essreflectometry/amor/beamline.py @@ -14,6 +14,7 @@ def make_beamline( sample_rotation: SampleRotation[Run], ) -> BeamlineParams[Run]: + # TODO beam_size: sc.Variable = None sample_size: sc.Variable = None detector_spatial_resolution: sc.Variable = None @@ -132,3 +133,6 @@ def instrument_view_components(da: sc.DataArray) -> dict: 'type': 'disk', }, } + + +providers = [make_beamline] diff --git a/src/essreflectometry/amor/calibrations.py b/src/essreflectometry/amor/calibrations.py index 3d308b6..acbb57e 100644 --- a/src/essreflectometry/amor/calibrations.py +++ b/src/essreflectometry/amor/calibrations.py @@ -3,12 +3,12 @@ import scipp as sc # from ..reflectometry import orso -from ..reflectometry.types import CalibratedReference, HistogrammedByQ, QData, Reference +from ..reflectometry.types import CalibratedReference, Histogrammed, Reference def supermirror_calibration( - data_array: HistogrammedByQ[QData[Reference]], -) -> CalibratedReference: + data_array: Histogrammed[Reference], +) -> Histogrammed[CalibratedReference]: # TODO m_value: sc.Variable = None critical_edge: sc.Variable = None @@ -47,7 +47,7 @@ def supermirror_calibration( # ] # except KeyError: # orso.not_found_warning() - return CalibratedReference(data_array_cal) + return Histogrammed[CalibratedReference](data_array_cal) def calibration_factor( @@ -90,3 +90,6 @@ def calibration_factor( nq = 1.0 / (1.0 - alpha * (q - critical_edge)) calibration_factor = sc.where(q < max_q, lim + (1 - lim) * nq, sc.scalar(1.0)) return calibration_factor + + +providers = [supermirror_calibration] diff --git a/src/essreflectometry/amor/conversions.py b/src/essreflectometry/amor/conversions.py index 3a643a2..cf8e0e3 100644 --- a/src/essreflectometry/amor/conversions.py +++ b/src/essreflectometry/amor/conversions.py @@ -1,6 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import NewType import scipp as sc from ..reflectometry.conversions import specular_reflection as spec_relf_graph @@ -31,3 +30,6 @@ def specular_reflection() -> SpecularReflectionCoordTransformGraph: graph = spec_relf_graph() graph['incident_beam'] = incident_beam return SpecularReflectionCoordTransformGraph(graph) + + +providers = [specular_reflection] diff --git a/src/essreflectometry/amor/load.py b/src/essreflectometry/amor/load.py index 7479ada..23441ce 100644 --- a/src/essreflectometry/amor/load.py +++ b/src/essreflectometry/amor/load.py @@ -160,3 +160,6 @@ def populate_orso(orso: Any, data: sc.DataGroup, filename: str) -> Any: '%Y-%m-%d', ) orso.data_source.measurement.data_files = [filename] + + +providers = [load] diff --git a/src/essreflectometry/amor/normalize.py b/src/essreflectometry/amor/normalize.py index fbb626e..024498f 100644 --- a/src/essreflectometry/amor/normalize.py +++ b/src/essreflectometry/amor/normalize.py @@ -5,16 +5,15 @@ # from ..reflectometry import orso from ..reflectometry.types import ( CalibratedReference, - HistogrammedByQ, - NormalizedData, + Normalized, NormalizedIOverQ, - QDataWithResolutions, + Sample, ) def normalize_by_supermirror( - sample: NormalizedData[HistogrammedByQ[QDataWithResolutions]], - supermirror: NormalizedData[CalibratedReference], + sample: Normalized[Sample], + supermirror: Normalized[CalibratedReference], ) -> NormalizedIOverQ: """ Normalize the sample measurement by the (ideally calibrated) supermirror. @@ -50,4 +49,7 @@ def normalize_by_supermirror( # ].value.data_source.measurement.data_files # except KeyError: # orso.not_found_warning() - return normalized + return NormalizedIOverQ(normalized) + + +providers = [normalize_by_supermirror] diff --git a/src/essreflectometry/amor/resolution.py b/src/essreflectometry/amor/resolution.py index 31bfaf7..8654717 100644 --- a/src/essreflectometry/amor/resolution.py +++ b/src/essreflectometry/amor/resolution.py @@ -2,29 +2,49 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import scipp as sc -from ..reflectometry.types import QData, QDataWithResolutions, Sample +from ..reflectometry.types import ( + AngularResolution, + Histogrammed, + QBins, + QData, + QStd, + Sample, + SampleSizeResolution, + WavelengthResolution, +) from .tools import fwhm_to_std -def compute_resolution(da: QData[Sample]) -> QDataWithResolutions: - da.coords['wavelength_resolution'] = wavelength_resolution( - chopper_1_position=da.coords['source_chopper_1'].value['position'], - chopper_2_position=da.coords['source_chopper_2'].value['position'], - pixel_position=da.coords['position'], +def wavelength_resolution(da: QData[Sample]) -> WavelengthResolution: + return WavelengthResolution( + _wavelength_resolution( + chopper_1_position=da.coords['source_chopper_1'].value['position'], + chopper_2_position=da.coords['source_chopper_2'].value['position'], + pixel_position=da.coords['position'], + ) ) - da.coords['angular_resolution'] = angular_resolution( - pixel_position=da.coords['position'], - theta=da.bins.coords['theta'], - detector_spatial_resolution=da.coords['detector_spatial_resolution'], + + +def angular_resolution(da: QData[Sample]) -> AngularResolution: + return AngularResolution( + _angular_resolution( + pixel_position=da.coords['position'], + theta=da.bins.coords['theta'], + detector_spatial_resolution=da.coords['detector_spatial_resolution'], + ) ) - da.coords['sample_size_resolution'] = sample_size_resolution( - pixel_position=da.coords['position'], - sample_size=da.coords['sample_size'], + + +def sample_size_resolution(da: QData[Sample]) -> SampleSizeResolution: + return SampleSizeResolution( + _sample_size_resolution( + pixel_position=da.coords['position'], + sample_size=da.coords['sample_size'], + ) ) - return QDataWithResolutions(da) -def wavelength_resolution( +def _wavelength_resolution( chopper_1_position: sc.Variable, chopper_2_position: sc.Variable, pixel_position: sc.Variable, @@ -57,7 +77,7 @@ def wavelength_resolution( return fwhm_to_std(distance_between_choppers / chopper_detector_distance) -def sample_size_resolution( +def _sample_size_resolution( pixel_position: sc.Variable, sample_size: sc.Variable ) -> sc.Variable: """ @@ -83,7 +103,7 @@ def sample_size_resolution( ) -def angular_resolution( +def _angular_resolution( pixel_position: sc.Variable, theta: sc.Variable, detector_spatial_resolution: sc.Variable, @@ -123,11 +143,11 @@ def angular_resolution( def sigma_Q( - angular_resolution: sc.Variable, - wavelength_resolution: sc.Variable, - sample_size_resolution: sc.Variable, - q_bins: sc.Variable, -) -> sc.Variable: + angular_resolution: Histogrammed[AngularResolution], + wavelength_resolution: WavelengthResolution, + sample_size_resolution: SampleSizeResolution, + q_bins: QBins, +) -> QStd: """ Combine all of the components of the resolution and add Q contribution. @@ -152,3 +172,6 @@ def sigma_Q( + wavelength_resolution**2 + sample_size_resolution**2 ).max('detector_number') * sc.midpoints(q_bins) + + +providers = [sigma_Q, angular_resolution, wavelength_resolution, sample_size_resolution] diff --git a/src/essreflectometry/reflectometry/__init__.py b/src/essreflectometry/reflectometry/__init__.py index fcb6518..e5328ac 100644 --- a/src/essreflectometry/reflectometry/__init__.py +++ b/src/essreflectometry/reflectometry/__init__.py @@ -2,5 +2,13 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) # flake8: noqa: F401 +from itertools import chain from . import conversions, corrections, io + +providers = list( + chain( + conversions.providers, + corrections.providers, + ) +) diff --git a/src/essreflectometry/reflectometry/conversions.py b/src/essreflectometry/reflectometry/conversions.py index acd58a3..68cc602 100644 --- a/src/essreflectometry/reflectometry/conversions.py +++ b/src/essreflectometry/reflectometry/conversions.py @@ -7,17 +7,15 @@ # from . import orso from .types import ( - CorrectedQData, + AngularResolution, FootprintCorrected, - HistogrammedByQ, + Histogrammed, QBins, QData, Raw, Run, SpecularReflectionCoordTransformGraph, - ThetaBins, ThetaData, - WavelengthBins, WavelengthData, ) @@ -120,7 +118,6 @@ def specular_reflection() -> SpecularReflectionCoordTransformGraph: def tof_to_wavelength( data_array: Raw[Run], - wavelength_edges: WavelengthBins, graph: SpecularReflectionCoordTransformGraph, ) -> WavelengthData[Run]: """ @@ -131,9 +128,6 @@ def tof_to_wavelength( ---------- data_array: Data array to convert. - wavelength_edges: - The lower and upper limits for the wavelength. - If :code:`None`, no binning is performed. graph: Graph for :code:`transform_coords`. @@ -143,7 +137,6 @@ def tof_to_wavelength( New data array with wavelength dimension. """ data_array_wav = data_array.transform_coords(["wavelength"], graph=graph) - data_array_wav = data_array_wav.bin({wavelength_edges.dim: wavelength_edges}) # TODO # try: # from orsopy import fileio @@ -166,7 +159,6 @@ def tof_to_wavelength( def wavelength_to_theta( data_array: WavelengthData[Run], - theta_edges: ThetaBins, graph: SpecularReflectionCoordTransformGraph, ) -> ThetaData[Run]: """ @@ -177,9 +169,6 @@ def wavelength_to_theta( ---------- data_array: Data array to convert. - theta_edges: - The lower and upper limits for the theta. If :code:`None`, no - binning is performed. graph: Graph for :code:`transform_coords`. @@ -189,7 +178,6 @@ def wavelength_to_theta( New data array with theta coordinate. """ data_array_theta = data_array.transform_coords(['theta'], graph=graph) - data_array_theta = data_array_theta.bin({theta_edges.dim: theta_edges}) # TODO # try: # from orsopy import fileio @@ -230,8 +218,7 @@ def theta_to_q( data_array: Data array to convert. q_edges: - The lower and upper limits for the Q. If :code:`None`, no - binning is performed. + The lower and upper limits for the Q. graph: Graph for :code:`transform_coords`. @@ -245,7 +232,7 @@ def theta_to_q( return QData[Run](data_array_q) -def sum_bins(data_array: CorrectedQData) -> HistogrammedByQ[CorrectedQData]: +def sum_bins(data_array: QData[Run]) -> Histogrammed[Run]: """ Sum the event bins and propagate the maximum resolution, where available. @@ -259,12 +246,32 @@ def sum_bins(data_array: CorrectedQData) -> HistogrammedByQ[CorrectedQData]: : Summed data array. """ - data_array_summed = data_array.bins.sum() - if 'angular_resolution' in data_array.bins.coords: - data_array_summed.coords['angular_resolution'] = data_array.bins.coords[ - 'angular_resolution' - ].max('detector_number') - return data_array_summed + return Histogrammed[Run](data_array.bins.sum()) -providers = [tof_to_wavelength, wavelength_to_theta, theta_to_q, sum_bins] +def aggregate_resolution_in_bins( + angular_resolution: AngularResolution, +) -> Histogrammed[AngularResolution]: + """ + Propagate the maximum resolution. + + Parameters + ---------- + angular_resolution: + Angular resolution for each Q. + + Returns + ------- + : + Max of angular resolution over detectors. + """ + return Histogrammed[AngularResolution](angular_resolution.max('detector_number')) + + +providers = [ + tof_to_wavelength, + wavelength_to_theta, + theta_to_q, + sum_bins, + aggregate_resolution_in_bins, +] diff --git a/src/essreflectometry/reflectometry/corrections.py b/src/essreflectometry/reflectometry/corrections.py index 22de22b..f539d9d 100644 --- a/src/essreflectometry/reflectometry/corrections.py +++ b/src/essreflectometry/reflectometry/corrections.py @@ -4,8 +4,16 @@ import scipp as sc from ..amor.tools import fwhm_to_std -from . import orso -from .types import FootprintCorrected, Normalizable, NormalizedData, Run, ThetaData + +# from . import orso +from .types import ( + CalibratedRun, + FootprintCorrected, + Histogrammed, + Normalized, + Run, + ThetaData, +) def footprint_correction(data_array: ThetaData[Run]) -> FootprintCorrected[Run]: @@ -39,7 +47,9 @@ def footprint_correction(data_array: ThetaData[Run]) -> FootprintCorrected[Run]: return FootprintCorrected[Run](data_array_fp_correction) -def normalize_by_counts(data_array: Normalizable) -> NormalizedData[Normalizable]: +def normalize_by_counts( + data_array: Histogrammed[CalibratedRun], +) -> Normalized[CalibratedRun]: """ Normalize the bin-summed data by the total number of counts. If the data has variances, a check is performed to ensure that the counts in each @@ -73,11 +83,12 @@ def normalize_by_counts(data_array: Normalizable) -> NormalizedData[Normalizable f'regime. The maximum counts found is {data_array.values[ind]} at ' f'index {ind}. The total number of counts is {ncounts.value}.' ) - try: - norm.attrs['orso'].value.reduction.corrections += ['total counts'] - except KeyError: - orso.not_found_warning() - return norm + # TODO + # try: + # norm.attrs['orso'].value.reduction.corrections += ['total counts'] + # except KeyError: + # orso.not_found_warning() + return Normalized[CalibratedRun](norm) def beam_on_sample(beam_size: sc.Variable, theta: sc.Variable) -> sc.Variable: @@ -97,3 +108,6 @@ def beam_on_sample(beam_size: sc.Variable, theta: sc.Variable) -> sc.Variable: Size of the beam on the sample. """ return beam_size / sc.sin(theta) + + +providers = [footprint_correction, normalize_by_counts] diff --git a/src/essreflectometry/reflectometry/types.py b/src/essreflectometry/reflectometry/types.py index b5ea793..6c66e44 100644 --- a/src/essreflectometry/reflectometry/types.py +++ b/src/essreflectometry/reflectometry/types.py @@ -8,10 +8,6 @@ Run = TypeVar('Run', Reference, Sample) -class Filename(sciline.Scope[Run, str], str): - """Filename of the raw data""" - - class Raw(sciline.Scope[Run, sc.DataArray], sc.DataArray): """Raw data""" @@ -28,23 +24,16 @@ class QData(sciline.Scope[Run, sc.DataArray], sc.DataArray): """Theta data transformed to momentum transfer""" -class FootprintCorrected(sciline.Scope[Run, sc.DataArray], sc.DataArray): - """Experiment data corrected by footprint on sample""" +QStd = NewType('QStd', sc.Variable) -CalibratedReference = NewType('CalibratedReference', sc.DataArray) -Resolutions = NewType('Resolutions', dict) -Normalized = NewType('Normalized', sc.DataArray) -CountsByMomentumTransfer = NewType('CountsByMomentumTransfer', sc.DataArray) - -''' Parameters for the workflow ''' -QBins = NewType('QBins', sc.Variable) -WavelengthBins = NewType('WavelengthBins', sc.Variable) -ThetaBins = NewType('ThetaBins', sc.Variable) +class FootprintCorrected(sciline.Scope[Run, sc.DataArray], sc.DataArray): + """Experiment data corrected by footprint on sample""" -class SampleRotation(sciline.Scope[Run, sc.Variable], sc.Variable): - """The rotation of the sample / the reference sample""" +WavelengthResolution = NewType('WavelengthResolution', sc.Variable) +AngularResolution = NewType('AngularResolution', sc.Variable) +SampleSizeResolution = NewType('SampleSizeResolution', sc.Variable) class BeamlineParams(sciline.Scope[Run, dict], dict): @@ -55,21 +44,34 @@ class BeamlineParams(sciline.Scope[Run, dict], dict): 'SpecularReflectionCoordTransformGraph', dict ) -QDataWithResolutions = NewType('QDataWithResolutions', sc.DataArray) -CorrectedQData = TypeVar('CorrectedQData', QData[Reference], QDataWithResolutions) +CalibratedReference = NewType('CalibratedReference', sc.DataArray) +HistogramContent = TypeVar( + 'HistogramContent', Sample, Reference, CalibratedReference, AngularResolution +) -class HistogrammedByQ(sciline.Scope[CorrectedQData, sc.DataArray], sc.DataArray): - """Histogrammmed by Q. Either reference data or sample data with resolutions.""" +class Histogrammed(sciline.Scope[HistogramContent, sc.DataArray], sc.DataArray): + """Histogrammmed by Q and detector_number""" -Normalizable = TypeVar( - 'Normalizable', HistogrammedByQ[QDataWithResolutions], CalibratedReference -) +CalibratedRun = TypeVar('CalibratedRun', CalibratedReference, Sample) -class NormalizedData(sciline.Scope[Normalizable, sc.DataArray], sc.DataArray): - """Normalized histogramm by Q.""" +class Normalized(sciline.Scope[CalibratedRun, sc.DataArray], sc.DataArray): + """Normalized histogram""" NormalizedIOverQ = NewType('NormalizedIOverQ', sc.DataArray) + + +''' Parameters for the workflow ''' + +QBins = NewType('QBins', sc.Variable) + + +class SampleRotation(sciline.Scope[Run, sc.Variable], sc.Variable): + """The rotation of the sample / the reference sample""" + + +class Filename(sciline.Scope[Run, str], str): + """Filename of the raw data""" From 50deaae3967daa9df0f8ebb870ebe7c4eb948211 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 09:41:40 +0200 Subject: [PATCH 08/18] Make supermirror parameter of the pipeline --- docs/examples/amor.ipynb | 3 +- src/essreflectometry/amor/__init__.py | 14 ++++++-- src/essreflectometry/amor/calibrations.py | 39 ++++++++--------------- src/essreflectometry/amor/types.py | 13 ++++++++ 4 files changed, 40 insertions(+), 29 deletions(-) create mode 100644 src/essreflectometry/amor/types.py diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb index 07e123b..c171fea 100644 --- a/docs/examples/amor.ipynb +++ b/docs/examples/amor.ipynb @@ -8,7 +8,7 @@ "source": [ "import scipp as sc\n", "import sciline\n", - "from essreflectometry.amor import providers as amor\n", + "from essreflectometry.amor import providers as amor, default_parameters\n", "from essreflectometry.reflectometry import providers as reflectometry\n", "from essreflectometry.reflectometry.types import (\n", " Sample, Reference, Sample, SampleRotation, Filename,\n", @@ -18,6 +18,7 @@ "pipeline = sciline.Pipeline(\n", " amor + reflectometry,\n", " params={\n", + " **default_parameters,\n", " QBins: sc.geomspace(dim='Q', start=0.008, stop=0.075, num=200, unit='1/angstrom'),\n", " SampleRotation[Sample]: sc.scalar(0.7989, unit='deg'),\n", " Filename[Sample]: \"sample.nxs\",\n", diff --git a/src/essreflectometry/amor/__init__.py b/src/essreflectometry/amor/__init__.py index c8bd3e1..5d31332 100644 --- a/src/essreflectometry/amor/__init__.py +++ b/src/essreflectometry/amor/__init__.py @@ -3,9 +3,13 @@ # flake8: noqa: F401 from itertools import chain -from . import calibrations, conversions, load, normalize, resolution, tools -from .beamline import instrument_view_components +import scipp as sc + +from . import beamline, calibrations, conversions, load, normalize, resolution, tools + +# from .beamline import instrument_view_components from .instrument_view import instrument_view +from .types import * providers = list( chain( @@ -17,3 +21,9 @@ beamline.providers, ) ) + +default_parameters = { + Supermirror[MValue]: sc.scalar(5, unit=sc.units.dimensionless), + Supermirror[CriticalEdge]: 0.022 * sc.Unit('1/angstrom'), + Supermirror[Alpha]: sc.scalar(0.25 / 0.088, unit=sc.units.angstrom), +} diff --git a/src/essreflectometry/amor/calibrations.py b/src/essreflectometry/amor/calibrations.py index acbb57e..57c71ad 100644 --- a/src/essreflectometry/amor/calibrations.py +++ b/src/essreflectometry/amor/calibrations.py @@ -4,15 +4,15 @@ # from ..reflectometry import orso from ..reflectometry.types import CalibratedReference, Histogrammed, Reference +from .types import Alpha, CriticalEdge, MValue, Supermirror def supermirror_calibration( data_array: Histogrammed[Reference], + m_value: Supermirror[MValue], + critical_edge: Supermirror[CriticalEdge], + alpha: Supermirror[Alpha], ) -> Histogrammed[CalibratedReference]: - # TODO - m_value: sc.Variable = None - critical_edge: sc.Variable = None - alpha: sc.Variable = None """ Calibrate supermirror measurements @@ -21,23 +21,16 @@ def supermirror_calibration( data_array: Data array to get q-bins/values from. m_value: - m-value for the supermirror. Defaults to 5. + m-value for the supermirror. critical_edge: - Supermirror critical edge. Defaults to 0.022 1/angstrom. + Supermirror critical edge. alpha: - Supermirror alpha value. Defaults to 0.25 / 0.088 angstrom. - + Supermirror alpha value. Returns ------- : Calibrated supermirror measurement. """ - if m_value is None: - m_value = sc.scalar(5, unit=sc.units.dimensionless) - if critical_edge is None: - critical_edge = 0.022 * sc.Unit('1/angstrom') - if alpha is None: - alpha = sc.scalar(0.25 / 0.088, unit=sc.units.angstrom) calibration = calibration_factor(data_array, m_value, critical_edge, alpha) data_array_cal = data_array * calibration # TODO @@ -52,9 +45,9 @@ def supermirror_calibration( def calibration_factor( data_array: sc.DataArray, - m_value: sc.Variable = None, - critical_edge: sc.Variable = None, - alpha: sc.Variable = None, + m_value: sc.Variable, + critical_edge: sc.Variable, + alpha: sc.Variable, ) -> sc.Variable: """ Return the calibration factor for the supermirror. @@ -64,23 +57,17 @@ def calibration_factor( data_array: Data array to get q-bins/values from. m_value: - m-value for the supermirror. Defaults to 5. + m-value for the supermirror. critical_edge: - Supermirror critical edge. Defaults to 0.022 1/angstrom. + Supermirror critical edge. alpha: - Supermirror alpha value. Defaults to 0.25 / 0.088 angstrom. + Supermirror alpha value. Returns ------- : Calibration factor at the midpoint of each Q-bin. """ - if m_value is None: - m_value = sc.scalar(5, unit=sc.units.dimensionless) - if critical_edge is None: - critical_edge = 0.022 * sc.Unit('1/angstrom') - if alpha is None: - alpha = sc.scalar(0.25 / 0.088, unit=sc.units.angstrom) q = data_array.coords['Q'] if data_array.coords.is_edges('Q'): q = sc.midpoints(q) diff --git a/src/essreflectometry/amor/types.py b/src/essreflectometry/amor/types.py new file mode 100644 index 0000000..f4ca226 --- /dev/null +++ b/src/essreflectometry/amor/types.py @@ -0,0 +1,13 @@ +from typing import NewType, TypeVar + +import sciline +import scipp as sc + +MValue = NewType('MValue', str) +CriticalEdge = NewType('CriticalEdge', str) +Alpha = NewType('Alpha', str) +SupermirrorParameter = TypeVar('SupermirrorParameter', MValue, CriticalEdge, Alpha) + + +class Supermirror(sciline.Scope[SupermirrorParameter, sc.Variable], sc.Variable): + """Supermirror parameter scope""" From 2369400924f318c0061095d88d08feb3997ee403 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 11:30:01 +0200 Subject: [PATCH 09/18] Make beamline default parameters into providers --- src/essreflectometry/amor/__init__.py | 10 +++++ src/essreflectometry/amor/beamline.py | 47 +++++++++------------ src/essreflectometry/amor/types.py | 37 ++++++++++++++++ src/essreflectometry/reflectometry/types.py | 4 -- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/essreflectometry/amor/__init__.py b/src/essreflectometry/amor/__init__.py index 5d31332..cc9e419 100644 --- a/src/essreflectometry/amor/__init__.py +++ b/src/essreflectometry/amor/__init__.py @@ -4,7 +4,9 @@ from itertools import chain import scipp as sc +from scipp.constants import g +from ..reflectometry.types import Run from . import beamline, calibrations, conversions, load, normalize, resolution, tools # from .beamline import instrument_view_components @@ -26,4 +28,12 @@ Supermirror[MValue]: sc.scalar(5, unit=sc.units.dimensionless), Supermirror[CriticalEdge]: 0.022 * sc.Unit('1/angstrom'), Supermirror[Alpha]: sc.scalar(0.25 / 0.088, unit=sc.units.angstrom), + BeamSize[Run]: 2.0 * sc.units.mm, + SampleSize[Run]: 10.0 * sc.units.mm, + DetectorSpatialResolution[Run]: 0.0025 * sc.units.m, + Gravity: sc.vector(value=[0, -1, 0]) * g, + ChopperFrequency[Run]: sc.scalar(20 / 3, unit='Hz'), + ChopperPhase[Run]: sc.scalar(-8.0, unit='deg'), + Chopper1Position[Run]: sc.vector(value=[0, 0, -15.5], unit='m'), + Chopper2Position[Run]: sc.vector(value=[0, 0, -14.5], unit='m'), } diff --git a/src/essreflectometry/amor/beamline.py b/src/essreflectometry/amor/beamline.py index 0969afa..133f807 100644 --- a/src/essreflectometry/amor/beamline.py +++ b/src/essreflectometry/amor/beamline.py @@ -1,11 +1,21 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import scipp as sc -from scipp.constants import g from ..choppers import make_chopper from ..logging import log_call -from ..reflectometry.types import BeamlineParams, Run, SampleRotation +from ..reflectometry.types import BeamlineParams, Run +from .types import ( + BeamSize, + Chopper1Position, + Chopper2Position, + ChopperFrequency, + ChopperPhase, + DetectorSpatialResolution, + Gravity, + SampleRotation, + SampleSize, +) @log_call( @@ -13,16 +23,15 @@ ) def make_beamline( sample_rotation: SampleRotation[Run], + beam_size: BeamSize[Run], + sample_size: SampleSize[Run], + detector_spatial_resolution: DetectorSpatialResolution[Run], + gravity: Gravity, + chopper_frequency: ChopperFrequency[Run], + chopper_phase: ChopperPhase[Run], + chopper_1_position: Chopper1Position[Run], + chopper_2_position: Chopper2Position[Run], ) -> BeamlineParams[Run]: - # TODO - beam_size: sc.Variable = None - sample_size: sc.Variable = None - detector_spatial_resolution: sc.Variable = None - gravity: sc.Variable = None - chopper_frequency: sc.Variable = None - chopper_phase: sc.Variable = None - chopper_1_position: sc.Variable = None - chopper_2_position: sc.Variable = None """ Amor beamline components. @@ -52,22 +61,6 @@ def make_beamline( : A dict. """ - if beam_size is None: - beam_size = 2.0 * sc.units.mm - if sample_size is None: - sample_size = 10.0 * sc.units.mm - if detector_spatial_resolution is None: - detector_spatial_resolution = 0.0025 * sc.units.m - if gravity is None: - gravity = sc.vector(value=[0, -1, 0]) * g - if chopper_frequency is None: - chopper_frequency = sc.scalar(20 / 3, unit='Hz') - if chopper_phase is None: - chopper_phase = sc.scalar(-8.0, unit='deg') - if chopper_1_position is None: - chopper_1_position = sc.vector(value=[0, 0, -15.5], unit='m') - if chopper_2_position is None: - chopper_2_position = sc.vector(value=[0, 0, -14.5], unit='m') beamline = { 'sample_rotation': sample_rotation, 'beam_size': beam_size, diff --git a/src/essreflectometry/amor/types.py b/src/essreflectometry/amor/types.py index f4ca226..415375d 100644 --- a/src/essreflectometry/amor/types.py +++ b/src/essreflectometry/amor/types.py @@ -3,6 +3,8 @@ import sciline import scipp as sc +from ..reflectometry.types import Run + MValue = NewType('MValue', str) CriticalEdge = NewType('CriticalEdge', str) Alpha = NewType('Alpha', str) @@ -11,3 +13,38 @@ class Supermirror(sciline.Scope[SupermirrorParameter, sc.Variable], sc.Variable): """Supermirror parameter scope""" + + +class SampleRotation(sciline.Scope[Run, sc.Variable], sc.Variable): + """The rotation of the sample / the reference sample""" + + +class BeamSize(sciline.Scope[Run, sc.Variable], sc.Variable): + """parameter scope""" + + +class DetectorSpatialResolution(sciline.Scope[Run, sc.Variable], sc.Variable): + """parameter scope""" + + +class SampleSize(sciline.Scope[Run, sc.Variable], sc.Variable): + """parameter scope""" + + +Gravity = NewType('Gravity', sc.Variable) + + +class ChopperFrequency(sciline.Scope[Run, sc.Variable], sc.Variable): + """parameter scope""" + + +class ChopperPhase(sciline.Scope[Run, sc.Variable], sc.Variable): + """parameter scope""" + + +class Chopper1Position(sciline.Scope[Run, sc.Variable], sc.Variable): + """parameter scope""" + + +class Chopper2Position(sciline.Scope[Run, sc.Variable], sc.Variable): + """parameter scope""" diff --git a/src/essreflectometry/reflectometry/types.py b/src/essreflectometry/reflectometry/types.py index 6c66e44..94ebd59 100644 --- a/src/essreflectometry/reflectometry/types.py +++ b/src/essreflectometry/reflectometry/types.py @@ -69,9 +69,5 @@ class Normalized(sciline.Scope[CalibratedRun, sc.DataArray], sc.DataArray): QBins = NewType('QBins', sc.Variable) -class SampleRotation(sciline.Scope[Run, sc.Variable], sc.Variable): - """The rotation of the sample / the reference sample""" - - class Filename(sciline.Scope[Run, str], str): """Filename of the raw data""" From 2d0506d5591cccdc12084fef289dbe8aa7de3575 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 14:14:20 +0200 Subject: [PATCH 10/18] Simplify graph. Specialize normalization for sample and reference. --- src/essreflectometry/amor/calibrations.py | 2 +- src/essreflectometry/amor/normalize.py | 9 ++---- src/essreflectometry/amor/resolution.py | 3 +- .../reflectometry/conversions.py | 21 ------------- .../reflectometry/corrections.py | 30 +++++++++++++++---- src/essreflectometry/reflectometry/types.py | 10 ++----- 6 files changed, 30 insertions(+), 45 deletions(-) diff --git a/src/essreflectometry/amor/calibrations.py b/src/essreflectometry/amor/calibrations.py index 57c71ad..38f95c4 100644 --- a/src/essreflectometry/amor/calibrations.py +++ b/src/essreflectometry/amor/calibrations.py @@ -12,7 +12,7 @@ def supermirror_calibration( m_value: Supermirror[MValue], critical_edge: Supermirror[CriticalEdge], alpha: Supermirror[Alpha], -) -> Histogrammed[CalibratedReference]: +) -> CalibratedReference: """ Calibrate supermirror measurements diff --git a/src/essreflectometry/amor/normalize.py b/src/essreflectometry/amor/normalize.py index 024498f..79340b4 100644 --- a/src/essreflectometry/amor/normalize.py +++ b/src/essreflectometry/amor/normalize.py @@ -3,17 +3,12 @@ import scipp as sc # from ..reflectometry import orso -from ..reflectometry.types import ( - CalibratedReference, - Normalized, - NormalizedIOverQ, - Sample, -) +from ..reflectometry.types import Normalized, NormalizedIOverQ, Reference, Sample def normalize_by_supermirror( sample: Normalized[Sample], - supermirror: Normalized[CalibratedReference], + supermirror: Normalized[Reference], ) -> NormalizedIOverQ: """ Normalize the sample measurement by the (ideally calibrated) supermirror. diff --git a/src/essreflectometry/amor/resolution.py b/src/essreflectometry/amor/resolution.py index 8654717..909dfa4 100644 --- a/src/essreflectometry/amor/resolution.py +++ b/src/essreflectometry/amor/resolution.py @@ -4,7 +4,6 @@ from ..reflectometry.types import ( AngularResolution, - Histogrammed, QBins, QData, QStd, @@ -143,7 +142,7 @@ def _angular_resolution( def sigma_Q( - angular_resolution: Histogrammed[AngularResolution], + angular_resolution: AngularResolution, wavelength_resolution: WavelengthResolution, sample_size_resolution: SampleSizeResolution, q_bins: QBins, diff --git a/src/essreflectometry/reflectometry/conversions.py b/src/essreflectometry/reflectometry/conversions.py index 68cc602..c37cd04 100644 --- a/src/essreflectometry/reflectometry/conversions.py +++ b/src/essreflectometry/reflectometry/conversions.py @@ -7,7 +7,6 @@ # from . import orso from .types import ( - AngularResolution, FootprintCorrected, Histogrammed, QBins, @@ -249,29 +248,9 @@ def sum_bins(data_array: QData[Run]) -> Histogrammed[Run]: return Histogrammed[Run](data_array.bins.sum()) -def aggregate_resolution_in_bins( - angular_resolution: AngularResolution, -) -> Histogrammed[AngularResolution]: - """ - Propagate the maximum resolution. - - Parameters - ---------- - angular_resolution: - Angular resolution for each Q. - - Returns - ------- - : - Max of angular resolution over detectors. - """ - return Histogrammed[AngularResolution](angular_resolution.max('detector_number')) - - providers = [ tof_to_wavelength, wavelength_to_theta, theta_to_q, sum_bins, - aggregate_resolution_in_bins, ] diff --git a/src/essreflectometry/reflectometry/corrections.py b/src/essreflectometry/reflectometry/corrections.py index f539d9d..6197122 100644 --- a/src/essreflectometry/reflectometry/corrections.py +++ b/src/essreflectometry/reflectometry/corrections.py @@ -7,11 +7,13 @@ # from . import orso from .types import ( - CalibratedRun, + CalibratedReference, FootprintCorrected, Histogrammed, Normalized, + Reference, Run, + Sample, ThetaData, ) @@ -47,9 +49,21 @@ def footprint_correction(data_array: ThetaData[Run]) -> FootprintCorrected[Run]: return FootprintCorrected[Run](data_array_fp_correction) -def normalize_by_counts( - data_array: Histogrammed[CalibratedRun], -) -> Normalized[CalibratedRun]: +def normalize_sample_by_counts( + data_array: Histogrammed[Sample], +) -> Normalized[Sample]: + return Normalized[Sample](_normalize_by_counts(data_array)) + + +def normalize_reference_by_counts( + data_array: CalibratedReference, +) -> Normalized[Reference]: + return Normalized[Reference](_normalize_by_counts(data_array)) + + +def _normalize_by_counts( + data_array: sc.DataArray, +) -> sc.DataArray: """ Normalize the bin-summed data by the total number of counts. If the data has variances, a check is performed to ensure that the counts in each @@ -88,7 +102,7 @@ def normalize_by_counts( # norm.attrs['orso'].value.reduction.corrections += ['total counts'] # except KeyError: # orso.not_found_warning() - return Normalized[CalibratedRun](norm) + return norm def beam_on_sample(beam_size: sc.Variable, theta: sc.Variable) -> sc.Variable: @@ -110,4 +124,8 @@ def beam_on_sample(beam_size: sc.Variable, theta: sc.Variable) -> sc.Variable: return beam_size / sc.sin(theta) -providers = [footprint_correction, normalize_by_counts] +providers = [ + footprint_correction, + normalize_sample_by_counts, + normalize_reference_by_counts, +] diff --git a/src/essreflectometry/reflectometry/types.py b/src/essreflectometry/reflectometry/types.py index 94ebd59..6d8ade2 100644 --- a/src/essreflectometry/reflectometry/types.py +++ b/src/essreflectometry/reflectometry/types.py @@ -45,19 +45,13 @@ class BeamlineParams(sciline.Scope[Run, dict], dict): ) CalibratedReference = NewType('CalibratedReference', sc.DataArray) -HistogramContent = TypeVar( - 'HistogramContent', Sample, Reference, CalibratedReference, AngularResolution -) -class Histogrammed(sciline.Scope[HistogramContent, sc.DataArray], sc.DataArray): +class Histogrammed(sciline.Scope[Run, sc.DataArray], sc.DataArray): """Histogrammmed by Q and detector_number""" -CalibratedRun = TypeVar('CalibratedRun', CalibratedReference, Sample) - - -class Normalized(sciline.Scope[CalibratedRun, sc.DataArray], sc.DataArray): +class Normalized(sciline.Scope[Run, sc.DataArray], sc.DataArray): """Normalized histogram""" From cf4f6fc25164e8c6cc37a25e8a7012df1b2d8cd2 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 14:23:04 +0200 Subject: [PATCH 11/18] Comment orso related --- src/essreflectometry/amor/load.py | 53 ++++++++++++++++--------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/essreflectometry/amor/load.py b/src/essreflectometry/amor/load.py index 23441ce..4116f2a 100644 --- a/src/essreflectometry/amor/load.py +++ b/src/essreflectometry/amor/load.py @@ -1,8 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from datetime import datetime from pathlib import Path -from typing import Any, Union +from typing import Union import scipp as sc import scippnexus as snx @@ -30,8 +29,9 @@ def _tof_correction(data: sc.DataArray, dim: str = 'tof') -> sc.DataArray: : ToF corrected data array. """ - if 'orso' in data.attrs: - data.attrs['orso'].value.reduction.corrections += ['chopper ToF correction'] + # TODO + # if 'orso' in data.attrs: + # data.attrs['orso'].value.reduction.corrections += ['chopper ToF correction'] tof_unit = data.bins.coords[dim].bins.unit tau = sc.to_unit( 1 / (2 * data.coords['source_chopper_2'].value['frequency'].data), @@ -138,28 +138,29 @@ def load(filename: Filename[Run], beamline: BeamlineParams[Run]) -> Raw[Run]: return data -def populate_orso(orso: Any, data: sc.DataGroup, filename: str) -> Any: - """ - Populate the Orso object, by calling the :code:`base_orso` and adding data from the - file. - - Parameters - ---------- - orso: - The orso object to be populated by additional information from the loaded file. - data: - Data group to source information from. - Should mimic the structure of the NeXus file. - filename: - Path of the file to load. - """ - orso.data_source.experiment.title = data['title'] - orso.data_source.experiment.instrument = data['name'] - orso.data_source.experiment.start_date = datetime.strftime( - datetime.strptime(data['start_time'][:-3], '%Y-%m-%dT%H:%M:%S.%f'), - '%Y-%m-%d', - ) - orso.data_source.measurement.data_files = [filename] +# TODO +# def populate_orso(orso: Any, data: sc.DataGroup, filename: str) -> Any: +# """ +# Populate the Orso object, by calling the :code:`base_orso` and adding data from the +# file. +# +# Parameters +# ---------- +# orso: +# The orso object to be populated by additional information from the loaded file. +# data: +# Data group to source information from. +# Should mimic the structure of the NeXus file. +# filename: +# Path of the file to load. +# """ +# orso.data_source.experiment.title = data['title'] +# orso.data_source.experiment.instrument = data['name'] +# orso.data_source.experiment.start_date = datetime.strftime( +# datetime.strptime(data['start_time'][:-3], '%Y-%m-%dT%H:%M:%S.%f'), +# '%Y-%m-%d', +# ) +# orso.data_source.measurement.data_files = [filename] providers = [load] From 96df949dc02b6b567503a2e4e007f4350f33bb8c Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 14:30:06 +0200 Subject: [PATCH 12/18] docs: add comments describing workflow parameters --- src/essreflectometry/amor/types.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/essreflectometry/amor/types.py b/src/essreflectometry/amor/types.py index 415375d..df9c6ac 100644 --- a/src/essreflectometry/amor/types.py +++ b/src/essreflectometry/amor/types.py @@ -5,6 +5,8 @@ from ..reflectometry.types import Run +# TODO What do they mean? +# Supermirror parameters MValue = NewType('MValue', str) CriticalEdge = NewType('CriticalEdge', str) Alpha = NewType('Alpha', str) @@ -12,39 +14,41 @@ class Supermirror(sciline.Scope[SupermirrorParameter, sc.Variable], sc.Variable): - """Supermirror parameter scope""" + """Supermirror parameter scope.""" class SampleRotation(sciline.Scope[Run, sc.Variable], sc.Variable): - """The rotation of the sample / the reference sample""" + """The rotation of the sample / the reference sample.""" class BeamSize(sciline.Scope[Run, sc.Variable], sc.Variable): - """parameter scope""" + """FWHM of the neutron beam.""" class DetectorSpatialResolution(sciline.Scope[Run, sc.Variable], sc.Variable): - """parameter scope""" + # TODO + """Don't know what this is.""" class SampleSize(sciline.Scope[Run, sc.Variable], sc.Variable): - """parameter scope""" + # TODO is this radius or total length? + """Size of the sample.""" Gravity = NewType('Gravity', sc.Variable) class ChopperFrequency(sciline.Scope[Run, sc.Variable], sc.Variable): - """parameter scope""" + """Frequency of the choppers used in the run.""" class ChopperPhase(sciline.Scope[Run, sc.Variable], sc.Variable): - """parameter scope""" + """Phase of the choppers in the run.""" class Chopper1Position(sciline.Scope[Run, sc.Variable], sc.Variable): - """parameter scope""" + """Position of the first chopper relative the source of the beam.""" class Chopper2Position(sciline.Scope[Run, sc.Variable], sc.Variable): - """parameter scope""" + """Position of the second chopper relative to the source of the beam.""" From 34dcbd329424fe23cbe667d52aae76bf83ce8d77 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 14:40:01 +0200 Subject: [PATCH 13/18] fix example --- docs/examples/amor.ipynb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb index c171fea..d67ab9f 100644 --- a/docs/examples/amor.ipynb +++ b/docs/examples/amor.ipynb @@ -11,9 +11,10 @@ "from essreflectometry.amor import providers as amor, default_parameters\n", "from essreflectometry.reflectometry import providers as reflectometry\n", "from essreflectometry.reflectometry.types import (\n", - " Sample, Reference, Sample, SampleRotation, Filename,\n", - " ThetaData, QBins, NormalizedIOverQ, QStd\n", + " Sample, Reference, Sample, Filename,\n", + " QBins, NormalizedIOverQ, QStd\n", ")\n", + "from essreflectometry.amor.types import SampleRotation\n", "\n", "pipeline = sciline.Pipeline(\n", " amor + reflectometry,\n", @@ -27,7 +28,7 @@ " }\n", ")\n", "\n", - "pipeline.visualize((NormalizedIOverQ, QStd))" + "pipeline.visualize((NormalizedIOverQ, QStd), graph_attr={'rankdir': 'LR'})" ] }, { From 52ac457da103630d7795384b4894129bf22bf848 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 14:41:52 +0200 Subject: [PATCH 14/18] fix no need to rename normalization function --- src/essreflectometry/reflectometry/corrections.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/essreflectometry/reflectometry/corrections.py b/src/essreflectometry/reflectometry/corrections.py index 6197122..e7f73b4 100644 --- a/src/essreflectometry/reflectometry/corrections.py +++ b/src/essreflectometry/reflectometry/corrections.py @@ -52,16 +52,16 @@ def footprint_correction(data_array: ThetaData[Run]) -> FootprintCorrected[Run]: def normalize_sample_by_counts( data_array: Histogrammed[Sample], ) -> Normalized[Sample]: - return Normalized[Sample](_normalize_by_counts(data_array)) + return Normalized[Sample](normalize_by_counts(data_array)) def normalize_reference_by_counts( data_array: CalibratedReference, ) -> Normalized[Reference]: - return Normalized[Reference](_normalize_by_counts(data_array)) + return Normalized[Reference](normalize_by_counts(data_array)) -def _normalize_by_counts( +def normalize_by_counts( data_array: sc.DataArray, ) -> sc.DataArray: """ From 0dc7266c174ed259d47fa24932f9a5e23b15d877 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 14:46:10 +0200 Subject: [PATCH 15/18] test: disable orso test --- tests/reflectometry/corrections_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/reflectometry/corrections_test.py b/tests/reflectometry/corrections_test.py index 98924e1..044b5fc 100644 --- a/tests/reflectometry/corrections_test.py +++ b/tests/reflectometry/corrections_test.py @@ -46,6 +46,8 @@ def test_normalize_by_counts_fails_when_ncounts_is_too_small(): _ = corrections.normalize_by_counts(array) +# TODO +@pytest.mark.skip(reason="Orso disabled for now.") def test_normalize_by_counts_orso(): """ Tests the corrections.normalize_by_counts function From 302892aec92c4551b04c77ecf7c81c62c17a087b Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 15:50:37 +0200 Subject: [PATCH 16/18] docs: add better plot and some text to the notebook example --- docs/examples/amor.ipynb | 47 ++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb index d67ab9f..96d8d0a 100644 --- a/docs/examples/amor.ipynb +++ b/docs/examples/amor.ipynb @@ -37,8 +37,8 @@ "metadata": {}, "outputs": [], "source": [ - "normalized = pipeline.compute(NormalizedIOverQ)\n", - "normalized.plot(norm='log') + normalized.mean('detector_number').plot(norm='log')\n" + "# Compute I over Q and the standard deviation of Q\n", + "ioq, qstd = pipeline.compute((NormalizedIOverQ, QStd)).values()" ] }, { @@ -47,14 +47,24 @@ "metadata": {}, "outputs": [], "source": [ - "# Diagnostics plot\n", - "(pipeline.compute(ThetaData[Sample])\n", - " .bins.concat('detector_number')\n", - " .hist(\n", - " theta=sc.linspace(dim='theta', start=0.0, stop=1.2, num=165, unit='deg').to(unit='rad'),\n", - " wavelength=sc.linspace(dim='wavelength', start=0, stop=15.0, num=165, unit='angstrom'),\n", - " )\n", - " .plot())\n" + "import matplotlib.pyplot as plt\n", + "\n", + "fig = plt.figure(figsize=(5, 7))\n", + "ax1 = fig.add_axes([0, 0.55, 1.0, 0.45])\n", + "ax2 = fig.add_axes([0, 0.0, 1.0, 0.45])\n", + "cax = fig.add_axes([1.05, 0.55, 0.03, 0.45])\n", + "fig1 = ioq.plot(norm='log', ax=ax1, cax=cax, grid=True)\n", + "fig2 = ioq.mean('detector_number').plot(norm='log', ax=ax2, grid=True)\n", + "fig1.canvas.xrange = fig2.canvas.xrange\n", + "fig1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make a $(\\lambda, \\theta)$ map\n", + "A good sanity check is to create a two-dimensional map of the counts in $\\lambda$ and $\\theta$ bins. To achieve this, we request the `ThetaData` from the pipeline. In the graph above we can see that `WavelengthData` is required to compute `ThetaData`, therefore it is also present in `ThetaData` so we don't need to require it separately." ] }, { @@ -63,8 +73,21 @@ "metadata": {}, "outputs": [], "source": [ - "res = pipeline.compute((NormalizedIOverQ, QStd))\n", - "res[QStd].plot()" + "from essreflectometry.reflectometry.types import ThetaData\n", + "pipeline.compute(ThetaData[Sample])\\\n", + " .bins.concat('detector_number')\\\n", + " .hist(\n", + " theta=sc.linspace(dim='theta', start=0.0, stop=1.2, num=165, unit='deg').to(unit='rad'),\n", + " wavelength=sc.linspace(dim='wavelength', start=0, stop=15.0, num=165, unit='angstrom'),\n", + " )\\\n", + " .plot()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This plot can be used to check if the value of the sample rotation angle $\\omega$ is correct. The bright triangles should be pointing back to the origin $\\lambda = \\theta = 0$." ] } ], From 43566e8455af4d473d8b0d723d36a913e7600531 Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Tue, 24 Oct 2023 16:08:36 +0200 Subject: [PATCH 17/18] docs: restructure and add some more context --- docs/examples/amor.ipynb | 68 +++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/docs/examples/amor.ipynb b/docs/examples/amor.ipynb index 96d8d0a..41cd07e 100644 --- a/docs/examples/amor.ipynb +++ b/docs/examples/amor.ipynb @@ -1,5 +1,16 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Divergent data reduction for Amor\n", + "\n", + "In this notebook, we will look at how to use the `essreflectometry` package with Sciline, for reflectometry data collected from the PSI instrument [Amor](https://www.psi.ch/en/sinq/amor) in [divergent beam mode](https://www.psi.ch/en/sinq/amor/selene).\n", + "\n", + "We will begin by importing the modules that are necessary for this notebook." + ] + }, { "cell_type": "code", "execution_count": null, @@ -8,26 +19,45 @@ "source": [ "import scipp as sc\n", "import sciline\n", - "from essreflectometry.amor import providers as amor, default_parameters\n", - "from essreflectometry.reflectometry import providers as reflectometry\n", - "from essreflectometry.reflectometry.types import (\n", - " Sample, Reference, Sample, Filename,\n", - " QBins, NormalizedIOverQ, QStd\n", - ")\n", - "from essreflectometry.amor.types import SampleRotation\n", - "\n", + "from essreflectometry.amor import providers, default_parameters\n", + "from essreflectometry.reflectometry.types import *\n", + "from essreflectometry.amor.types import SampleRotation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "params={\n", + " **default_parameters,\n", + " QBins: sc.geomspace(dim='Q', start=0.008, stop=0.075, num=200, unit='1/angstrom'),\n", + " SampleRotation[Sample]: sc.scalar(0.7989, unit='deg'),\n", + " Filename[Sample]: \"sample.nxs\",\n", + " SampleRotation[Reference]: sc.scalar(0.8389, unit='deg'),\n", + " Filename[Reference]: \"reference.nxs\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "pipeline = sciline.Pipeline(\n", - " amor + reflectometry,\n", - " params={\n", - " **default_parameters,\n", - " QBins: sc.geomspace(dim='Q', start=0.008, stop=0.075, num=200, unit='1/angstrom'),\n", - " SampleRotation[Sample]: sc.scalar(0.7989, unit='deg'),\n", - " Filename[Sample]: \"sample.nxs\",\n", - " SampleRotation[Reference]: sc.scalar(0.8389, unit='deg'),\n", - " Filename[Reference]: \"reference.nxs\",\n", - " }\n", - ")\n", - "\n", + " providers,\n", + " params=params\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "pipeline.visualize((NormalizedIOverQ, QStd), graph_attr={'rankdir': 'LR'})" ] }, From 3d32c6ac889ffc70dde2f770259cdbf79b40753a Mon Sep 17 00:00:00 2001 From: Johannes Kasimir Date: Wed, 25 Oct 2023 09:19:20 +0200 Subject: [PATCH 18/18] fix: include providers --- src/essreflectometry/amor/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/essreflectometry/amor/__init__.py b/src/essreflectometry/amor/__init__.py index cc9e419..d4122e7 100644 --- a/src/essreflectometry/amor/__init__.py +++ b/src/essreflectometry/amor/__init__.py @@ -6,6 +6,7 @@ import scipp as sc from scipp.constants import g +from ..reflectometry import providers as reflectometry_providers from ..reflectometry.types import Run from . import beamline, calibrations, conversions, load, normalize, resolution, tools @@ -15,6 +16,7 @@ providers = list( chain( + reflectometry_providers, load.providers, calibrations.providers, conversions.providers,