Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enable user defined sample and container geometry for abs correction #38887

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
59 changes: 55 additions & 4 deletions Framework/PythonInterface/mantid/utils/absorptioncorrutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from mantid.kernel import Logger, Property, PropertyManager
from mantid.simpleapi import (
AbsorptionCorrection,
DefineGaugeVolume,
DeleteWorkspace,
Divide,
Load,
Expand Down Expand Up @@ -284,6 +285,10 @@ def calculate_absorption_correction(
sample_formula,
mass_density,
sample_geometry={},
can_geometry={},
can_material={},
gauge_vol="",
beam_height=Property.EMPTY_DBL,
number_density=Property.EMPTY_DBL,
container_shape="PAC06",
num_wl_bins=1000,
Expand Down Expand Up @@ -323,6 +328,10 @@ def calculate_absorption_correction(
:param sample_formula: Sample formula to specify the Material for absorption correction
:param mass_density: Mass density of the sample to specify the Material for absorption correction
:param sample_geometry: Dictionary to specify the sample geometry for absorption correction
:param can_geometry: Dictionary to specify the container geometry for absorption correction
:param can_material: Dictionary to specify the container material for absorption correction
:param gauge_vol: String in XML form to define the gauge volume, i.e., the sample portion visible to the beam
:param beam_height: Optional beam height to use for absorption correction
:param number_density: Optional number density of sample to be added to the Material for absorption correction
:param container_shape: Shape definition of container, such as PAC06.
:param num_wl_bins: Number of bins for calculating wavelength
Expand All @@ -344,12 +353,26 @@ def calculate_absorption_correction(
material["SampleNumberDensity"] = number_density

environment = {}
if container_shape:
find_env = True
if container_shape or (can_geometry and can_material):
environment["Name"] = "InAir"
environment["Container"] = container_shape
find_env = False
if not (can_geometry and can_material):
environment["Container"] = container_shape

donorWS = create_absorption_input(
filename, props, num_wl_bins, material=material, geometry=sample_geometry, environment=environment, metaws=metaws
filename,
props,
num_wl_bins,
material=material,
geometry=sample_geometry,
can_geometry=can_geometry,
can_material=can_material,
gauge_vol=gauge_vol,
beam_height=beam_height,
environment=environment,
find_environment=find_env,
metaws=metaws,
)

# NOTE: Ideally we want to separate cache related task from calculation,
Expand Down Expand Up @@ -499,6 +522,10 @@ def create_absorption_input(
num_wl_bins=1000,
material={},
geometry={},
can_geometry={},
can_material={},
gauge_vol="",
beam_height=Property.EMPTY_DBL,
environment={},
find_environment=True,
opt_wl_min=0,
Expand All @@ -513,6 +540,10 @@ def create_absorption_input(
:param num_wl_bins: The number of wavelength bins used for absorption correction
:param material: Optional material to use in SetSample
:param geometry: Optional geometry to use in SetSample
:param can_geometry: Optional container geometry to use in SetSample
:param can_material: Optional container material to use in SetSample
:param gauge_vol: Optional gauge volume definition, i.e., sample portion visible to the beam.
:param beam_height: Optional beam height to define gauge volume
:param environment: Optional environment to use in SetSample
:param find_environment: Optional find_environment to control whether to figure out environment automatically.
:param opt_wl_min: Optional minimum wavelength. If specified, this is used instead of from the props
Expand Down Expand Up @@ -607,11 +638,31 @@ def confirmProps(props):
geometry = {}
if not environment:
environment = {}
if can_geometry and can_material:
environment = {}

# Make sure one is set before calling SetSample
if material or geometry or environment:
mantid.simpleapi.SetSampleFromLogs(
InputWorkspace=absName, Material=material, Geometry=geometry, Environment=environment, FindEnvironment=find_environment
InputWorkspace=absName,
Material=material,
Geometry=geometry,
ContainerGeometry=can_geometry,
ContainerMaterial=can_material,
Environment=environment,
FindEnvironment=find_environment,
)

if beam_height != Property.EMPTY_DBL and not gauge_vol:
gauge_vol = """<cuboid id="shape">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strange in a way similar to the DefineGaugeVolume user docs. I think it is configured that

  • front-back is x-dimension
  • left/right is y-dimension (beam height)
  • top/bottom is z-dimension

It would be good to also add in the beam width for the dimension that has that

Adding a comment explaining that will help future people who see this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DefineGaugeVolume user docs is indeed a bit confusing in the explanation of how the gauge volume is defined. Here are several comments,

  1. For the cuboid volume definition, I created an image to demonstrate the idea,
    Cuboid volume definition demo

  2. Ideally, indeed the gauge volume could be defined as above a a cuboid and Mantid then worries about constructing the intersection area between the sample and the defined gauge volume. However, the construction of the intersection area is not implemented yet. So, we cannot go with this route.

  3. However, the gauge volume can be defined as with the same shape as the sample, e.g., cylinder or hollow cylinder and current implementation can meet our need without problems. We do need some further implementation in this PR to define the gauge volume for the sample and container separately.

  4. The implementation for SampleOnly and SampleAndContainer method is straightforward -- just define the gauge volume twice here

  5. For the PaalmanPingsAbsorptionCorrection method, I am not sure how to do that -- the same principle applies but I am not so familiar with the CPP codes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At ISIS we are also interested in starting to use DefineGaugeVolume with other attenuation algorithms such as MonteCarloAbsoption for use on our engineering beamline ENGIN-X. For us we would need to consider the case of when the gauge volume is not wholly occupied by the sample, both for attenuation correction and normalising by the illuminated sample volume. If you do implement this let us know! Not sure how this fits in with your plans? Happy to discuss!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. I will keep you updated about the implementation. We do plan to do the gauge volume definition for both the absorption correction and normalization purpose. Currently I am working on this and the PR here is part of the work. Maybe we need another PR for working with implementation for PaalmanPingsAbsorptionCorrection which may need the help from @peterfpeterson and his team since I am not so familiar the C++ code and the code architecture there^_^ Anyhow, I will keep you in the loop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also the algorithm SetBeam which may be appropriate for these calculations. I'm still in progress on understanding the effect of it.

<left-front-bottom-point x="0.02" y="-{0:4.2F}" z="-0.02" />
<left-front-top-point x="0.02" y="-{0:4.2F}" z="0.02" />
<left-back-bottom-point x="-0.02" y="-{0:4.2F}" z="-0.02" />
<right-front-bottom-point x="0.02" y="{0:4.2F}" z="-0.02" />
</cuboid>"""
gauge_vol = gauge_vol.format(beam_height / 2.0)

if gauge_vol:
DefineGaugeVolume(absName, gauge_vol)

return absName
18 changes: 18 additions & 0 deletions Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,16 @@ def PyInit(self):
)
self.declareProperty("SampleFormula", "", doc="Chemical formula of the sample")
self.declareProperty("SampleGeometry", {}, doc="A dictionary of geometry parameters for the sample.")
self.declareProperty("ContainerGeometry", {}, doc="A dictionary of geometry parameters for the container.")
self.declareProperty("ContainerMaterial", {}, doc="A dictionary of material parameters for the container.")
self.declareProperty(
"GaugeVolume", "", "A string in XML form for gauge volume definition indicating sample portion visible to the beam."
)
self.declareProperty(
"BeamHeight",
defaultValue=Property.EMPTY_DBL,
doc="Height of the neutron beam cross section in cm",
)
self.declareProperty(
"MeasuredMassDensity",
defaultValue=0.1,
Expand Down Expand Up @@ -423,6 +433,10 @@ def PyExec(self): # noqa
self._absMethod = self.getProperty("TypeOfCorrection").value
self._sampleFormula = self.getProperty("SampleFormula").value
self._sampleGeometry = self.getProperty("SampleGeometry").value
self._containerGeometry = self.getProperty("ContainerGeometry").value
self._containerMaterial = self.getProperty("ContainerMaterial").value
self._gaugeVolume = self.getProperty("GaugeVolume").value
self._beamHeight = self.getProperty("BeamHeight").value
self._massDensity = self.getProperty("MeasuredMassDensity").value
self._numberDensity = self.getProperty("SampleNumberDensity").value
self._containerShape = self.getProperty("ContainerShape").value
Expand Down Expand Up @@ -524,6 +538,10 @@ def PyExec(self): # noqa
self._sampleFormula, # Material for absorption correction
self._massDensity, # Mass density of the sample
self._sampleGeometry, # Geometry parameters for the sample
self._containerGeometry, # Geometry parameters for the container
self._containerMaterial, # Material parameters for the container
self._gaugeVolume, # Gauge volume definition
self._beamHeight, # Height of the neutron beam cross section in cm
self._numberDensity, # Optional number density of sample to be added
self._containerShape, # Shape definition of container
self._num_wl_bins, # Number of bins: len(ws.readX(0))-1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Enable user defined sample and container geometry together with the definition of gauge volume to account for the beam size. Implementation made in :ref:`SNSPowderReduction <algm-SNSPowderReduction>` and ``mantid.utils.absorptioncorrutils``.