Beispiel #1
0
def sel(sample, const):
    """
    Convert workspace into normalised spin echo units

    Parameters
    ----------
    sample : str
      The name of the workspace to be converted
    const : float
      The spin echo length of a one angstrom neutron in nanometers

    Returns
    -------
    The name of a workspace with the x coordinate in proper spin echo
    units and the y coordinate in log(P/P₀)/λ²
    """
    wtemp = mtd[sample]
    x = wtemp.extractX()
    y = wtemp.extractY()
    e = wtemp.extractE()

    dx = (x[:, 1:] + x[:, :-1]) / 2

    wtemp = ConvertUnits(sample, "SpinEchoLength", EFixed=const)

    wenv = CreateWorkspace(wtemp.extractX(),
                           np.log(y) / dx**2,
                           e / y / dx**2,
                           UnitX="SpinEchoLength",
                           YUnitLabel="Counts")
    RenameWorkspace(wenv, OutputWorkspace=sample + "_sel")
Beispiel #2
0
    def _save(self, runnumber, basename, norm):
        if not self.getProperty("SaveData").value:
            return

        saveDir = self.getProperty("OutputDirectory").value.strip()
        if len(saveDir) <= 0:
            self.log().notice('Using default save location')
            saveDir = os.path.join(
                self.get_IPTS_Local(runnumber), 'shared', 'data')
        self.log().notice('Writing to \'' + saveDir + '\'')

        if norm == 'None':
            SaveNexusProcessed(InputWorkspace='WS_red',
                               Filename=os.path.join(saveDir, 'nexus', basename + '.nxs'))
            SaveAscii(InputWorkspace='WS_red',
                      Filename=os.path.join(saveDir, 'd_spacing', basename + '.dat'))
            ConvertUnits(InputWorkspace='WS_red', OutputWorkspace='WS_tof',
                         Target="TOF", AlignBins=False)
        else:
            SaveNexusProcessed(InputWorkspace='WS_nor',
                               Filename=os.path.join(saveDir, 'nexus', basename + '.nxs'))
            SaveAscii(InputWorkspace='WS_nor',
                      Filename=os.path.join(saveDir, 'd_spacing', basename + '.dat'))
            ConvertUnits(InputWorkspace='WS_nor', OutputWorkspace='WS_tof',
                         Target="TOF", AlignBins=False)

        SaveGSS(InputWorkspace='WS_tof',
                Filename=os.path.join(saveDir, 'gsas', basename + '.gsa'),
                Format='SLOG', SplitFiles=False, Append=False, ExtendedHeader=True)
        SaveFocusedXYE(InputWorkspace='WS_tof',
                       Filename=os.path.join(
                           saveDir, 'fullprof', basename + '.dat'),
                       SplitFiles=True, Append=False)
        DeleteWorkspace(Workspace='WS_tof')
def sel(sample, const):
    """
    Convert workspace into normalised spin echo units

    Parameters
    ----------
    sample : str
      The name of the workspace to be converted
    const : float
      The spin echo length of a one angstrom neutron in nanometers

    Returns
    -------
    The name of a workspace with the x coordinate in proper spin echo
    units and the y coordinate in log(P/P₀)/λ²
    """
    wtemp = mtd[sample]
    x = wtemp.extractX()
    y = wtemp.extractY()
    e = wtemp.extractE()

    dx = (x[:, 1:] + x[:, :-1]) / 2

    wtemp = ConvertUnits(sample, "SpinEchoLength", EFixed=const)

    wenv = CreateWorkspace(wtemp.extractX(), np.log(y) / dx**2, e / y / dx**2,
                           UnitX="SpinEchoLength",
                           YUnitLabel="Counts")
    RenameWorkspace(wenv, OutputWorkspace=sample + "_sel")
    def setUp(self):
        """
        Create sample workspaces.
        """

        # Load the sample and can
        sample_ws = Load('irs26176_graphite002_red.nxs')
        can_ws = Load('irs26173_graphite002_red.nxs')

        # Convert sample and can to wavelength
        sample_ws = ConvertUnits(InputWorkspace=sample_ws,
                                 Target='Wavelength',
                                 EMode='Indirect',
                                 EFixed=1.845)
        can_ws = ConvertUnits(InputWorkspace=can_ws,
                              Target='Wavelength',
                              EMode='Indirect',
                              EFixed=1.845)

        self._sample_ws = sample_ws
        self._can_ws = can_ws

        # Load the corrections workspace
        corrections = Load('irs26176_graphite002_cyl_Abs.nxs')

        # Interpolate each of the correction factor workspaces
        # Required to use corrections from the old indirect calculate
        # corrections routines
        for factor_ws in corrections:
            SplineInterpolation(WorkspaceToMatch=sample_ws,
                                WorkspaceToInterpolate=factor_ws,
                                OutputWorkspace=factor_ws,
                                OutputWorkspaceDeriv='')

        self._corrections_ws = corrections
Beispiel #5
0
 def setUp(self) -> None:
     r"""Fixture runs at the beginning of every test method"""
     spacings_reference = [
         0.9179, 0.9600, 1.0451, 1.2458, 1.3576, 1.5677, 1.6374, 3.1353
     ]  # silicon
     # add one Gaussian peak for every reference d-spacing
     peak_functions = list()
     for spacing in spacings_reference:
         peak_function = f'name=Gaussian, PeakCentre={spacing}, Height={10 * np.sqrt(spacing)}, Sigma={0.003 * spacing}'
         peak_functions.append(peak_function)
     function = ';'.join(peak_functions)
     begin, end, bin_width = spacings_reference[
         0] - 0.5, spacings_reference[-1] + 0.5, 0.0001
     # Single 10x10 rectangular detector, located 4m downstream the sample along the X-axis
     # Each detector has the same histogram of intensities, showing eight Gaussian peaks with centers at the
     # reference d-spacings
     CreateSampleWorkspace(WorkspaceType='Histogram',
                           Function='User Defined',
                           UserDefinedFunction=function,
                           XUnit='dSpacing',
                           XMin=begin,
                           XMax=end,
                           BinWidth=bin_width,
                           NumBanks=1,
                           PixelSpacing=0.02,
                           SourceDistanceFromSample=10.0,
                           BankDistanceFromSample=4.0,
                           OutputWorkspace='test_workspace_dSpacing')
     RotateInstrumentComponent(Workspace='test_workspace_dSpacing',
                               ComponentName='bank1',
                               X=0.,
                               Y=1.,
                               z=0.,
                               Angle=90,
                               RelativeRotation=True)
     MoveInstrumentComponent(Workspace='test_workspace_dSpacing',
                             ComponentName='bank1',
                             X=4.0,
                             y=0.0,
                             z=0.0,
                             RelativePosition=False)
     # Eight peaks now in TOF. Only when the instrument is located 4m downstream along the X-axis will we obtain
     # the correct d-Spacings if we convert back to dSpacings units. If we perturb the instrument and convert
     # back to dSpacing units, we'll obtain eight peaks centered at d-spacings sligthly different than the
     # reference values
     ConvertUnits(InputWorkspace='test_workspace_dSpacing',
                  Target='TOF',
                  EMode='Elastic',
                  OutputWorkspace='test_workspace_TOF')
     Rebin(InputWorkspace='test_workspace_TOF',
           Params=[300, 1.0, 16666.7],
           OutputWorkspace='test_workspace_TOF')
     ConvertUnits(InputWorkspace='test_workspace_TOF',
                  Target='dSpacing',
                  EMode='Elastic',
                  OutputWorkspace='test_workspace_dSpacing')
     self.spacings_reference = spacings_reference
Beispiel #6
0
    def _calculate_wavelength_band(self):
        """
        Calculate the wavelength band using the monitors from the sample runs

        Consider wavelenghts with an associated intensity above a certain
        fraction of the maximum observed intensity.
        """
        _t_w = self._load_monitors('sample')
        _t_w = ConvertUnits(_t_w, Target='Wavelength', Emode='Elastic')
        l_min, l_max = 0.0, 20.0
        _t_w = CropWorkspace(_t_w, XMin=l_min, XMax=l_max)
        _t_w = OneMinusExponentialCor(_t_w,
                                      C='0.20749999999999999',
                                      C1='0.001276')
        _t_w = Scale(_t_w, Factor='1e-06', Operation='Multiply')
        _t_w = Rebin(_t_w,
                     Params=[l_min, self._wavelength_dl, l_max],
                     PreserveEvents=False)
        y = _t_w.readY(0)
        k = np.argmax(y)  # y[k] is the maximum observed intensity
        factor = 0.8  # 80% of the maximum intensity
        i_s = k - 1
        while y[i_s] > factor * y[k]:
            i_s -= 1
        i_e = k + 1
        while y[i_e] > factor * y[k]:
            i_e += 1
        x = _t_w.readX(0)
        self._wavelength_band = [x[i_s], x[i_e]]
Beispiel #7
0
    def __processFile(self, filename, wkspname, file_prog_start, determineCharacterizations):
        chunks = determineChunking(filename, self.chunkSize)
        self.log().information('Processing \'%s\' in %d chunks' % (filename, len(chunks)))
        prog_per_chunk_step = self.prog_per_file * 1./(6.*float(len(chunks))) # for better progress reporting - 6 steps per chunk

        # inner loop is over chunks
        for (j, chunk) in enumerate(chunks):
            prog_start = file_prog_start + float(j) * 5. * prog_per_chunk_step
            chunkname = "%s_c%d" % (wkspname, j)
            Load(Filename=filename, OutputWorkspace=chunkname,
                 startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step,
                 **chunk)
            if determineCharacterizations:
                self.__determineCharacterizations(filename, chunkname, False) # updates instance variable
                determineCharacterizations = False

            prog_start += prog_per_chunk_step
            if self.filterBadPulses > 0.:
                FilterBadPulses(InputWorkspace=chunkname, OutputWorkspace=chunkname,
                                LowerCutoff=self.filterBadPulses,
                                startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step)
            prog_start += prog_per_chunk_step

            # absorption correction workspace
            if self.absorption is not None and len(str(self.absorption)) > 0:
                ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname,
                             Target='Wavelength', EMode='Elastic')
                Divide(LHSWorkspace=chunkname, RHSWorkspace=self.absorption, OutputWorkspace=chunkname,
                       startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step)
                ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname,
                             Target='TOF', EMode='Elastic')
            prog_start += prog_per_chunk_step

            AlignAndFocusPowder(InputWorkspace=chunkname, OutputWorkspace=chunkname,
                                startProgress=prog_start, endProgress=prog_start+2.*prog_per_chunk_step,
                                **self.kwargs)
            prog_start += 2.*prog_per_chunk_step # AlignAndFocusPowder counts for two steps

            if j == 0:
                self.__updateAlignAndFocusArgs(chunkname)
                RenameWorkspace(InputWorkspace=chunkname, OutputWorkspace=wkspname)
            else:
                Plus(LHSWorkspace=wkspname, RHSWorkspace=chunkname, OutputWorkspace=wkspname,
                     ClearRHSWorkspace=self.kwargs['PreserveEvents'],
                     startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step)
                DeleteWorkspace(Workspace=chunkname)
                if self.kwargs['PreserveEvents']:
                    CompressEvents(InputWorkspace=wkspname, OutputWorkspace=wkspname)
    def test_ILL_reduced(self):

        ill_red_ws = Load('ILL/IN16B/091515_red.nxs')

        ill_red_ws = ConvertUnits(ill_red_ws,
                                  Target='Wavelength',
                                  EMode='Indirect',
                                  EFixed=1.845)

        kwargs = self._arguments
        corrected = SimpleShapeMonteCarloAbsorption(InputWorkspace=ill_red_ws,
                                                    Shape='FlatPlate',
                                                    Width=2.0,
                                                    Thickness=2.0,
                                                    **kwargs)

        x_unit = corrected.getAxis(0).getUnit().unitID()
        self.assertEquals(x_unit, 'Wavelength')

        y_unit = corrected.YUnitLabel()
        self.assertEquals(y_unit, 'Attenuation factor')

        num_hists = corrected.getNumberHistograms()
        self.assertEquals(num_hists, 18)

        blocksize = corrected.blocksize()
        self.assertEquals(blocksize, 1024)

        DeleteWorkspace(ill_red_ws)
 def processData(self, filename, wsName):
     if filename != '':
         if self._SystemTest:
             Load(Filename=filename, OutputWorkspace=wsName, BankName = 'bank22')
         else:
             Load(Filename=filename, OutputWorkspace=wsName)
     FindDetectorsPar(InputWorkspace=wsName,
                      ReturnLinearRanges=self._returnLinearRanges,
                      ParFile=self._parFile,
                      OutputParTable=self._outputParTable)
     FilterBadPulses(InputWorkspace=wsName, Outputworkspace=wsName, LowerCutoff=self._lowerCutoff)
     RemovePromptPulse(InputWorkspace=wsName, OutputWorkspace=wsName, Width=self._width, Frequency=self._frequency)
     LoadDiffCal(InputWorkspace=wsName,
                 InstrumentName=self._instrumentName,
                 InstrumentFilename=self._instrumentFilename,
                 Filename=self._filename,
                 MakeGroupingWorkspace=self._makeGroupingWorkspace,
                 MakeCalWorkspace=self._makeCalWorkspace,
                 MakeMaskWorkspace=self._makeMaskWorkspace,
                 WorkspaceName=self._workspaceName,
                 TofMin=self._tofMin,
                 TofMax=self._tofMax,
                 FixConversionIssues=self._fixConversionIssues)
     MaskDetectors(Workspace=wsName,
                   SpectraList=self._spectraList,
                   DetectorList=self._detectorList,
                   WorkspaceIndexList=self._workspaceIndexList,
                   MaskedWorkspace=self._maskedWorkspace,
                   ForceInstrumentMasking=self._forceInstrumentMasking,
                   StartWorkspaceIndex=self._startWorkspaceIndex,
                   EndWorkspaceIndex=self._endWorkspaceIndex,
                   ComponentList=self._componentList)
     AlignDetectors(InputWorkspace=wsName, OutputWorkspace=wsName, CalibrationFile=self._calibrationFile)
     ConvertUnits(InputWorkspace=wsName, OutputWorkspace=wsName, Target='Wavelength')
Beispiel #10
0
 def monitorTransfit(self, files, foilType, divE):
     isFirstFile = True
     isSingleFile = len(files) == 1
     firstFileName = ""
     for file in files:
         discard, fileName = path.split(file)
         fnNoExt = path.splitext(fileName)[0]
         if isFirstFile:
             firstFileName = fnNoExt
         fileName_Raw = fnNoExt + '_raw'
         fileName_3 = fnNoExt + '_3'
         LoadRaw(Filename=file, OutputWorkspace=fileName_Raw)
         CropWorkspace(InputWorkspace=fileName_Raw, OutputWorkspace=fileName_Raw, XMin=100, XMax=19990)
         NormaliseByCurrent(InputWorkspace=fileName_Raw, OutputWorkspace=fileName_Raw)
         ExtractSingleSpectrum(InputWorkspace=fileName_Raw, OutputWorkspace=fileName_3, WorkspaceIndex=3)
         DeleteWorkspace(fileName_Raw)
         ConvertUnits(InputWorkspace=fileName_3, Target='Energy', OutputWorkspace=fileName_3)
         self.TransfitRebin(fileName_3, fileName_3, foilType, divE)
         if not isFirstFile:
             Plus(LHSWorkspace=firstFileName + '_3', RHSWorkspace=fileName_3, OutputWorkspace=firstFileName + '_3')
             DeleteWorkspace(fileName_3)
         else:
             isFirstFile = False
     if isSingleFile:
         RenameWorkspace(InputWorkspace=firstFileName + '_3', OutputWorkspace=firstFileName + '_monitor')
     else:
         noFiles = len(files) ** (-1)
         CreateSingleValuedWorkspace(OutputWorkspace='scale', DataValue=noFiles)
         Multiply(LHSWorkspace=firstFileName + '_3', RHSWorkspace='scale',
                  OutputWorkspace=firstFileName + '_monitor')
         DeleteWorkspace('scale')
         DeleteWorkspace(firstFileName + '_3')
    def setUp(self):
        red_ws = Load('irs26176_graphite002_red.nxs')
        red_ws = ConvertUnits(InputWorkspace=red_ws,
                              Target='Wavelength',
                              EMode='Indirect',
                              EFixed=1.845)

        self._arguments = {
            'ChemicalFormula': 'H2-O',
            'DensityType': 'Mass Density',
            'Density': 1.0,
            'EventsPerPoint': 200,
            'BeamHeight': 3.5,
            'BeamWidth': 4.0,
            'Height': 2.0
        }

        self._red_ws = red_ws

        corrected = SimpleShapeMonteCarloAbsorption(
            InputWorkspace=self._red_ws,
            Shape='FlatPlate',
            Width=2.0,
            Thickness=2.0,
            **self._arguments)

        # store the basic flat plate workspace so it can be compared with others
        self._corrected_flat_plate = corrected
    def test_not_in_deltaE(self):
        red_ws_not_deltaE = Load('irs26176_graphite002_red.nxs')

        red_ws_not_deltaE = ConvertUnits(InputWorkspace=self._red_ws,
                                         Target='Wavelength',
                                         EMode='Indirect',
                                         EFixed=1.845)

        kwargs = {
            'ReducedWorkspace': red_ws_not_deltaE,
            'SqwWorkspace': self._sqw_ws,
            'ChemicalFormula': 'H2-O',
            'SampleMassDensity': 1.0,
            'NeutronPathsSingle': 50,
            'NeutronPathsMultiple': 50,
            'Height': 2.0,
            'Shape': 'FlatPlate',
            'Width': 1.4,
            'Thickness': 2.1
        }

        with self.assertRaises(RuntimeError):
            SimpleShapeDiscusInelastic(**kwargs)

        DeleteWorkspace(red_ws_not_deltaE)
Beispiel #13
0
    def test_adsrp_cylinder(self):
        ash = Cylinder('V', [10, 2])
        res = ash.shape
        self.assertEqual(res['Height'], 10)
        self.assertEqual(res['Radius'], 2)
        self.assertTrue(ash._axis_is_default)

        ash.shape = [5, 1, [0, 1, 0], [0., 0., -0.5]]
        res = ash.shape
        self.assertEqual(res['Height'], 5)
        self.assertEqual(res['Radius'], 1)
        self.assertEqual(res['Axis'], [0, 1, 0])
        self.assertEqual(res['Center'], [0, 0, -0.5])
        self.assertFalse(ash._axis_is_default)

        ash.shape = {'Height': 5, 'Radius': 2, 'Axis': [1, 0, 0], 'Center': [0., 0., 0.]}
        res = ash.shape
        self.assertEqual(res['Height'], 5)
        self.assertEqual(res['Radius'], 2)
        self.assertEqual(res['Axis'], [1, 0, 0])
        self.assertEqual(res['Center'], [0, 0, 0])

        test_ws = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=1)
        test_ws = ConvertUnits(test_ws, 'DeltaE', Emode='Direct', EFixed=2000)
        cor_ws, corrections = ash.correct_absorption(test_ws, is_fast=True)
        n_bins = corrections.blocksize()
        corr_ranges = [n_bins, corrections.readY(0)[0], corrections.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(corr_ranges, [97, 0.0, 0.0], 4)
        mccor_ws, mc_corr = ash.correct_absorption(test_ws, EventsPerPoint=300)
        n_bins = mc_corr.blocksize()
        mccorr_ranges = [n_bins, mc_corr.readY(0)[0], mc_corr.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(mccorr_ranges, [97, 0.266, 0.033], 3)
Beispiel #14
0
def _create_single_test_workspace(fwhm, output_name, i):
    function = "name=Lorentzian,Amplitude=100,PeakCentre=27500,FWHM=" + str(
        fwhm)

    CreateSampleWorkspace(Function='User Defined',
                          UserDefinedFunction=function,
                          XMin=27000,
                          XMax=28000,
                          BinWidth=10,
                          NumBanks=1,
                          OutputWorkspace=output_name)
    ConvertUnits(InputWorkspace=output_name,
                 OutputWorkspace=output_name,
                 Target='DeltaE',
                 EMode='Indirect',
                 EFixed=1.5)
    Rebin(InputWorkspace=output_name,
          OutputWorkspace=output_name,
          Params=[-0.2, 0.004, 0.2])
    LoadInstrument(Workspace=output_name,
                   InstrumentName='IRIS',
                   RewriteSpectraMap=True)
    SetInstrumentParameter(Workspace=output_name,
                           ParameterName='Efixed',
                           DetectorList=range(1, 113),
                           ParameterType='Number',
                           Value='1.5')

    output = AnalysisDataService.retrieve(output_name)
    output.mutableRun()['run_number'] = i + 1
    output.mutableRun()['sample'] = [1, 2, 3]
    output.mutableRun()['sample'].units = " "
Beispiel #15
0
 def _convert_units(self, workspace, target, emode, efixed):
     return ConvertUnits(InputWorkspace=workspace,
                         OutputWorkspace="__units_converted",
                         Target=target,
                         EMode=emode,
                         EFixed=efixed,
                         StoreInADS=False)
 def _mask_t0_crop(self, run_number, name):
     """
     Load a run into a workspace with:
      1. Masked detectors
      2. Delayed emission time from  moderator removed
      3. Conversion of units to momentum
      4. Remove events outside the valid momentum range
     :param run_number: BASIS run number
     :param name: name for the output workspace
     :return: workspace object
     """
     ws = self._load_single_run(run_number, name)
     MaskDetectors(ws, MaskedWorkspace=self._t_mask)
     ws = ModeratorTzeroLinear(InputWorkspace=ws.name(),
                               Gradient=self._tzero['gradient'],
                               Intercept=self._tzero['intercept'],
                               OutputWorkspace=ws.name())
     # Correct old DAS shift of fast neutrons. See GitHub issue 23855
     if self._das_version == VDAS.v1900_2018:
         ws = self.add_previous_pulse(ws)
     ws = ConvertUnits(ws, Target='Momentum', OutputWorkspace=ws.name())
     ws = CropWorkspace(ws,
                        OutputWorkspace=ws.name(),
                        XMin=self._momentum_range[0],
                        XMax=self._momentum_range[1])
     return ws
Beispiel #17
0
 def load_files(self, filenames_string, xunit):
     self._last_added = []
     filenames = [name.strip() for name in filenames_string.split(",")]
     for filename in filenames:
         ws_name = self._generate_workspace_name(filename, xunit)
         if ws_name not in self._loaded_workspaces:
             try:
                 if not ADS.doesExist(ws_name):
                     ws = Load(filename, OutputWorkspace=ws_name)
                     if xunit != "TOF":
                         ConvertUnits(InputWorkspace=ws, OutputWorkspace=ws_name, Target=xunit)
                 else:
                     ws = ADS.retrieve(ws_name)
                 if ws.getNumberHistograms() == 1:
                     self._loaded_workspaces[ws_name] = ws
                     if ws_name not in self._background_workspaces:
                         self._background_workspaces[ws_name] = None
                     self._last_added.append(ws_name)
                     self.add_log_to_table(ws_name, ws)
                 else:
                     logger.warning(
                         f"Invalid number of spectra in workspace {ws_name}. Skipping loading of file.")
             except RuntimeError as e:
                 logger.error(
                     f"Failed to load file: {filename}. Error: {e}. \n Continuing loading of other files.")
         else:
             logger.warning(f"File {ws_name} has already been loaded")
Beispiel #18
0
    def _monitor_normalization(self, w, target):
        """
        Divide data by integrated monitor intensity

        Parameters
        ----------
        w: Mantid.EventsWorkspace
            Input workspace
        target: str
            Specify the entity the workspace refers to. Valid options are
            'sample', 'background', and 'vanadium'

        Returns
        -------
        Mantid.EventWorkspace
        """
        _t_mon = self._load_monitors(target)
        _t_mon = ConvertUnits(_t_mon, Target='Wavelength', Emode='Elastic')
        _t_mon = CropWorkspace(_t_mon,
                               XMin=self._wavelength_band[0],
                               XMax=self._wavelength_band[1])
        _t_mon = OneMinusExponentialCor(_t_mon,
                                        C='0.20749999999999999',
                                        C1='0.001276')
        _t_mon = Scale(_t_mon, Factor='1e-06', Operation='Multiply')
        _t_mon = Integration(_t_mon)  # total monitor count
        _t_w = Divide(w, _t_mon, OutputWorkspace=w.name())
        return _t_w
Beispiel #19
0
    def _apply_corrections(self, w, target='sample'):
        """
        Apply a series of corrections and normalizations to the input
        workspace

        Parameters
        ----------
        w: Mantid.EventsWorkspace
            Input workspace
        target: str
            Specify the entity the workspace refers to. Valid options are
            'sample', 'background', and 'vanadium'

        Returns
        -------
        Mantid.EventsWorkspace
        """
        MaskDetectors(w, MaskedWorkspace=self._t_mask)
        _t_corr = ModeratorTzeroLinear(w)  # delayed emission from moderator
        _t_corr = self.add_previous_pulse(_t_corr)
        _t_corr = ConvertUnits(_t_corr, Target='Wavelength', Emode='Elastic')
        l_s, l_e = self._wavelength_band[0], self._wavelength_band[1]
        _t_corr = CropWorkspace(_t_corr, XMin=l_s, XMax=l_e)
        _t_corr = Rebin(_t_corr,
                        Params=[l_s, self._wavelength_dl, l_e],
                        PreserveEvents=False)
        if self.getProperty('MonitorNormalization').value is True:
            _t_corr = self._monitor_normalization(_t_corr, target)
        return _t_corr
    def runTest(self):
        ws = DirectILLCollectData('ILL/IN6/164192.nxs',
                                  ElasticChannel='Default Elastic Channel',
                                  FlatBkg='Flat Bkg OFF',
                                  Normalisation='Normalisation OFF')
        for i in range(ws.getNumberHistograms()):
            ws.dataY(i).fill(1)
        dE = ConvertUnits(ws, 'DeltaE', 'Direct')
        corr = DetectorEfficiencyCorUser(dE)
        Ei = corr.run().get('Ei').value

        def det_corr(x):
            high = x > 5.113
            low = x <= 5.113
            c = numpy.empty_like(x)
            c[high] = 0.94 * (1. - numpy.exp(-3.284 / numpy.sqrt(x[high])))
            c[low] = numpy.exp(-0.0565 / numpy.sqrt(x[low])) * (
                1. - numpy.exp(-3.284 / numpy.sqrt(x[low])))
            return c

        corr_at_Ei = det_corr(numpy.array([Ei]))[0]
        for i in range(corr.getNumberHistograms()):
            x = (corr.readX(i)[:-1] + corr.readX(i)[1:]) / 2.
            e = Ei - x
            numpy.testing.assert_almost_equal(corr.readY(i),
                                              corr_at_Ei / det_corr(e))
Beispiel #21
0
    def _save(self, saveDir, basename, outputWksp):
        if not self.getProperty("SaveData").value:
            return

        self.log().notice('Writing to \'' + saveDir + '\'')

        SaveNexusProcessed(InputWorkspace=outputWksp,
                           Filename=os.path.join(saveDir, 'nexus',
                                                 basename + '.nxs'))
        SaveAscii(InputWorkspace=outputWksp,
                  Filename=os.path.join(saveDir, 'd_spacing',
                                        basename + '.dat'))
        ConvertUnits(InputWorkspace=outputWksp,
                     OutputWorkspace='WS_tof',
                     Target="TOF",
                     AlignBins=False)

        # GSAS and FullProf require data in time-of-flight
        SaveGSS(InputWorkspace='WS_tof',
                Filename=os.path.join(saveDir, 'gsas', basename + '.gsa'),
                Format='SLOG',
                SplitFiles=False,
                Append=False,
                ExtendedHeader=True)
        SaveFocusedXYE(InputWorkspace='WS_tof',
                       Filename=os.path.join(saveDir, 'fullprof',
                                             basename + '.dat'),
                       SplitFiles=True,
                       Append=False)
        DeleteWorkspace(Workspace='WS_tof')
Beispiel #22
0
    def test_adsrp_hollow_cylinder(self):
        ash = HollowCylinder('V', [10, 2, 4])
        res = ash.shape
        self.assertEqual(res['Height'], 10)
        self.assertEqual(res['InnerRadius'], 2)
        self.assertEqual(res['OuterRadius'], 4)

        ash.shape = [5, 1, 2, [1, 0, 0], [0, 0, 0]]
        res = ash.shape
        self.assertEqual(res['Height'], 5)
        self.assertEqual(res['InnerRadius'], 1)
        self.assertEqual(res['OuterRadius'], 2)
        self.assertEqual(res['Axis'], [1, 0, 0])
        self.assertEqual(res['Center'], [0, 0, 0])

        ash.shape = {'Height': 5, 'InnerRadius': 0.01, 'OuterRadius': 2, 'Center': [0., 0., 0.], 'Axis': [0, 1, 0]}
        res = ash.shape
        self.assertEqual(res['Height'], 5)
        self.assertEqual(res['InnerRadius'], 0.01)
        self.assertEqual(res['OuterRadius'], 2)
        self.assertEqual(res['Axis'], [0, 1, 0])
        self.assertEqual(res['Center'], [0, 0, 0])

        test_ws = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=1)
        test_ws = ConvertUnits(test_ws, 'DeltaE', Emode='Direct', EFixed=2000)
        cor_ws, corrections = ash.correct_absorption(test_ws, is_fast=True, ElementSize=5)
        n_bins = corrections.blocksize()
        corr_ranges = [n_bins, corrections.readY(0)[0], corrections.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(corr_ranges, [97, 0.0, 0.000], 4)

        mccor_ws, mc_corr = ash.correct_absorption(test_ws, is_mc=True, EventsPerPoint=300)
        n_bins = mc_corr.blocksize()
        mccorr_ranges = [n_bins, mc_corr.readY(0)[0], mc_corr.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(mccorr_ranges, [97, 0.27, 0.03], 2)
 def runTest(self):
     flood = CreateFloodWorkspace('OFFSPEC00035946.nxs', StartSpectrum=250, EndSpectrum=600,
                                  ExcludeSpectra=[260, 261, 262, 516, 517, 518], OutputWorkspace='flood')
     data = Load('OFFSPEC00044998.nxs')
     data = Rebin(data, [0,1000,100000], PreserveEvents=False)
     data = ConvertUnits(data, 'Wavelength')
     ApplyFloodWorkspace(InputWorkspace=data, FloodWorkspace=flood, OutputWorkspace=self.out_ws_name)
Beispiel #24
0
 def load_file_and_apply(self, filename, ws_name):
     Load(Filename=filename,
          OutputWorkspace=ws_name,
          FilterByTofMin=self.getProperty("FilterByTofMin").value,
          FilterByTofMax=self.getProperty("FilterByTofMax").value)
     if self._load_inst:
         LoadInstrument(Workspace=ws_name,
                        Filename=self.getProperty("LoadInstrument").value,
                        RewriteSpectraMap=False)
     if self._apply_cal:
         ApplyCalibration(
             Workspace=ws_name,
             CalibrationTable=self.getProperty("ApplyCalibration").value)
     if self._detcal:
         LoadIsawDetCal(InputWorkspace=ws_name,
                        Filename=self.getProperty("DetCal").value)
     if self._copy_params:
         CopyInstrumentParameters(OutputWorkspace=ws_name,
                                  InputWorkspace=self.getProperty(
                                      "CopyInstrumentParameters").value)
     if self._masking:
         if not mtd.doesExist('__mask'):
             LoadMask(Instrument=mtd[ws_name].getInstrument().getName(),
                      InputFile=self.getProperty("MaskFile").value,
                      OutputWorkspace='__mask')
         MaskDetectors(Workspace=ws_name, MaskedWorkspace='__mask')
     if self.XMin != Property.EMPTY_DBL and self.XMax != Property.EMPTY_DBL:
         ConvertUnits(InputWorkspace=ws_name,
                      OutputWorkspace=ws_name,
                      Target='Momentum')
         CropWorkspaceForMDNorm(InputWorkspace=ws_name,
                                OutputWorkspace=ws_name,
                                XMin=self.XMin,
                                XMax=self.XMax)
Beispiel #25
0
        def calibrate_region_of_interest(ceria_d_ws, roi: str,
                                         grouping_kwarg: dict,
                                         cal_output: dict) -> None:
            """
            Focus the processed ceria workspace (dSpacing) over the chosen region of interest, and run the calibration
            using this result
            :param ceria_d_ws: Workspace containing the processed ceria data converted to dSpacing
            :param roi: String describing chosen region of interest
            :param grouping_kwarg: Dict containing kwarg to pass to DiffractionFocussing to select the roi
            :param cal_output: Dictionary to append with the output of PDCalibration for the chosen roi
            """
            # focus ceria
            focused_ceria = DiffractionFocussing(InputWorkspace=ceria_d_ws,
                                                 **grouping_kwarg)
            ApplyDiffCal(InstrumentWorkspace=focused_ceria,
                         ClearCalibration=True)
            ConvertUnits(InputWorkspace=focused_ceria,
                         OutputWorkspace=focused_ceria,
                         Target='TOF')

            # calibration of focused data over chosen region of interest
            kwargs["InputWorkspace"] = focused_ceria
            kwargs["OutputCalibrationTable"] = "engggui_calibration_" + roi
            kwargs["DiagnosticWorkspaces"] = "diag_" + roi

            cal_roi = run_pd_calibration(kwargs)[0]
            cal_output[roi] = cal_roi
Beispiel #26
0
    def runTest(self):
        ws = DirectILLCollectData('ILL/IN4/084446.nxs', ElasticChannel='Default Elastic Channel',
                                  FlatBkg='Flat Bkg OFF', Normalisation='Normalisation OFF')
        for i in range(ws.getNumberHistograms()):
            ws.dataY(i).fill(1)
        dE = ConvertUnits(ws, 'DeltaE', 'Direct')
        corr = DetectorEfficiencyCorUser(dE)
        Ei = corr.run().get('Ei').value

        def rosace_corr(x):
            return 1.0 - numpy.exp(-6.1343 / numpy.sqrt(x))

        def wide_angle_corr(x):
            return 0.951 * numpy.exp(-0.0887 / numpy.sqrt(x)) * (1 - numpy.exp(-5.597 / numpy.sqrt(x)))

        def eff_factor(x, corr_func):
            return corr_func(Ei) / corr_func(x)

        # Wide-angle detectors are at ws indices 0-299
        for i in range(0, 300):
            x = (corr.readX(i)[:-1] + corr.readX(i)[1:]) / 2.
            e = Ei - x
            assert_almost_equal(corr.readY(i), eff_factor(e, wide_angle_corr))
        # Rosace detectors are at ws indices 300-395
        for i in range(300, 396):
            x = (corr.readX(i)[:-1] + corr.readX(i)[1:]) / 2.
            e = Ei - x
            assert_almost_equal(corr.readY(i), eff_factor(e, rosace_corr))
Beispiel #27
0
    def _save(self, runnumber, basename, outputWksp):
        if not self.getProperty("SaveData").value:
            return

        # determine where to save the data
        saveDir = self.getPropertyValue("OutputDirectory").strip()
        if len(saveDir) <= 0:
            self.log().notice('Using default save location')
            saveDir = os.path.join(self.get_IPTS_Local(runnumber), 'shared', 'data')

        self.log().notice('Writing to \'' + saveDir + '\'')

        SaveNexusProcessed(InputWorkspace=outputWksp,
                           Filename=os.path.join(saveDir, 'nexus', basename + '.nxs'))
        SaveAscii(InputWorkspace=outputWksp,
                  Filename=os.path.join(saveDir, 'd_spacing', basename + '.dat'))
        ConvertUnits(InputWorkspace=outputWksp, OutputWorkspace='WS_tof',
                     Target="TOF", AlignBins=False)

        # GSAS and FullProf require data in time-of-flight
        SaveGSS(InputWorkspace='WS_tof',
                Filename=os.path.join(saveDir, 'gsas', basename + '.gsa'),
                Format='SLOG', SplitFiles=False, Append=False, ExtendedHeader=True)
        SaveFocusedXYE(InputWorkspace='WS_tof',
                       Filename=os.path.join(
                           saveDir, 'fullprof', basename + '.dat'),
                       SplitFiles=True, Append=False)
        DeleteWorkspace(Workspace='WS_tof')
Beispiel #28
0
    def test_adsrp_Plate(self):
        ash = FlatPlate('V', [10, 2, 0.1])
        res = ash.shape
        self.assertEqual(res['Height'], 10)
        self.assertEqual(res['Width'], 2)
        self.assertEqual(res['Thick'], 0.1)

        ash.shape = [5, 1, 0.2, [0, 1, 0], 10]
        res = ash.shape
        self.assertEqual(res['Height'], 5)
        self.assertEqual(res['Width'], 1)
        self.assertEqual(res['Thick'], 0.2)
        self.assertEqual(res['Center'], [0, 1, 0])
        self.assertEqual(res['Angle'], 10)

        ash.shape = {'Height': 5, 'Width': 1, 'Thick': 2, 'Center': [0., 0., 0.], 'Angle': 20}
        res = ash.shape
        self.assertEqual(res['Height'], 5)
        self.assertEqual(res['Width'], 1)
        self.assertEqual(res['Thick'], 2)
        self.assertEqual(res['Center'], [0, 0, 0])
        self.assertEqual(res['Angle'], 20)

        test_ws = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=1)
        test_ws = ConvertUnits(test_ws, 'DeltaE', Emode='Direct', EFixed=2000)

        cor_ws, corrections = ash.correct_absorption(test_ws, is_fast=True, ElementSize=5)
        n_bins = corrections.blocksize()
        corr_ranges = [n_bins, corrections.readY(0)[0], corrections.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(corr_ranges, [97, 0., 0.], 4)

        mccor_ws, mc_corr = ash.correct_absorption(test_ws, is_mc=True, EventsPerPoint=300)
        n_bins = mc_corr.blocksize()
        mccorr_ranges = [n_bins, mc_corr.readY(0)[0], mc_corr.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(mccorr_ranges, [97, 0.52, 0.13], 2)
Beispiel #29
0
    def test_adsrp_sphere(self):
        ash = Sphere('Al', 10)
        res = ash.shape
        self.assertEqual(res['Radius'], 10)

        ash.shape = [5, [1, 0, 0]]
        res = ash.shape
        rad = res['Radius']
        self.assertEqual(rad, 5)
        cen = res['Center']
        self.assertEqual(cen, [1, 0, 0])

        ash.shape = {'Radius': 3, 'Center': [0., 0., 0.]}
        res = ash.shape
        rad = res['Radius']
        self.assertEqual(rad, 3)
        cen = res['Center']
        self.assertEqual(cen, [0, 0, 0])

        test_ws = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=1)
        test_ws = ConvertUnits(test_ws, 'DeltaE', Emode='Direct', EFixed=2000)
        cor_ws, corrections = ash.correct_absorption(test_ws, is_fast=True, ElementSize=6)
        n_bins = corrections.blocksize()
        corr_ranges = [n_bins, corrections.readY(0)[0], corrections.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(corr_ranges, [97, 0.0, 0.0], 4)

        cor_ws, corrections = ash.correct_absorption(test_ws, is_fast=True)
        n_bins = corrections.blocksize()
        corr_ranges = [n_bins, corrections.readY(0)[0], corrections.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(corr_ranges, [97, 0.0, 0.0], 4)

        mccor_ws, mc_corr = ash.correct_absorption(test_ws, is_mc=True, EventsPerPoint=300)
        n_bins = mc_corr.blocksize()
        mccorr_ranges = [n_bins, mc_corr.readY(0)[0], mc_corr.readY(0)[n_bins - 1]]
        np.testing.assert_almost_equal(mccorr_ranges, [97, 0.66, 0.51], 2)
Beispiel #30
0
 def _whole_inst_prefocus(input_workspace, vanadium_integration_ws,
                          full_calib) -> bool:
     """This is used to perform the operations done on the whole instrument workspace, before the chosen region of
     interest is focused using _run_focus
     :param input_workspace: Raw sample run to process prior to focussing over a region of interest
     :param vanadium_integration_ws: Integral of the supplied vanadium run
     :param full_calib: Full instrument calibration workspace (table ws output from PDCalibration)
     :return True if successful, False if aborted
     """
     if input_workspace.getRun().getProtonCharge() > 0:
         NormaliseByCurrent(InputWorkspace=input_workspace,
                            OutputWorkspace=input_workspace)
     else:
         logger.warning(
             f"Skipping focus of run {input_workspace.name()} because it has invalid proton charge."
         )
         return False
     input_workspace /= vanadium_integration_ws
     # replace nans created in sensitivity correction
     ReplaceSpecialValues(InputWorkspace=input_workspace,
                          OutputWorkspace=input_workspace,
                          NaNValue=0,
                          InfinityValue=0)
     ApplyDiffCal(InstrumentWorkspace=input_workspace,
                  CalibrationWorkspace=full_calib)
     ConvertUnits(InputWorkspace=input_workspace,
                  OutputWorkspace=input_workspace,
                  Target='dSpacing')
     return True
Beispiel #31
0
 def spacings_recovered(self, input_workspace, calibrate=True):
     r"""Compare the input_workspace to the reference workspace 'test_workspace_dSpacing' after being
     converted to TOF units. If calibrate=True, calibrate first and then convert units"""
     if calibrate:
         CorelliPowderCalibrationCreate(
             InputWorkspace='perturbed',
             OutputWorkspacesPrefix='cal_',
             TofBinning=[300, 1.0, 16666.7],
             PeakPositions=self.spacings_reference,
             SourceToSampleDistance=10.0,
             ComponentList='bank1',
             FixY=False,
             ComponentMaxTranslation=0.03,
             FixYaw=False,
             ComponentMaxRotation=6,
             Minimizer='differential_evolution',
             MaxIterations=10)
     ConvertUnits(InputWorkspace='perturbed',
                  Target='dSpacing',
                  EMode='Elastic',
                  OutputWorkspace='perturbed_dS')
     results = CompareWorkspaces(Workspace1='test_workspace_dSpacing',
                                 Workspace2='perturbed_dS',
                                 Tolerance=0.001,
                                 CheckInstrument=False)
     DeleteWorkspaces(['perturbed_dS'])
     return results.Result
    def PyExec(self):
        self._setup()
        if not self.getProperty("InputWorkspace").isDefault:
            self._output_ws = CloneWorkspace(Inputworkspace=self._input_ws,
                                             OutputWorkspace=self._output_ws,
                                             StoreInADS=False)
        else:
            self._output_ws = CreateWorkspace(NSpec=1, DataX=[0], DataY=[0],
                                              UnitX='Wavelength', Distribution=False,
                                              StoreInADS=False)
            self._output_ws = Rebin(InputWorkspace=self._output_ws,
                                    Params=self._bin_params,
                                    StoreInADS=False)

        if self._output_ws.isDistribution():
            ConvertFromDistribution(Workspace=self._output_ws,
                                    StoreInADS=False)

        self._output_ws = ConvertToPointData(InputWorkspace=self._output_ws,
                                             StoreInADS=False)
        self._output_ws = ConvertUnits(InputWorkspace=self._output_ws,
                                       Target='Wavelength',
                                       EMode='Elastic',
                                       StoreInADS=False)

        if self.getProperty('Alpha').isDefault:
            SetSampleMaterial(
                InputWorkspace=self._output_ws,
                ChemicalFormula=self._chemical_formula,
                SampleNumberDensity=self._density,
                StoreInADS=False)
            if self.getProperty('MeasuredEfficiency').isDefault:
                self._calculate_area_density_from_density()
            else:
                self._calculate_area_density_from_efficiency()
            self._calculate_alpha_absXS_term()
            if self._xsection_type == "TotalXSection":
                self._calculate_alpha_scatXS_term()

        wavelengths = self._output_ws.readX(0)
        efficiency = self._calculate_efficiency(wavelengths)
        for histo in range(self._output_ws.getNumberHistograms()):
            self._output_ws.setY(histo, efficiency)

        self.setProperty('OutputWorkspace', self._output_ws)
class CalculateEfficiencyCorrection(PythonAlgorithm):
    _input_ws = None
    _output_ws = None

    def category(self):
        return 'CorrectionFunctions\\EfficiencyCorrections'

    def name(self):
        return 'CalculateEfficiencyCorrection'

    def summary(self):
        return 'Calculate an efficiency correction using various inputs. Can be used to determine \
                an incident spectrum after correcting a measured spectrum from beam monitors \
                or vanadium measurements.'

    def seeAlso(self):
        return [ "He3TubeEfficiency", "CalculateSampleTransmission",
                 "DetectorEfficiencyCor", "DetectorEfficiencyCorUser",
                 "CalculateEfficiency", "ComputeCalibrationCoefVan" ]

    def PyInit(self):
        self.declareProperty(
            MatrixWorkspaceProperty('InputWorkspace', '',
                                    direction=Direction.Input,
                                    optional=PropertyMode.Optional,
                                    validator=CommonBinsValidator()),
            doc='Input workspace with wavelength range to calculate for the correction.')

        self.declareProperty(name='WavelengthRange', defaultValue='',
                             doc='Wavelength range to calculate efficiency for.')

        self.declareProperty(
            MatrixWorkspaceProperty('OutputWorkspace', '',
                                    direction=Direction.Output),
            doc="Output workspace for the efficiency correction. \
                 This can be applied by multiplying the OutputWorkspace \
                 to the workspace that requires the correction.")

        self.declareProperty(
            name='ChemicalFormula', defaultValue='None',
            validator=StringMandatoryValidator(),
            doc='Sample chemical formula used to determine cross-section term.')

        self.declareProperty(
            name='DensityType', defaultValue = 'Mass Density',
            validator=StringListValidator(['Mass Density', 'Number Density']),
            doc = 'Use of Mass density (g/cm^3) or Number density (atoms/Angstrom^3)')

        self.declareProperty(
            name='Density',
            defaultValue=0.0,
            validator=FloatBoundedValidator(0.0),
            doc='Mass density (g/cm^3) or Number density (atoms/Angstrom^3).')

        self.declareProperty(
            name='Thickness',
            defaultValue=1.0,
            validator=FloatBoundedValidator(0.0),
            doc='Sample thickness (cm).')

        self.declareProperty(
            name='MeasuredEfficiency',
            defaultValue=0.0,
            validator=FloatBoundedValidator(0.0, 1.0),
            doc="Directly input the efficiency measured at MeasuredEfficiencyWavelength. \
                 This is used to determine a Density*Thickness term.")

        self.declareProperty(
            name='MeasuredEfficiencyWavelength',
            defaultValue=1.7982,
            validator=FloatBoundedValidator(0.0),
            doc="The wavelength at which the MeasuredEfficiency was measured.")

        self.declareProperty(
            name='Alpha', defaultValue=0.0,
            doc="Directly input the alpha term in exponential to multiply by the wavelength. \
                 XSectionType has no effect if this is used.")

        self.declareProperty(
            name='XSectionType',
            defaultValue="AttenuationXSection",
            validator=StringListValidator(['AttenuationXSection', 'TotalXSection']),
            doc = 'Use either the absorption  or total cross section in exponential term. \
                   The absorption cross section is for monitor-type corrections and \
                   the total cross section is for transmission-type corrections' )

    def validateInputs(self):
        issues = dict()

        # Check the inputs for wavelength
        isInWSDefault = self.getProperty('InputWorkspace').isDefault
        isWlRangeDefault = self.getProperty('WavelengthRange').isDefault

        if isInWSDefault and isWlRangeDefault:
            issues['InputWorkspace'] = "Must select either InputWorkspace and WavelengthRange as input"
            issues['WavelengthRange'] = "Must select either InputWorkspace and WavelengthRange as input"

        if isInWSDefault and isWlRangeDefault:
            issues['InputWorkspace'] = "Cannot select both InputWorkspace and WavelengthRange as input"
            issues['WavelengthRange'] = "Cannot select both InputWorkspace and WavelengthRange as input"

        # Check the different inputs for the exponential term
        isDensityDefault = self.getProperty('Density').isDefault
        isFormulaDefault = self.getProperty('ChemicalFormula').isDefault
        isEffDefault     = self.getProperty('MeasuredEfficiency').isDefault
        isAlphaDefault   = self.getProperty('Alpha').isDefault

        if not isDensityDefault:
            if isFormulaDefault:
                issues['ChemicalFormula'] = "Must specify the ChemicalFormula with Density"

        if not isEffDefault:
            if isFormulaDefault:
                issues['ChemicalFormula'] = "Must specify the ChemicalFormula with MeasuredEfficiency"

        if not isEffDefault and not isDensityDefault:
            issues['MeasuredEfficiency'] = "Cannot select both MeasuredEfficiency and Density as input"
            issues['Density'] = "Cannot select both MeasuredEfficiency and Density as input"

        if not isAlphaDefault and not isDensityDefault:
            issues['Alpha'] = "Cannot select both Alpha and Density as input"
            issues['Density'] = "Cannot select both Alpha and Density as input"

        if not isEffDefault and not isAlphaDefault:
            issues['MeasuredEfficiency'] = "Cannot select both MeasuredEfficiency and Alpha as input"
            issues['Alpha'] = "Cannot select both MeasuredEfficiency and Alpha as input"

        return issues

    def _setup(self):
        self._input_ws = self.getProperty('InputWorkspace').value
        self._bin_params = self.getPropertyValue('WavelengthRange')
        self._output_ws = self.getProperty('OutputWorkspace').valueAsStr
        self._chemical_formula = self.getPropertyValue('ChemicalFormula')
        self._density_type = self.getPropertyValue('DensityType')
        self._density = self.getProperty('Density').value
        self._thickness = self.getProperty('Thickness').value
        self._efficiency = self.getProperty('MeasuredEfficiency').value
        self._efficiency_wavelength = self.getProperty('MeasuredEfficiencyWavelength').value
        self._alpha_absXS = self.getProperty('Alpha').value
        self._alpha_scatXS = 0.0
        self._xsection_type = self.getProperty('XSectionType').value

    def PyExec(self):
        self._setup()
        if not self.getProperty("InputWorkspace").isDefault:
            self._output_ws = CloneWorkspace(Inputworkspace=self._input_ws,
                                             OutputWorkspace=self._output_ws,
                                             StoreInADS=False)
        else:
            self._output_ws = CreateWorkspace(NSpec=1, DataX=[0], DataY=[0],
                                              UnitX='Wavelength', Distribution=False,
                                              StoreInADS=False)
            self._output_ws = Rebin(InputWorkspace=self._output_ws,
                                    Params=self._bin_params,
                                    StoreInADS=False)

        if self._output_ws.isDistribution():
            ConvertFromDistribution(Workspace=self._output_ws,
                                    StoreInADS=False)

        self._output_ws = ConvertToPointData(InputWorkspace=self._output_ws,
                                             StoreInADS=False)
        self._output_ws = ConvertUnits(InputWorkspace=self._output_ws,
                                       Target='Wavelength',
                                       EMode='Elastic',
                                       StoreInADS=False)

        if self.getProperty('Alpha').isDefault:
            SetSampleMaterial(
                InputWorkspace=self._output_ws,
                ChemicalFormula=self._chemical_formula,
                SampleNumberDensity=self._density,
                StoreInADS=False)
            if self.getProperty('MeasuredEfficiency').isDefault:
                self._calculate_area_density_from_density()
            else:
                self._calculate_area_density_from_efficiency()
            self._calculate_alpha_absXS_term()
            if self._xsection_type == "TotalXSection":
                self._calculate_alpha_scatXS_term()

        wavelengths = self._output_ws.readX(0)
        efficiency = self._calculate_efficiency(wavelengths)
        for histo in range(self._output_ws.getNumberHistograms()):
            self._output_ws.setY(histo, efficiency)

        self.setProperty('OutputWorkspace', self._output_ws)

    def _calculate_area_density_from_efficiency(self):
        """Calculates area density (atom/cm^2) using efficiency"""
        material = self._output_ws.sample().getMaterial()
        ref_absXS = material.absorbXSection()
        xs_term = ref_absXS * self._efficiency_wavelength / TABULATED_WAVELENGTH
        if self._xsection_type == "TotalXSection":
            xs_term += material.totalScatterXSection()
        self._area_density = - np.log( 1.0 - self._efficiency) / xs_term

    def _calculate_area_density_from_density(self):
        """Calculates area density (atom/cm^2) using number density and thickness."""
        if self._density_type == 'Mass Density':
            builder = MaterialBuilder().setFormula(self._chemical_formula)
            mat = builder.setMassDensity(self._density).build()
            self._density = mat.numberDensity
        self._area_density = self._density * self._thickness

    def _calculate_alpha_absXS_term(self):
        """Calculates absorption XS alpha term = area_density * absXS / 1.7982"""
        material = self._output_ws.sample().getMaterial()
        absXS = material.absorbXSection()  / TABULATED_WAVELENGTH
        self._alpha_absXS = self._area_density * absXS

    def _calculate_alpha_scatXS_term(self):
        """Calculates scattering XS alpha term = area_density * scatXS"""
        material = self._output_ws.sample().getMaterial()
        scatXS = material.totalScatterXSection()
        self._alpha_scatXS = self._area_density * scatXS

    def _calculate_efficiency(self, wavelength):
        """
        Calculates efficiency of a detector / monitor at a given wavelength.
        If using just the absorption cross section, _alpha_scatXS is == 0.

        @param wavelength Wavelength at which to calculate (in Angstroms)
        @return efficiency
        """
        efficiency = 1. / (1.0 - np.exp(-(self._alpha_scatXS + self._alpha_absXS * wavelength)))
        return efficiency