Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 17 additions & 5 deletions packages/esssans/docs/user-guide/common/beam-center-finder.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@
"id": "13",
"metadata": {},
"source": [
"The result is the beam center relative to the sample.\n",
"Its component along the beam is the distance from the sample at which the transverse offset was determined, here the distance of the detector panel.\n",
"That distance is part of the result because the same beam direction corresponds to a proportionally smaller transverse offset on a detector closer to the sample.\n",
"\n",
"We can now update our previous figure with the new position of the beam center (pink dot),\n",
"which is clearly in the center of the beam/beam stop."
]
Expand Down Expand Up @@ -449,11 +453,20 @@
"workflow[DimsToKeep] = ()\n",
"workflow[WavelengthMask] = None\n",
"workflow[WavelengthBands] = None\n",
"\n",
"kwargs = dict( # noqa: C408\n",
" workflow=workflow,\n",
" detector=detector['data'],\n",
" norm=workflow.compute(CleanDirectBeam),\n",
")"
")\n",
"\n",
"\n",
"def beam_center(x, y):\n",
" \"\"\"Beam center from transverse offsets, at the distance found by method 1.\"\"\"\n",
" # Transverse offsets define a beam direction only together with the distance from\n",
" # the sample at which they are given. The SANS2D beam runs along Z, so the plane\n",
" # normal to the beam is the XY plane, here at the Z of the center of mass.\n",
" return sc.vector([x, y, com.fields.z.value], unit='m')"
]
},
{
Expand All @@ -474,7 +487,7 @@
"from ess.sans.beam_center_finder import _iofq_in_quadrants\n",
"\n",
"results = _iofq_in_quadrants(\n",
" xy=[0, 0],\n",
" beam_center=beam_center(x=0.0, y=0.0),\n",
" **kwargs,\n",
")"
]
Expand Down Expand Up @@ -541,9 +554,8 @@
"bounds = [(x.min().value, x.max().value), (y.min().value, y.max().value)]\n",
"\n",
"res = minimize(\n",
" sans.beam_center_finder._cost,\n",
" lambda xy: sans.beam_center_finder._cost(beam_center(*xy), **kwargs),\n",
" x0=[0, 0],\n",
" args=tuple(kwargs.values()),\n",
" bounds=bounds,\n",
" method='Powell',\n",
" tol=0.01,\n",
Expand Down Expand Up @@ -590,7 +602,7 @@
"outputs": [],
"source": [
"results = _iofq_in_quadrants(\n",
" xy=[res.x[0], res.x[1]],\n",
" beam_center=beam_center(*res.x),\n",
" **kwargs,\n",
")\n",
"\n",
Expand Down
1 change: 1 addition & 0 deletions packages/esssans/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies = [
"numpy>=1.26.4",
"pandas>=2.1.2",
"plopp>=26.5.0",
"scippneutron>=26.9.1",
]

[project.optional-dependencies]
Expand Down
5 changes: 2 additions & 3 deletions packages/esssans/src/ess/isissans/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import scippneutron as scn
import scippnexus as snx
from ess.sans.types import (
BeamCenter,
DetectorIDs,
DetectorPixelShape,
DetectorPositionOffset,
Expand Down Expand Up @@ -81,9 +80,9 @@ def default_parameters() -> dict:


def to_detector_position_offset(
global_offset: DetectorBankOffset, beam_center: BeamCenter
global_offset: DetectorBankOffset,
) -> DetectorPositionOffset[RunType]:
return DetectorPositionOffset[RunType](global_offset - beam_center)
return DetectorPositionOffset[RunType](global_offset)


def to_monitor_position_offset(
Expand Down
27 changes: 10 additions & 17 deletions packages/esssans/src/ess/isissans/sans2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import scipp as sc
from ess.sans import SansWorkflow
from ess.sans.parameters import typical_outputs
from ess.sans.types import BeamCenter, DetectorMasks, EmptyDetector, SampleRun
from ess.sans.types import DetectorMasks, EmptyDetector, SampleRun

from ess.reduce.workflow import register_workflow

Expand All @@ -25,33 +25,26 @@
"""Sample holder mask"""


def detector_edge_mask(
beam_center: BeamCenter, sample: EmptyDetector[SampleRun]
) -> DetectorEdgeMask:
# These values were determined by hand before the beam center was available.
# We therefore undo the shift introduced by the beam center.
raw_pos = sample.coords['position'] + beam_center
mask_edges = (sc.abs(raw_pos.fields.x) > sc.scalar(0.48, unit='m')) | (
sc.abs(raw_pos.fields.y) > sc.scalar(0.45, unit='m')
def detector_edge_mask(sample: EmptyDetector[SampleRun]) -> DetectorEdgeMask:
pos = sample.coords['position']
mask_edges = (sc.abs(pos.fields.x) > sc.scalar(0.48, unit='m')) | (
sc.abs(pos.fields.y) > sc.scalar(0.45, unit='m')
)
return DetectorEdgeMask(mask_edges)


def sample_holder_mask(
beam_center: BeamCenter,
sample: EmptyDetector[SampleRun],
low_counts_threshold: LowCountThreshold,
) -> SampleHolderMask:
# These values were determined by hand before the beam center was available.
# We therefore undo the shift introduced by the beam center.
raw_pos = sample.coords['position'] + beam_center
pos = sample.coords['position']
summed = sample.hist()
holder_mask = (
(summed.data < low_counts_threshold)
& (raw_pos.fields.x > sc.scalar(0, unit='m'))
& (raw_pos.fields.x < sc.scalar(0.42, unit='m'))
& (raw_pos.fields.y < sc.scalar(0.05, unit='m'))
& (raw_pos.fields.y > sc.scalar(-0.15, unit='m'))
& (pos.fields.x > sc.scalar(0, unit='m'))
& (pos.fields.x < sc.scalar(0.42, unit='m'))
& (pos.fields.y < sc.scalar(0.05, unit='m'))
& (pos.fields.y > sc.scalar(-0.15, unit='m'))
)
return SampleHolderMask(holder_mask)

Expand Down
8 changes: 7 additions & 1 deletion packages/esssans/src/ess/loki/larmor_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,14 @@ def larmor_detector_coord_transform_graph(
*,
sample_position: Position[snx.NXsample, RunType],
source_position: Position[snx.NXsource, RunType],
beam_center: BeamCenter,
gravity: GravityVector,
) -> ElasticCoordTransformGraph[RunType]:
graph = sans_elastic(
correct_for_gravity=correct_for_gravity,
sample_position=sample_position,
source_position=source_position,
beam_center=beam_center,
gravity=gravity,
)
return ElasticCoordTransformGraph[RunType]({**graph, **tof.elastic_Q('tof')})
Expand Down Expand Up @@ -186,5 +188,9 @@ def LokiAtLarmorTutorialWorkflow() -> sciline.Pipeline:
data.loki_tutorial_run_60392()
)
workflow[Filename[EmptyBeamRun]] = str(data.loki_tutorial_run_60392())
workflow[BeamCenter] = sc.vector(value=[-0.02914868, -0.01816138, 0.0], unit='m')
# Beam center determined with `beam_center_from_center_of_mass`, the Z component
# being the distance from the sample at which it was determined.
workflow[BeamCenter] = sc.vector(
value=[-0.02914868, -0.01816138, 4.11610], unit='m'
)
return workflow
Loading