Masking detectors from a script

If an algorithm or script works on a spectrum-by-spectrum basis it might want to mask certain spectra in the output if the input has zero counts, if a fit doesn’t converge, etc.

I note that in
there’s a function “maskDetectors”, but this seems to just run the algorithm MaskDetectors() and needs the name of the workspace to do anything. At that point in my algorithm the workspace is only known by a pointer returned from WorkspaceFactory.create(). Do I need to do self.setProperty(“OutputWorkspace”,ows) then go back and find out its name and then run MaskDetectors?

Meanwhile in
there’s a function isMasked() but no corresponding setMask().

Or have I overlooked something?

Also a simple MaskDetectorsIfZero() and/or MaskDetectorsWithInfOrNaN() which work on any workspace and don’t assume technique-specific calibration files would be very useful.

Hi James,

Unfortunately the way the masking works is a little cumbersome at the moment. Improvements to it have been in the pipeline for a while but we’ve yet to come to an agreement with many parties on exactly what an improved system should do.

To answer your last point first, we do have the FindDetectorsOutsideLimits algorithm that can be used in conjunction with MaskDetectors by feeding the output mask workspace from FindDetectorsOutsideLimits to MaskDetectors. As you say though, a good tidy up would be to have a MaskIfDetectorsOutsideLimits-type algorithm. We can look into that.

For your first use case where you have a pointer to the workspace then you’ll have to run the MaskDetectors algorithm manually, e.g.

ws = WorkspaceFactory.create(10,10,10)
masker = AlgorithmFactory.createUnmanaged("MaskDetectors")
masker.setChild(True) # doesn't need a name
masker.setProperty("Workspace", ws) 
workspaceIndex = 0
masker.setProperty("WorkspaceIndexList", [workspaceIndex]) # or the appropriate index
# this is always an in place operation so no need to retrieve the output
print ws.getDetector( workspaceIndex ).isMasked()

Thanks. FindDetectorsOutsideLimits is just what I wanted, but it isn’t referenced in the documentation for MaskDetectors or in Category:Masking. Keeping the “find bad” and “mask” operations separate can be useful if we have an intermittent fault and want to mask particular detectors throughout a complete experiment for consistency, or if it’s only possible to declare a detector “bad” from calibration data rather than from the real sample.

As for masking from a script: that code does work though it’s AlgorithmManager.createUnmanaged (not AlgorithmFactory).

A few other observations:

  1. If my script creates the new workspace based on the old one, to keep instrument association, logs, etc, with ows=WorkspaceFactory.create(iws,NVectors=iws.getNumberHistograms(),XLength=xl,YLength=yl)
    the masking flags are preserved.
  2. There is no matching way to un-mask a detector if the script now has valid data to put in its histogram, for example from a different run or by interpolating from the neighbouring detectors. Except…
  3. LoadInstrument() to load a different IDF (XML file) clears the masking flags but obviously doesn’t/can’t restore the data that had been zeroed! Is that by design such that an IDF could specify detectors to mask?

I see there’s now “MaskDetectorsIf”. However I’d like it to work in a predictable manner if there are detectors showing NaN, for example if I’m taking the ratio of two runs and the dead detectors now give 0/0 = NaN. At present the NaNs always pass the test and are not masked.
The reason this time is that I wanted to do Instrument View of this rato workspace and it doesn’t even open a window (in Workbench 4.2) if there are NaNs in the workspace. The above recipe, with a temporary masking workspace, did mask the bad spectra.

I can see that MaskDetectorsIf doesn’t replace NaN values.

Would this solution suffice? If you execute the algorithm “ReplaceSpecialValues” and set NaNValue and InfinityValue to 0, that should mean that the Ratio Workspace is able to be Viewed in Instrument Viewer.

I understand this is just changing those values to 0 and not exactly masking them, but is this okay for your purposes?

It works, but once I’ve manually rescaled the colour bar to see the majority of spectra the NaNs are now indistinguishable from outliers with valid data.
The solution here might be to fix Instrument Viewer to treat NaNs or Infs the same as masked detectors and colour them grey. I note detectors which have no associated spectrum are also grey (e.g. after CropWorkspace).
A useful enhancement might be to have the option to completely hide the missing / masked / NaN detectors instead of colouring them in grey.

While a current work around could involve something like this:

ws_fix = ReplaceSpecialValues(ws,NaNValue = -111, Infinityvalue = -111)
MaskDetectorsIf(ws_fix, Value = -111)

I have created an issue to Fix Instrument View so that it automaitcally masks and opens correctly with Nan and Inf values!