SNAPWrap is the primary user-facing Python layer for SNAP reduction. Most users
write Mantid Workbench scripts that import SNAPWrap directly; SNAPRed is the
backend engine SNAPWrap prepares requests for and calls.
SNAPWrap owns configuration, calibration lookup, mask preparation, hook
assembly, and output handling. SNAPRed owns the actual reduction computation.
-
Start from the library-first mental model — SNAPWrap is imported from
scripts, usually inside Mantid Workbench. It is not the place to duplicate
reduction algorithms.
Developer conventions:
- Treat SNAPWrap as a library, not a standalone CLI.
- Assume Mantid algorithms and workspace APIs are available.
- Keep reduction computation in SNAPRed, not in SNAPWrap.
- Treat the calibration index as the source of truth.
-
Use reduce() as the primary integration surface — Most user workflows
should pass through snapwrap.utils.reduce().
from snapwrap.utils import reduce
workspace_names = reduce(
runNumber,
binMaskList=[],
pixelMaskIndex='none',
continueNoDifcal=False,
continueNoVan=False,
noNorm=False,
requireSameCycle=True,
focusGroupAllowList=None,
keepUnfocussed=False,
qsp=False,
linBin=0.01,
save=True,
backgroundWSName=None,
attenuationWSName=None,
cisMode=False,
emptyTrash=True,
YMLOverride='none',
verbose=False,
reduceData=True,
)
Internal data flow:
reduce(runNumber)
1. Load YAML defaults (globalParams / YMLOverride)
2. Check difcal and normcal status via snapStateMgr
3. Apply continue-flag policy
4. Build requested hooks (background/attenuation, cheeseMask)
5. Assemble ReductionRequest
6. Call InterfaceController.executeRequest(SNAPRequest)
7. Return workspace names
[CHECKPOINT]: If you are extending a user-facing reduction path, you can
point to the reduce() call and explain which arguments or hooks you are
changing.
-
Handle output names through SNAPWrap helpers instead of string guessing
— SNAPRed workspace names are timestamped internally. When cleanTheTree is
enabled, SNAPWrap creates copies with clean names (no timestamps) and hides
the originals, but the timestamped workspaces remain in the tree and can be
re-exposed if needed.
Timestamped internal naming pattern:
{prefix}_{unit}_{pixelGroup}_{runNumber}_{timestamp}
Clean-tree displayed pattern when cleanTheTree is enabled:
{prefix}_{unit}_{pixelGroup}_{runNumber}
Use snapwrap.io.redObject to parse names programmatically.
| Prefix | Meaning |
|---|
reduced_ | Full calibration path succeeded |
diagnostic_ | Approximation path used because calibration was missing |
-
Use binMaskList and swissCheese through the naming contract — Bin
masks are table workspaces applied by the cheeseMask hook during
PostPreprocessReductionRecipe. Masks are reduction artifacts governed by
sns-snap-sample-environment-reduction-special-cases.
Required naming format:
- Workspace names must follow exactly:
{prefix}-{units}
- Two parts only, separated by a single hyphen.
- The part after the hyphen must be the Mantid unit name (
Wavelength,
dSpacing, TOF, Energy, etc.).
- Nothing can follow the units; the units must be the final part.
- Unit suffixes must match Mantid unit naming exactly (no abbreviations like
wav or dsp).
- Multiple masks in different units can be supplied in one
binMaskList.
Typical usage:
reduce(runNumber, binMaskList=['DAC_notch-Wavelength', 'PE_occlusion-dSpacing'])
SNAPWrap code for artifact construction (see
sns-snap-sample-environment-reduction-special-cases
for when and why to create each artifact type):
- DAC notch bin-mask artifacts: use
snapwrap.maskUtils with diamond UB
matrices.
- Manual bin-mask artifacts extracted from workspace history: use
swissCheese.ExtractFromWorkspaceHistory(...).
-
Resolve calibration state through snapStateMgr, not hardcoded paths
— Use checkCalibrationStatus() to determine whether the run and state have
valid difcal or normcal coverage.
from snapwrap.snapStateMgr import checkCalibrationStatus
status = checkCalibrationStatus(
runNumber,
stateID=None,
isLite=True,
calType="difcal",
requireSameCycle=True,
)
Important outputs:
runIsCalibrated
stateIsCalibrated
latestValidCalibrationDict
statusDetail
The calibration index maps runs to calibration records through appliesTo,
and requireSameCycle=True further restricts matches to the same SNS cycle.
-
Use SEEMeta to branch sample-environment behavior early — SNAPWrap can
extract assembly metadata from an override JSON file or embedded run logs.
Lookup priority:
/IPTS-{ipts}/shared/SEE/SEE{runNumber}.json
- Embedded NeXus log
entry/DASlogs/BL3:SE:SEEMeta:JSON/value
None if absent
Assembly classes include DAC, PE, CylinderCell, and Empty. Use the
extracted assembly type to decide whether to apply DAC notching, PE pixel
masks, or other environment-specific branches before calling reduce().
-
Attach custom behavior through hooks only at valid SNAPRed lifecycle
points — SNAPWrap passes Hook objects into SNAPRequest, and SNAPRed's
HookManager executes them. Lifecycle names are recipe steps in SNAPRed's
reduction engine (e.g., PostPreprocessReductionRecipe).
Built-in hooks assembled by reduce():
BackgroundAttenuationCorrection
cheeseMask
If you add new hooks, verify the lifecycle name against SNAPRed's recipe
lifecycle documentation (see sns-snapred-developer-guide) and remember
that all registered hooks must execute successfully.
-
Use the module surface intentionally — Reach for the right module rather
than adding ad hoc helpers.
| Import | Key exports | When to use |
|---|
snapwrap.utils | reduce(), globalParams(), propagateDifcal() | Main reduction scripts |
snapwrap.io | redObject, exportData() | Workspace parsing and export |
snapwrap.snapStateMgr | checkCalibrationStatus(), SNAPHome | Calibration queries |
snapwrap.maskUtils | Swiss cheese utilities, pixel-mask tools | DAC/PE masking |
snapwrap.SEEMeta.utils | acquireMeta() | Assembly metadata extraction |
snapwrap.SEEMeta.assembly | DAC, PE, CylinderCell, Empty | Assembly objects |
snapwrap.cycleDates | get_cycle_for_run() | Cycle-aware logic |
snapwrap.wrapConfig | WrapConfig | Runtime config loading |
-
Load configuration through the YAML config layer — SNAPWrap uses its
own application.yml for runtime configuration. For access to SNAPRed
configuration (such as instrument.calibration.home), SNAPWrap queries
SNAPRed's application.yml through the SNAPRed interface.
from snapwrap.wrapConfig import WrapConfig
WrapConfig.load()
seeJsonHome = WrapConfig.get("SEE.json.home")
For local testing outside the SNS Analysis Cluster, SNAPWrap relies on
environment setup or direct file paths; SNAPWrap config does not support
YAML override files (SNAPRed config does). Check SNAPWrap documentation for
local development setup options.