Пример #1
0
    def PyExec(self):
        config['default.facility'] = "SNS"
        config['default.instrument'] = self._long_inst
        self._doIndiv = self.getProperty("DoIndividual").value
        self._etBins = self.getProperty(
            "EnergyBins").value / MICROEV_TO_MILLIEV
        self._qBins = self.getProperty("MomentumTransferBins").value
        self._noMonNorm = self.getProperty("NoMonitorNorm").value
        self._maskFile = self.getProperty("MaskFile").value
        self._groupDetOpt = self.getProperty("GroupDetectors").value
        self._normalizeToFirst = self.getProperty("NormalizeToFirst").value
        self._normalizeToVanadium = self.getProperty("GroupDetectors").value
        self._doNorm = self.getProperty("DivideByVanadium").value

        datasearch = config["datasearch.searcharchive"]
        if datasearch != "On":
            config["datasearch.searcharchive"] = "On"

        # Handle masking file override if necessary
        self._overrideMask = bool(self._maskFile)
        if not self._overrideMask:
            config.appendDataSearchDir(DEFAULT_MASK_GROUP_DIR)
            self._maskFile = DEFAULT_MASK_FILE

        api.LoadMask(Instrument='BASIS',
                     OutputWorkspace='BASIS_MASK',
                     InputFile=self._maskFile)

        # Work around length issue
        _dMask = api.ExtractMask('BASIS_MASK')
        self._dMask = _dMask[1]
        api.DeleteWorkspace(_dMask[0])

        ############################
        ##  Process the Vanadium  ##
        ############################

        norm_runs = self.getProperty("NormRunNumbers").value
        if self._doNorm and bool(norm_runs):
            if ";" in norm_runs:
                raise SyntaxError("Normalization does not support run groups")
            self._doNorm = self.getProperty("NormalizationType").value
            self.log().information("Divide by Vanadium with normalization" +
                                   self._doNorm)

            # The following steps are common to all types of Vanadium normalization

            # norm_runs encompasses a single set, thus _getRuns returns
            # a list of only one item
            norm_set = self._getRuns(norm_runs, doIndiv=False)[0]
            self._normWs = self._sum_and_calibrate(norm_set,
                                                   extra_extension="_norm")

            # This rebin integrates counts onto a histogram of a single bin
            if self._doNorm == "by detectorID":
                normRange = self.getProperty("NormWavelengthRange").value
                self._normRange = [
                    normRange[0], normRange[1] - normRange[0], normRange[1]
                ]
                api.Rebin(InputWorkspace=self._normWs,
                          OutputWorkspace=self._normWs,
                          Params=self._normRange)

            # FindDetectorsOutsideLimits to be substituted by MedianDetectorTest
            api.FindDetectorsOutsideLimits(InputWorkspace=self._normWs,
                                           OutputWorkspace="BASIS_NORM_MASK")

            # additional reduction steps when normalizing by Q slice
            if self._doNorm == "by Q slice":
                self._normWs = self._group_and_SofQW(self._normWs,
                                                     self._etBins,
                                                     isSample=False)

        ##########################
        ##  Process the sample  ##
        ##########################
        self._run_list = self._getRuns(self.getProperty("RunNumbers").value,
                                       doIndiv=self._doIndiv)
        for run_set in self._run_list:
            self._samWs = self._sum_and_calibrate(run_set)
            self._samWsRun = str(run_set[0])
            # Mask detectors with insufficient Vanadium signal
            if self._doNorm:
                api.MaskDetectors(Workspace=self._samWs,
                                  MaskedWorkspace='BASIS_NORM_MASK')
            # Divide by Vanadium
            if self._doNorm == "by detector ID":
                api.Divide(LHSWorkspace=self._samWs,
                           RHSWorkspace=self._normWs,
                           OutputWorkspace=self._samWs)
            # additional reduction steps
            self._samSqwWs = self._group_and_SofQW(self._samWs,
                                                   self._etBins,
                                                   isSample=True)
            # Divide by Vanadium
            if self._doNorm == "by Q slice":
                api.Integration(InputWorkspace=self._normWs,
                                OutputWorkspace=self._normWs,
                                RangeLower=DEFAULT_VANADIUM_ENERGY_RANGE[0],
                                RangeUpper=DEFAULT_VANADIUM_ENERGY_RANGE[1])
                api.Divide(LHSWorkspace=self._samSqwWs,
                           RHSWorkspace=self._normWs,
                           OutputWorkspace=self._samSqwWs)
            # Clear mask from reduced file. Needed for binary operations
            # involving this S(Q,w)
            api.ClearMaskFlag(Workspace=self._samSqwWs)
            # Scale so that elastic line has Y-values ~ 1
            if self._normalizeToFirst:
                self._ScaleY(self._samSqwWs)
            # Output Dave and Nexus files
            extension = "_divided.dat" if self._doNorm else ".dat"
            dave_grp_filename = self._makeRunName(self._samWsRun,
                                                  False) + extension
            api.SaveDaveGrp(Filename=dave_grp_filename,
                            InputWorkspace=self._samSqwWs,
                            ToMicroEV=True)
            extension = "_divided_sqw.nxs" if self._doNorm else "_sqw.nxs"
            processed_filename = self._makeRunName(self._samWsRun,
                                                   False) + extension
            api.SaveNexus(Filename=processed_filename,
                          InputWorkspace=self._samSqwWs)
Пример #2
0
import mantid.simpleapi as mantid

# == Set parameters for calibration ==

filename = 'MAP14919.raw'  # Calibration run ( found in \\isis\inst$\NDXMAPS\Instrument\data\cycle_09_5 )
# Set what we want to calibrate (e.g whole instrument or one door )
CalibratedComponent = 'D2_window'  # Calibrate D2 window

# Get calibration raw file and integrate it
rawCalibInstWS = mantid.Load(
    filename)  # 'raw' in 'rawCalibInstWS' means unintegrated.
print("Integrating Workspace")
rangeLower = 2000  # Integrate counts in each spectra from rangeLower to rangeUpper
rangeUpper = 10000  #
CalibInstWS = mantid.Integration(rawCalibInstWS,
                                 RangeLower=rangeLower,
                                 RangeUpper=rangeUpper)
mantid.DeleteWorkspace(rawCalibInstWS)
print(
    "Created workspace (CalibInstWS) with integrated data from run and instrument to calibrate"
)

# == Create Objects needed for calibration ==

# The positions of the shadows and ends here are an intelligent guess.
# First array gives positions in Metres and second array gives type 1=Gaussian peak 2=edge.

knownPos = [-0.65, -0.22, -0.00, 0.22, 0.65]
funcForm = [2, 1, 1, 1, 2]

# Get fitting parameters
Пример #3
0
def CalibrateWish(run_per_panel_list):
    '''
    :param run_per_panel_list: is a list of tuples with the run number and the associated panel

    run_per_panel_list =  [ (17706, 'panel01'), (17705, 'panel02'),  (17701, 'panel03'), (17702, 'panel04'), (17695, 'panel05')]
    '''
    # == Set parameters for calibration ==
    previousDefaultInstrument = mantid.config['default.instrument']
    mantid.config['default.instrument'] = "WISH"

    # definition of the parameters static for the calibration
    lower_tube = numpy.array(
        [-0.41, -0.31, -0.21, -0.11, -0.02, 0.09, 0.18, 0.28, 0.39])
    upper_tube = numpy.array(lower_tube + 0.003)
    funcForm = 9 * [1]  # 9 gaussian peaks
    margin = 15
    low_range = list(range(0, 76))
    high_range = list(range(76, 152))
    kwargs = {'margin': margin}

    # it will copy all the data from the runs to have a single instrument with the calibrated data.
    whole_instrument = mantid.LoadRaw(str(run_per_panel_list[0][0]))
    whole_instrument = mantid.Integration(whole_instrument)

    for (run_number, panel_name) in run_per_panel_list:
        panel_name = str(panel_name)
        run_number = str(run_number)
        # load your data and integrate it
        ws = mantid.LoadRaw(run_number, OutputWorkspace=panel_name)
        ws = mantid.Integration(ws, 1, 20000, OutputWorkspace=panel_name)

        # use the TubeSpec object to be able to copy the data to the whole_instrument
        tube_set = TubeSpec(ws)
        tube_set.setTubeSpecByString(panel_name)

        # update kwargs argument before calling calibrate
        kwargs['rangeList'] = low_range  # calibrate only the lower tubes
        calibrationTable = tube.calibrate(ws, tube_set, lower_tube, funcForm,
                                          **kwargs)

        # update kwargs
        kwargs[
            'calibTable'] = calibrationTable  # append calib to calibrationtable
        kwargs['rangeList'] = high_range  # calibrate only the upper tubes

        calibrationTable = tube.calibrate(ws, tube_set, upper_tube, funcForm,
                                          **kwargs)
        kwargs['calibTable'] = calibrationTable

        mantid.ApplyCalibration(ws, calibrationTable)

        # copy data from the current panel to the whole_instrument
        for i in range(tube_set.getNumTubes()):
            for spec_num in tube_set.getTube(i):
                whole_instrument.setY(spec_num, ws.dataY(spec_num))

    # calibrate the whole_instrument with the last calibrated panel which has the calibration accumulation
    # of all the others
    mantid.CopyInstrumentParameters(run_per_panel_list[-1][1],
                                    whole_instrument)

    mantid.config['default.instrument'] = previousDefaultInstrument
Пример #4
0
# Here we run the calibration of WISH panel03
# We base the ideal tube on one tube of this door.
#

from __future__ import absolute_import, division, print_function

import tube
reload(tube) # noqa
from tube_spec import TubeSpec
import tube_calib #from tube_calib import constructIdealTubeFromRealTube
from tube_calib_fit_params import TubeCalibFitParams
import mantid.simpleapi as mantid

filename = 'WISH00017701.raw' # Calibration run ( found in \\isis\inst$\NDXWISH\Instrument\data\cycle_11_1 )
rawCalibInstWS = mantid.Load(filename)  #'raw' in 'rawCalibInstWS' means unintegrated.
CalibInstWS = mantid.Integration( rawCalibInstWS, RangeLower=1, RangeUpper=20000 )
mantid.DeleteWorkspace(rawCalibInstWS)
print("Created workspace (CalibInstWS) with integrated data from run and instrument to calibrate")

CalibratedComponent = 'WISH/panel03/tube038'

# Set fitting parameters
eP = [65.0, 113.0, 161.0, 209.0, 257.0, 305.0, 353.0, 401.0, 449.0]
ExpectedHeight = 2000.0 # Expected Height of Gaussian Peaks (initial value of fit parameter)
ExpectedWidth = 32.0 # Expected width of Gaussian peaks in pixels  (initial value of fit parameter)
fitPar = TubeCalibFitParams( eP, ExpectedHeight, ExpectedWidth )
fitPar.setAutomatic(True)
print("Created objects needed for calibration.")
func_form = 9*[1]

# Use first tube as ideal tube
Пример #5
0
    def PyExec(self):
        config['default.facility'] = 'SNS'
        config['default.instrument'] = 'ARCS'
        self._runs = self.getProperty('RunNumbers').value
        self._vanfile = self.getProperty('Vanadium').value
        self._ecruns = self.getProperty('EmptyCanRunNumbers').value
        self._ebins_str = self.getProperty('EnergyBins').value
        self._qbins_str = self.getProperty('MomentumTransferBins').value
        self._snorm = self.getProperty('NormalizeSlices').value
        self._clean = self.getProperty('CleanWorkspaces').value
        wn_sqes = self.getPropertyValue("OutputWorkspace")

        # workspace names
        prefix = ''
        if self._clean:
            prefix = '__'
        # Sample files
        wn_data = prefix + 'data'
        wn_van = prefix + 'vanadium'
        wn_reduced = prefix + 'reduced'
        wn_ste = prefix + 'S_theta_E'
        wn_van_st = prefix + 'vanadium_S_theta'
        wn_sten = prefix + 'S_theta_E_normalized'
        wn_steni = prefix + 'S_theta_E_normalized_interp'
        wn_sqe = prefix + 'S_Q_E'
        wn_sqeb = prefix + 'S_Q_E_binned'
        wn_sqesn = prefix + wn_sqes + '_norm'
        # Empty can files
        wn_ec_data = prefix + 'ec_data'
        wn_ec_reduced = prefix + 'ec_reduced'
        wn_ec_ste = prefix + 'ec_S_theta_E'

        datasearch = config["datasearch.searcharchive"]
        if datasearch != "On":
            config["datasearch.searcharchive"] = "On"

        # Load several event files into a sinle workspace. The nominal incident
        # energy should be the same to avoid difference in energy resolution
        api.Load(Filename=self._runs, OutputWorkspace=wn_data)

        # Load the vanadium file, assume to be preprocessed, meaning that
        # for every detector all events whithin a particular wide wavelength
        # range have been rebinned into a single histogram
        api.Load(Filename=self._vanfile, OutputWorkspace=wn_van)

        # Load empty can event files, if present
        if self._ecruns:
            api.Load(Filename=self._ecruns, OutputWorkspace=wn_ec_data)

        # Retrieve the mask from the vanadium workspace, and apply it to the data
        # (and empty can, if submitted)
        api.MaskDetectors(Workspace=wn_data, MaskedWorkspace=wn_van)
        if self._ecruns:
            api.MaskDetectors(Workspace=wn_ec_data, MaskedWorkspace=wn_van)

        # Obtain incident energy as the mean of the nominal Ei values.
        # There is one nominal value per events file.
        ws_data = api.mtd[wn_data]
        Ei = ws_data.getRun()['EnergyRequest'].getStatistics().mean
        Ei_std = ws_data.getRun()['EnergyRequest'].getStatistics(
        ).standard_deviation

        # Verify empty can runs were obtained at similar energy
        if self._ecruns:
            ws_ec_data = api.mtd[wn_ec_data]
            ec_Ei = ws_ec_data.getRun()['EnergyRequest'].getStatistics().mean
            if abs(Ei - ec_Ei) > Ei_std:
                raise RuntimeError(
                    'Empty can runs were obtained at a significant' +
                    ' different incident energy than the sample runs')

        # Obtain energy range
        self._ebins = [
            float(x)
            for x in re.compile(r'\d+[\.\d+]*').findall(self._ebins_str)
        ]
        if len(self._ebins) == 1:
            ws_data = api.mtd[wn_data]
            Ei = ws_data.getRun()['EnergyRequest'].getStatistics().mean
            self._ebins.insert(0, -0.5 * Ei)  # prepend
            self._ebins.append(0.95 * Ei)  # append

        # Enforce that the elastic energy (E=0) lies in the middle of the
        # central bin with an appropriate small shift in the energy range
        Ei_min_reduced = self._ebins[0] / self._ebins[1]
        remainder = Ei_min_reduced - int(Ei_min_reduced)
        if remainder >= 0.0:
            erange_shift = self._ebins[1] * (0.5 - remainder)
        else:
            erange_shift = self._ebins[1] * (-0.5 - remainder)
        self._ebins[0] += erange_shift  # shift minimum energy
        self._ebins[-1] += erange_shift  # shift maximum energy

        # Convert to energy transfer. Normalize by proton charge.
        # The output workspace is S(detector-id,E)
        factor = 0.1  # a fine energy bin
        Erange = '{0},{1},{2}'.format(self._ebins[0], factor * self._ebins[1],
                                      self._ebins[2])
        api.DgsReduction(SampleInputWorkspace=wn_data,
                         EnergyTransferRange=Erange,
                         OutputWorkspace=wn_reduced)
        if self._ecruns:
            api.DgsReduction(SampleInputWorkspace=wn_ec_data,
                             EnergyTransferRange=Erange,
                             IncidentBeamNormalisation='ByCurrent',
                             OutputWorkspace=wn_ec_reduced)

        # Obtain maximum and minimum |Q| values, as well as dQ if none passed
        self._qbins = [
            float(x)
            for x in re.compile(r'\d+[\.\d+]*').findall(self._qbins_str)
        ]
        if len(self._qbins) < 3:
            if not self._qbins:
                # insert dQ if empty qbins
                dE = self._ebins[1]
                self._qbins.append(
                    numpy.sqrt((Ei + dE) / ENERGY_TO_WAVEVECTOR) -
                    numpy.sqrt(Ei / ENERGY_TO_WAVEVECTOR))
            mins, maxs = api.ConvertToMDMinMaxLocal(wn_reduced,
                                                    Qdimensions='|Q|',
                                                    dEAnalysisMode='Direct')
            self._qbins.insert(0, mins[0])  # prepend minimum Q
            self._qbins.append(maxs[0])  # append maximum Q

        # Clean up the events files. They take a lot of space in memory
        api.DeleteWorkspace(wn_data)
        if self._ecruns:
            api.DeleteWorkspace(wn_ec_data)

        # Convert to S(theta,E)
        ki = numpy.sqrt(Ei / ENERGY_TO_WAVEVECTOR)
        factor = 1. / 5  # a reasonable (heuristic) value
        # If dE is the smallest energy transfer considered,
        # then dQ/ki is the smallest dtheta (in radians)
        dtheta = factor * self._qbins[1] / ki * (180.0 / numpy.pi)
        # very small dtheta (<0.15 degrees) prevents interpolation
        dtheta = max(0.15, dtheta)
        group_file_os_handle, group_file_name = mkstemp(suffix='.xml')
        group_file_handle = os.fdopen(group_file_os_handle, 'w')
        api.GenerateGroupingPowder(InputWorkspace=wn_reduced,
                                   AngleStep=dtheta,
                                   GroupingFilename=group_file_name)
        group_file_handle.close()
        api.GroupDetectors(InputWorkspace=wn_reduced,
                           MapFile=group_file_name,
                           OutputWorkspace=wn_ste)
        if self._ecruns:
            api.GroupDetectors(InputWorkspace=wn_ec_reduced,
                               MapFile=group_file_name,
                               OutputWorkspace=wn_ec_ste)
            # Substract the empty can from the can+sample
            api.Minus(LHSWorkspace=wn_ste,
                      RHSWorkspace=wn_ec_ste,
                      OutputWorkspace=wn_ste)

        # Normalize by the vanadium intensity, but before that we need S(theta)
        # for the vanadium. Recall every detector has all energies into a single
        # bin, so we get S(theta) instead of S(theta,E)
        api.GroupDetectors(InputWorkspace=wn_van,
                           MapFile=group_file_name,
                           OutputWorkspace=wn_van_st)
        os.remove(group_file_name)  # no need for this file
        api.Divide(wn_ste, wn_van_st, OutputWorkspace=wn_sten)
        api.ClearMaskFlag(Workspace=wn_sten)

        max_i_theta = 0.0
        min_i_theta = 0.0

        # Linear interpolation
        # First, find minimum theta index with a non-zero histogram
        ws_sten = api.mtd[wn_sten]
        for i_theta in range(ws_sten.getNumberHistograms()):
            if ws_sten.dataY(i_theta).any():
                min_i_theta = i_theta
                break
        # second, find maximum theta with a non-zero histogram
        for i_theta in range(ws_sten.getNumberHistograms() - 1, -1, -1):
            if ws_sten.dataY(i_theta).any():
                max_i_theta = i_theta
                break
        # Scan the region [min_i_theta, max_i_theta] and apply interpolation to
        # theta angles with no signal whatsoever, S(theta*, E)=0.0 for all energies
        api.CloneWorkspace(InputWorkspace=wn_sten, OutputWorkspace=wn_steni)
        ws_steni = api.mtd[wn_steni]
        i_theta = 1 + min_i_theta
        while i_theta < max_i_theta:
            if not ws_steni.dataY(i_theta).any():
                nonnull_i_theta_start = i_theta - 1  # angle index of non-null histogram
                # scan until we find a non-null histogram
                while not ws_steni.dataY(i_theta).any():
                    i_theta += 1
                nonnull_i_theta_end = i_theta  # angle index of non-null histogram
                # The range [1+nonnull_i_theta_start, nonnull_i_theta_end]
                # contains only null-histograms. Interpolate!
                y_start = ws_steni.dataY(nonnull_i_theta_start)
                y_end = ws_steni.dataY(nonnull_i_theta_end)
                intercept = y_start
                slope = (y_end - y_start) / (nonnull_i_theta_end -
                                             nonnull_i_theta_start)
                for null_i_theta in range(1 + nonnull_i_theta_start,
                                          nonnull_i_theta_end):
                    ws_steni.dataY(null_i_theta)[:] = intercept + slope * (
                        null_i_theta - nonnull_i_theta_start)
            i_theta += 1

        # Convert S(theta,E) to S(Q,E), then rebin in |Q| and E to MD workspace
        api.ConvertToMD(InputWorkspace=wn_steni,
                        QDimensions='|Q|',
                        dEAnalysisMode='Direct',
                        OutputWorkspace=wn_sqe)
        Qmin = self._qbins[0]
        Qmax = self._qbins[-1]
        dQ = self._qbins[1]
        Qrange = '|Q|,{0},{1},{2}'.format(Qmin, Qmax, int((Qmax - Qmin) / dQ))
        Ei_min = self._ebins[0]
        Ei_max = self._ebins[-1]
        dE = self._ebins[1]
        deltaErange = 'DeltaE,{0},{1},{2}'.format(Ei_min, Ei_max,
                                                  int((Ei_max - Ei_min) / dE))
        api.BinMD(InputWorkspace=wn_sqe,
                  AxisAligned=1,
                  AlignedDim0=Qrange,
                  AlignedDim1=deltaErange,
                  OutputWorkspace=wn_sqeb)

        # Slice the data by transforming to a Matrix2Dworkspace, with deltaE along the vertical axis
        api.ConvertMDHistoToMatrixWorkspace(
            InputWorkspace=wn_sqeb,
            Normalization='NumEventsNormalization',
            OutputWorkspace=wn_sqes)

        # Shift the energy axis, since the reported values should be the center
        # of the bins, instead of the minimum bin boundary
        ws_sqes = api.mtd[wn_sqes]
        Eaxis = ws_sqes.getAxis(1)
        e_shift = self._ebins[1] / 2.0
        for i in range(Eaxis.length()):
            Eaxis.setValue(i, Eaxis.getValue(i) + e_shift)

        # Normalize each slice
        if self._snorm:
            api.Integration(InputWorkspace=wn_sqes, OutputWorkspace=wn_sqesn)
            api.Divide(LHSWorkspace=wn_sqes,
                       RHSWorkspace=wn_sqesn,
                       OutputWorkspace=wn_sqes)

        # Clean up workspaces from intermediate steps
        if self._clean:
            for name in (wn_van, wn_reduced, wn_ste, wn_van_st, wn_sten,
                         wn_steni, wn_sqe, wn_sqeb, wn_sqesn):
                api.DeleteWorkspace(name)
            if api.mtd.doesExist('PreprocessedDetectorsWS'):
                api.DeleteWorkspace('PreprocessedDetectorsWS')

        # Ouput some info
        message = '\n******  SOME OUTPUT INFORMATION ***' + \
                  '\nEnergy bins: ' + ', '.join(['{0:.2f}'.format(x) for x in self._ebins]) + \
                  '\nQ bins: ' + ', '.join(['{0:.2f}'.format(x) for x in self._qbins]) + \
                  '\nTheta bins: {0:.2f} {1:.2f} {2:.2f}'.format(min_i_theta * dtheta, dtheta, max_i_theta * dtheta)
        logger.notice(message)

        self.setProperty("OutputWorkspace", api.mtd[wn_sqes])
Пример #6
0
def CalibrateMerlin(RunNumber):
    # == Set parameters for calibration ==
    previousDefaultInstrument = mantid.config['default.instrument']
    mantid.config['default.instrument'] = "MERLIN"
    filename = str(RunNumber)  # Name of calibration run.
    rangeLower = 3000  # Integrate counts in each spectra from rangeLower to rangeUpper
    rangeUpper = 20000  #

    # Set parameters for ideal tube.
    Left = 2.0  # Where the left end of tube should be in pixels (target for AP)
    Centre = 512.5  # Where the centre of the tube should be in pixels (target for CP)
    Right = 1023.0  # Where the right of the tube should be in pixels (target for BP)
    ActiveLength = 2.9  # Active length of tube in Metres

    # Set initial parameters for peak finding
    ExpectedHeight = 1000.0  # Expected Height of Gaussian Peaks (initial value of fit parameter)
    ExpectedWidth = 32.0  # Expected width of centre peak in Pixels (initial value of fit parameter)
    ExpectedPositions = [
        35.0, 512.0, 989.0
    ]  # Expected positions of the edges and peak in pixels (initial values of fit parameters)

    # Set what we want to calibrate (e.g whole instrument or one door )
    CalibratedComponent = 'MERLIN'  # Calibrate door 2

    # Get calibration raw file and integrate it
    print(filename)
    rawCalibInstWS = mantid.LoadRaw(filename)
    # 'raw' in 'rawCalibInstWS' means unintegrated.
    print("Integrating Workspace")
    CalibInstWS = mantid.Integration(rawCalibInstWS,
                                     RangeLower=rangeLower,
                                     RangeUpper=rangeUpper)
    mantid.DeleteWorkspace(rawCalibInstWS)
    print(
        "Created workspace (CalibInstWS) with integrated data from run and instrument to calibrate"
    )

    # == Create Objects needed for calibration ==

    ## In the merlin case, the positions are usually given in pixels, instead of being given in
    ## meters, to convert to meter and put the origin in the center, we have to apply the following
    ## transformation:
    ##
    ## pos = pixel * length/npixels - length/2 = length (pixel/npixels - 1/2)
    ##
    ## for merlin: npixels = 1024

    knownPos = ActiveLength * (numpy.array([Left, Centre, Right]) / 1024.0 -
                               0.5)
    funcForm = 3 * [1]

    # Get fitting parameters
    fitPar = TubeCalibFitParams(ExpectedPositions,
                                ExpectedHeight,
                                ExpectedWidth,
                                margin=40)

    print("Created objects needed for calibration.")

    # == Get the calibration and put results into calibration table ==
    # also put peaks into PeakFile
    calibrationTable, peakTable = tube.calibrate(CalibInstWS,
                                                 CalibratedComponent,
                                                 knownPos,
                                                 funcForm,
                                                 outputPeak=True,
                                                 fitPar=fitPar,
                                                 plotTube=list(
                                                     range(0, 280, 20)))
    print(
        "Got calibration (new positions of detectors) and put slit peaks into file TubeDemoMerlin01.txt"
    )

    # == Apply the Calibation ==
    mantid.ApplyCalibration(Workspace=CalibInstWS,
                            CalibrationTable=calibrationTable)
    print("Applied calibration")

    # == Save workspace ==
    # mantid.SaveNexusProcessed(CalibInstWS, 'TubeCalibDemoMerlinResult.nxs', "Result of Running TubeCalibDemoMerlin_Simple.py")
    # print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMerlinResult.nxs")

    # == Reset default instrument ==
    mantid.config['default.instrument'] = previousDefaultInstrument
Пример #7
0
def normalise_workspace(ws_name):
    tmp_norm = sapi.Integration(ws_name)
    sapi.Divide(LHSWorkspace=ws_name,RHSWorkspace="tmp_norm",OutputWorkspace=ws_name)
    safe_delete_ws(tmp_norm)
def generate_plots(run_number, workspace, options=None):
    """
        Generate diagnostics plots
    """
    n_x = int(
        workspace.getInstrument().getNumberParameter("number-of-x-pixels")[0])
    n_y = int(
        workspace.getInstrument().getNumberParameter("number-of-y-pixels")[0])

    # X-TOF plot
    tof_min = workspace.getTofMin()
    tof_max = workspace.getTofMax()
    workspace = api.Rebin(workspace, params="%s, 50, %s" % (tof_min, tof_max))

    direct_summed = api.RefRoi(InputWorkspace=workspace,
                               IntegrateY=True,
                               NXPixel=n_x,
                               NYPixel=n_y,
                               ConvertToQ=False,
                               YPixelMin=0,
                               YPixelMax=n_y,
                               OutputWorkspace="direct_summed")
    signal = np.log10(direct_summed.extractY())
    tof_axis = direct_summed.extractX()[0] / 1000.0

    x_tof_plot = _plot2d(z=signal,
                         y=np.arange(signal.shape[0]),
                         x=tof_axis,
                         x_label="TOF (ms)",
                         y_label="X pixel",
                         title="r%s" % run_number)

    # X-Y plot
    _workspace = api.Integration(workspace)
    signal = np.log10(_workspace.extractY())
    z = np.reshape(signal, (n_x, n_y))
    xy_plot = _plot2d(z=z.T,
                      x=np.arange(n_x),
                      y=np.arange(n_y),
                      title="r%s" % run_number)

    # Count per X pixel
    integrated = api.Integration(direct_summed)
    integrated = api.Transpose(integrated)
    signal_y = integrated.readY(0)
    signal_x = np.arange(len(signal_y))
    peak_pixels = _plot1d(signal_x,
                          signal_y,
                          x_label="X pixel",
                          y_label="Counts",
                          title="r%s" % run_number)

    # TOF distribution
    workspace = api.SumSpectra(workspace)
    signal_x = workspace.readX(0) / 1000.0
    signal_y = workspace.readY(0)
    tof_dist = _plot1d(signal_x,
                       signal_y,
                       x_range=None,
                       x_label="TOF (ms)",
                       y_label="Counts",
                       title="r%s" % run_number)

    return [xy_plot, x_tof_plot, peak_pixels, tof_dist]
Пример #9
0
    def PyExec(self):
        self._runs = self.getProperty('RunNumbers').value
        self._vanfile = self.getProperty('Vanadium').value
        self._ecruns = self.getProperty('EmptyCanRunNumbers').value
        self._ebins = (self.getProperty('EnergyBins').value).tolist()
        self._qbins = (self.getProperty('MomentumTransferBins').value).tolist()
        self._snorm = self.getProperty('NormalizeSlices').value
        self._clean = self.getProperty('CleanWorkspaces').value
        wn_sqes = self.getPropertyValue("OutputWorkspace")

        # workspace names
        prefix = ''
        if self._clean:
            prefix = '__'
        # "wn" denotes workspace name
        wn_data = prefix + 'data'  # Accumulated data events
        wn_data_mon = prefix + 'data_monitors'  # Accumulated monitors for data
        wn_van = prefix + 'vanadium'  # White-beam vanadium
        wn_van_st = prefix + 'vanadium_S_theta'
        wn_reduced = prefix + 'reduced'  # data after DGSReduction
        wn_ste = prefix + 'S_theta_E'  # data after grouping by theta angle
        wn_sten = prefix + 'S_theta_E_normalized'
        wn_steni = prefix + 'S_theta_E_interp'
        wn_sqe = prefix + 'S_Q_E'
        wn_sqeb = prefix + 'S_Q_E_binned'
        wn_sqesn = prefix + wn_sqes + '_norm'
        # Empty can files
        wn_ec_data = prefix + 'ec_data'  # Accumulated empty can data
        wn_ec_data_mon = prefix + 'ec_data_monitors'  # Accumulated monitors for empty can
        wn_ec_reduced = prefix + 'ec_reduced'  # empty can data after DGSReduction
        wn_ec_ste = prefix + 'ec_S_theta_E'  # empty can data after grouping by theta angle

        # Save current configuration
        facility = config['default.facility']
        instrument = config['default.instrument']
        datasearch = config["datasearch.searcharchive"]
        # Allows searching for ARCS run numbers
        config['default.facility'] = 'SNS'
        config['default.instrument'] = 'ARCS'
        config["datasearch.searcharchive"] = "On"

        try:
            # Load the vanadium file, assumed to be preprocessed, meaning that
            # for every detector all events within a particular wide wavelength
            # range have been rebinned into a single histogram
            self._load(self._vanfile, wn_van)
            # Check for white-beam vanadium, true if the vertical chopper is absent (vChTrans==2)
            if api.mtd[wn_van].run().getProperty('vChTrans').value[0] != 2:
                raise ValueError("White-vanadium is required")

            # Load several event files into a single workspace. The nominal incident
            # energy should be the same to avoid difference in energy resolution
            self._load(self._runs, wn_data)

            # Load empty can event files, if present
            if self._ecruns:
                self._load(self._ecruns, wn_ec_data)

        finally:
            # Recover the default configuration
            config['default.facility'] = facility
            config['default.instrument'] = instrument
            config["datasearch.searcharchive"] = datasearch

        # Obtain incident energy as the mean of the nominal Ei values.
        # There is one nominal value for each run number.
        ws_data = sapi.mtd[wn_data]
        Ei = ws_data.getRun()['EnergyRequest'].getStatistics().mean
        Ei_std = ws_data.getRun()['EnergyRequest'].getStatistics(
        ).standard_deviation

        # Verify empty can runs were obtained at similar energy
        if self._ecruns:
            ws_ec_data = sapi.mtd[wn_ec_data]
            ec_Ei = ws_ec_data.getRun()['EnergyRequest'].getStatistics().mean
            if abs(Ei - ec_Ei) > Ei_std:
                raise RuntimeError(
                    'Empty can runs were obtained at a significant' +
                    ' different incident energy than the sample runs')

        # Obtain energy range. If user did not supply a triad
        # [Estart, Ewidth, Eend] but only Ewidth, then estimate
        # Estart and End from the nominal energies
        if len(self._ebins) == 1:
            ws_data = sapi.mtd[wn_data]
            Ei = ws_data.getRun()['EnergyRequest'].getStatistics().mean
            self._ebins.insert(0, -0.5 * Ei)  # prepend
            self._ebins.append(0.95 * Ei)  # append

        # Enforce that the elastic energy (E=0) lies in the middle of the
        # central bin with an appropriate small shift in the energy range
        Ei_min_reduced = self._ebins[0] / self._ebins[1]
        remainder = Ei_min_reduced - int(Ei_min_reduced)
        if remainder >= 0.0:
            erange_shift = self._ebins[1] * (0.5 - remainder)
        else:
            erange_shift = self._ebins[1] * (-0.5 - remainder)
        self._ebins[0] += erange_shift  # shift minimum energy
        self._ebins[-1] += erange_shift  # shift maximum energy

        # Convert to energy transfer. Normalize by proton charge.
        # The output workspace is S(detector-id,E)
        factor = 0.1  # use a finer energy bin than the one passed (self._ebins[1])
        Erange = '{0},{1},{2}'.format(self._ebins[0], factor * self._ebins[1],
                                      self._ebins[2])
        Ei_calc, T0 = sapi.GetEiT0atSNS(MonitorWorkspace=wn_data_mon,
                                        IncidentEnergyGuess=Ei)
        sapi.MaskDetectors(Workspace=wn_data,
                           MaskedWorkspace=wn_van)  # Use vanadium mask
        sapi.DgsReduction(SampleInputWorkspace=wn_data,
                          SampleInputMonitorWorkspace=wn_data_mon,
                          IncidentEnergyGuess=Ei_calc,
                          UseIncidentEnergyGuess=1,
                          TimeZeroGuess=T0,
                          EnergyTransferRange=Erange,
                          IncidentBeamNormalisation='ByCurrent',
                          OutputWorkspace=wn_reduced)

        if self._ecruns:
            sapi.MaskDetectors(Workspace=wn_ec_data, MaskedWorkspace=wn_van)
            sapi.DgsReduction(SampleInputWorkspace=wn_ec_data,
                              SampleInputMonitorWorkspace=wn_ec_data_mon,
                              IncidentEnergyGuess=Ei_calc,
                              UseIncidentEnergyGuess=1,
                              TimeZeroGuess=T0,
                              EnergyTransferRange=Erange,
                              IncidentBeamNormalisation='ByCurrent',
                              OutputWorkspace=wn_ec_reduced)

        # Obtain maximum and minimum |Q| values, as well as dQ if none passed
        if len(self._qbins) < 3:
            if not self._qbins:
                # insert dQ if empty qbins. The minimal momentum transfer
                # is the result on an event where the initial energy was
                # Ei and the final energy was Ei+dE.
                dE = self._ebins[1]
                self._qbins.append(
                    numpy.sqrt((Ei + dE) / ENERGY_TO_WAVEVECTOR) -
                    numpy.sqrt(Ei / ENERGY_TO_WAVEVECTOR))
            mins, maxs = sapi.ConvertToMDMinMaxLocal(wn_reduced,
                                                     Qdimensions='|Q|',
                                                     dEAnalysisMode='Direct')
            self._qbins.insert(0, mins[0])  # prepend minimum Q
            self._qbins.append(maxs[0])  # append maximum Q

        # Delete sample and empty can event workspaces to free memory.
        if self._clean:
            sapi.DeleteWorkspace(wn_data)
            if self._ecruns:
                sapi.DeleteWorkspace(wn_ec_data)

        # Convert to S(theta,E)
        ki = numpy.sqrt(Ei / ENERGY_TO_WAVEVECTOR)
        # If dE is the smallest energy transfer considered,
        # then dQ/ki is the smallest dtheta (in radians)
        dtheta = self._qbins[1] / ki * (180.0 / numpy.pi)
        # Use a finer dtheta that the nominal smallest value
        factor = 1. / 5  # a reasonable (heuristic) value
        dtheta *= factor
        # Fix: a very small dtheta (<0.15 degrees) prevents correct interpolation
        dtheta = max(0.15, dtheta)
        # Group detectors according to theta angle for the sample runs
        group_file_os_handle, group_file_name = mkstemp(suffix='.xml')
        group_file_handle = os.fdopen(group_file_os_handle, 'w')
        sapi.GenerateGroupingPowder(InputWorkspace=wn_reduced,
                                    AngleStep=dtheta,
                                    GroupingFilename=group_file_name)
        group_file_handle.close()
        sapi.GroupDetectors(InputWorkspace=wn_reduced,
                            MapFile=group_file_name,
                            OutputWorkspace=wn_ste)
        # Group detectors according to theta angle for the emtpy can run
        if self._ecruns:
            sapi.GroupDetectors(InputWorkspace=wn_ec_reduced,
                                MapFile=group_file_name,
                                OutputWorkspace=wn_ec_ste)
            # Subtract the empty can from the can+sample
            sapi.Minus(LHSWorkspace=wn_ste,
                       RHSWorkspace=wn_ec_ste,
                       OutputWorkspace=wn_ste)

        # Normalize by the vanadium intensity, but before that we need S(theta)
        # for the vanadium. Recall every detector has all energies into a single
        # bin, so we get S(theta) instead of S(theta,E)
        sapi.GroupDetectors(InputWorkspace=wn_van,
                            MapFile=group_file_name,
                            OutputWorkspace=wn_van_st)
        # Divide by vanadium. Make sure it is integrated in the energy domain
        sapi.Integration(wn_van_st, OutputWorkspace=wn_van_st)
        sapi.Divide(wn_ste, wn_van_st, OutputWorkspace=wn_sten)
        sapi.ClearMaskFlag(Workspace=wn_sten)

        # Temporary file generated by GenerateGroupingPowder to be removed
        os.remove(group_file_name)  # no need for this file
        os.remove(os.path.splitext(group_file_name)[0] + ".par")

        max_i_theta = 0.0
        min_i_theta = 0.0

        # Linear interpolation for those theta values with low intensity
        # First, find minimum theta index with a non-zero histogram
        ws_sten = sapi.mtd[wn_sten]

        for i_theta in range(ws_sten.getNumberHistograms()):
            if ws_sten.dataY(i_theta).any():
                min_i_theta = i_theta
                break
        # second, find maximum theta with a non-zero histogram
        for i_theta in range(ws_sten.getNumberHistograms() - 1, -1, -1):
            if ws_sten.dataY(i_theta).any():
                max_i_theta = i_theta
                break

        # Scan a range of theta angles and apply interpolation to those theta angles
        # with considerably low intensity (gaps)
        delta_theta = max_i_theta - min_i_theta
        gaps = self._findGaps(wn_sten, int(min_i_theta + 0.1 * delta_theta),
                              int(max_i_theta - 0.1 * delta_theta))
        sapi.CloneWorkspace(InputWorkspace=wn_sten, OutputWorkspace=wn_steni)
        for gap in gaps:
            self._interpolate(wn_steni, gap)  # interpolate this gap

        # Convert S(theta,E) to S(Q,E), then rebin in |Q| and E to MD workspace
        sapi.ConvertToMD(InputWorkspace=wn_steni,
                         QDimensions='|Q|',
                         dEAnalysisMode='Direct',
                         OutputWorkspace=wn_sqe)
        Qmin = self._qbins[0]
        Qmax = self._qbins[-1]
        dQ = self._qbins[1]
        Qrange = '|Q|,{0},{1},{2}'.format(Qmin, Qmax, int((Qmax - Qmin) / dQ))
        Ei_min = self._ebins[0]
        Ei_max = self._ebins[-1]
        dE = self._ebins[1]
        deltaErange = 'DeltaE,{0},{1},{2}'.format(Ei_min, Ei_max,
                                                  int((Ei_max - Ei_min) / dE))
        sapi.BinMD(InputWorkspace=wn_sqe,
                   AxisAligned=1,
                   AlignedDim0=Qrange,
                   AlignedDim1=deltaErange,
                   OutputWorkspace=wn_sqeb)

        # Slice the data by transforming to a Matrix2Dworkspace,
        # with deltaE along the vertical axis
        sapi.ConvertMDHistoToMatrixWorkspace(
            InputWorkspace=wn_sqeb,
            Normalization='NumEventsNormalization',
            OutputWorkspace=wn_sqes)

        # Ensure correct units
        sapi.mtd[wn_sqes].getAxis(0).setUnit("MomentumTransfer")
        sapi.mtd[wn_sqes].getAxis(1).setUnit("DeltaE")

        # Shift the energy axis, since the reported values should be the center
        # of the bins, instead of the minimum bin boundary
        ws_sqes = sapi.mtd[wn_sqes]
        Eaxis = ws_sqes.getAxis(1)
        e_shift = self._ebins[1] / 2.0
        for i in range(Eaxis.length()):
            Eaxis.setValue(i, Eaxis.getValue(i) + e_shift)

        # Normalize each slice, if requested
        if self._snorm:
            sapi.Integration(InputWorkspace=wn_sqes, OutputWorkspace=wn_sqesn)
            sapi.Divide(LHSWorkspace=wn_sqes,
                        RHSWorkspace=wn_sqesn,
                        OutputWorkspace=wn_sqes)

        # Clean up workspaces from intermediate steps
        if self._clean:
            for name in (wn_van, wn_reduced, wn_ste, wn_van_st, wn_sten,
                         wn_steni, wn_sqe, wn_sqeb, wn_sqesn,
                         'PreprocessedDetectorsWS'):
                if sapi.mtd.doesExist(name):
                    sapi.DeleteWorkspace(name)

        # Ouput some info as a Notice in the log
        ebins = ', '.join(['{0:.2f}'.format(x) for x in self._ebins])
        qbins = ', '.join(['{0:.2f}'.format(x) for x in self._qbins])
        tbins = '{0:.2f} {1:.2f} {2:.2f}'.format(min_i_theta * dtheta, dtheta,
                                                 max_i_theta * dtheta)
        message = '\n******  SOME OUTPUT INFORMATION ***' + \
                  '\nEnergy bins: ' + ebins + \
                  '\nQ bins: ' + qbins + \
                  '\nTheta bins: '+tbins
        kapi.logger.notice(message)

        self.setProperty("OutputWorkspace", sapi.mtd[wn_sqes])
Пример #10
0
def CalibrateWish(RunNumber, PanelNumber):
    '''
    :param RunNumber: is the run number of the calibration.
    :param PanelNumber: is a string of two-digit number of the panel being calibrated
    '''
    # == Set parameters for calibration ==
    previousDefaultInstrument = mantid.config['default.instrument']
    mantid.config['default.instrument'] = "WISH"
    filename = str(RunNumber)
    CalibratedComponent = 'WISH/panel' + PanelNumber

    # Get calibration raw file and integrate it
    print("Loading", filename)
    rawCalibInstWS = mantid.Load(
        filename)  # 'raw' in 'rawCalibInstWS' means unintegrated.
    CalibInstWS = mantid.Integration(rawCalibInstWS,
                                     RangeLower=1,
                                     RangeUpper=20000)
    mantid.DeleteWorkspace(rawCalibInstWS)
    print(
        "Created workspace (CalibInstWS) with integrated data from run and instrument to calibrate"
    )

    # Give y-positions of slit points (gotten for converting first tube's slit point to Y)

    # WISH instrument has a particularity. It is composed by a group of upper tubes and lower tubes,
    # they are disposed 3 milimiters in difference one among the other
    lower_tube = numpy.array(
        [-0.41, -0.31, -0.21, -0.11, -0.02, 0.09, 0.18, 0.28, 0.39])
    upper_tube = numpy.array(lower_tube + 0.003)
    funcForm = 9 * [1]  # 9 gaussian peaks
    print("Created objects needed for calibration.")

    # Get the calibration and put it into the calibration table

    # calibrate the lower tubes
    calibrationTable, peakTable = tube.calibrate(CalibInstWS,
                                                 CalibratedComponent,
                                                 lower_tube,
                                                 funcForm,
                                                 rangeList=list(range(0, 76)),
                                                 outputPeak=True)

    # calibrate the upper tubes
    calibrationTable, peakTable = tube.calibrate(
        CalibInstWS,
        CalibratedComponent,
        upper_tube,
        funcForm,
        rangeList=list(range(76, 152)),
        calibTable=calibrationTable,
        # give the calibration table to append data
        outputPeak=peakTable  # give peak table to append data
    )

    print("Got calibration (new positions of detectors)")

    # Apply the calibration
    mantid.ApplyCalibration(Workspace=CalibInstWS,
                            PositionTable=calibrationTable)
    print("Applied calibration")

    # == Save workspace ==
    # uncomment these lines to save the workspace
    # nexusName = "TubeCalibDemoWish"+PanelNumber+"Result.nxs"
    # SaveNexusProcessed( CalibInstWS, 'TubeCalibDemoWishResult.nxs',"Result of Running TubeCalibWishMerlin_Simple.py")
    # print "saved calibrated workspace (CalibInstWS) into Nexus file",nexusName

    # == Reset dafault instrument ==
    mantid.config['default.instrument'] = previousDefaultInstrument
Пример #11
0
def calibrateMerlin(filename):
    # == Set parameters for calibration ==

    rangeLower = 3000  # Integrate counts in each spectra from rangeLower to rangeUpper
    rangeUpper = 20000  #

    # Get calibration raw file and integrate it
    rawCalibInstWS = mantid.LoadRaw(filename)  # 'raw' in 'rawCalibInstWS' means unintegrated.
    print("Integrating Workspace")
    CalibInstWS = mantid.Integration(rawCalibInstWS, RangeLower=rangeLower, RangeUpper=rangeUpper)
    mantid.DeleteWorkspace(rawCalibInstWS)
    print("Created workspace (CalibInstWS) with integrated data from run and instrument to calibrate")

    # the known positions are given in pixels inside the tubes and transformed to provide the positions
    # with the center of the tube as the origin
    knownPositions = 2.92713867188 * (numpy.array([27.30074322, 92.5, 294.65178585, 362.37861919,
                                                   512.77103043, 663.41425323, 798.3223896, 930.9,
                                                   997.08480835]) / 1024 - 0.5)
    funcForm = numpy.array([2, 2, 1, 1, 1, 1, 1, 2, 2], numpy.int8)
    # The calibration will follow different steps for sets of tubes

    # For the door9, the best points to define the known positions are the 1st edge, 5 peaks, last edge.
    points7 = knownPositions[[0, 2, 3, 4, 5, 6, 8]]
    points7func = funcForm[[0, 2, 3, 4, 5, 6, 8]]

    door9pos = points7
    door9func = points7func
    CalibratedComponent = 'MERLIN/door9'  # door9
    # == Get the calibration and put results into calibration table ==
    # also put peaks into PeakFile
    calibrationTable, peakTable = tube.calibrate(CalibInstWS, CalibratedComponent, door9pos, door9func,
                                                 outputPeak=True,
                                                 margin=30,
                                                 rangeList=list(range(20))
                                                 # because 20, 21, 22, 23 are defective detectors
                                                 )
    print("Got calibration (new positions of detectors) and put slit peaks into file TubeDemoMerlin01.txt")
    analisePeakTable(peakTable, 'door9_tube1_peaks')

    # For the door8, the best points to define the known positions are the 1st edge, 5 peaks, last_edge
    door8pos = points7
    door8func = points7func
    CalibratedComponent = 'MERLIN/door8'
    calibrationTable, peakTable = tube.calibrate(CalibInstWS, CalibratedComponent, door8pos,
                                                 door8func,
                                                 outputPeak=True,  # change to peakTable to append to peakTable
                                                 calibTable=calibrationTable,
                                                 margin=30)
    analisePeakTable(peakTable, 'door8_peaks')

    # For the doors 7,6,5,4, 2, 1 we may use the 9 points
    doorpos = knownPositions
    doorfunc = funcForm
    CalibratedComponent = ['MERLIN/door%d' % (i) for i in [7, 6, 5, 4, 2, 1]]
    calibrationTable, peakTable = tube.calibrate(CalibInstWS, CalibratedComponent, doorpos,
                                                 doorfunc,
                                                 outputPeak=True,
                                                 calibTable=calibrationTable,
                                                 margin=30)
    analisePeakTable(peakTable, 'door1to7_peaks')

    # The door 3 is a special case, because it is composed by diffent kind of tubes.
    # door 3 tubes: 5_8, 5_7, 5_6, 5_5, 5_4, 5_3, 5_2, 5_1, 4_8, 4_7, 4_6, 4_5, 4_4, 4_3, 4_2, 4_1, 3_8, 3_7, 3_6, 3_5, 3_4
    # obeys the same rules as the doors 7, 6, 5, 4, 2, 1
    # For the tubes 3_3, 3_2, 3_1 -> it is better to skip the central peak
    # For the tubes 1_x (smaller tube below), it is better to take the final part of known positions: peak4,peak5,edge6,edge7
    # For the tubes 2_x (smaller tube above, it is better to take the first part of known positions: edge1, edge2, peak1,peak2

    # NOTE: the smaller tubes they have length = 1.22879882813, but 1024 detectors
    # so we have to correct the known positiosn by multiplying by its length and dividing by the longer dimension

    from tube_calib_fit_params import TubeCalibFitParams

    # calibrating tubes 1_x
    CalibratedComponent = ['MERLIN/door3/tube_1_%d' % (i) for i in range(1, 9)]

    half_diff_center = (
                           2.92713867188 - 1.22879882813) / 2
    # difference among the expected center position for
    # both tubes here a little bit of attempts is necessary.
    # The effective center position and length is different for the calibrated tube, that is the reason,
    # the calibrated values of the smaller tube does not seems aligned with the others. By, finding the
    # 'best' half_diff_center value, the alignment occurs nicely.
    half_diff_center = 0.835  #

    # the knownpositions were given with the center of the bigger tube as origin, to convert
    # to the center of the upper tube as origin is necessary to subtract them with  the half_diff_center
    doorpos = knownPositions[[5, 6, 7, 8]] - half_diff_center
    doorfunc = [1, 1, 2, 2]
    # for the smal tubes, automatically searching for the peak position in pixel was not working quite well,
    # so we will give the approximate position for these tubes through fitPar argument
    fitPar = TubeCalibFitParams([216, 527, 826, 989])
    fitPar.setAutomatic(True)

    calibrationTable, peakTable = tube.calibrate(CalibInstWS, CalibratedComponent, doorpos,
                                                 doorfunc,
                                                 outputPeak=True,
                                                 fitPar=fitPar,
                                                 calibTable=calibrationTable,
                                                 margin=30)
    analisePeakTable(peakTable, 'door3_tube1_peaks')

    # calibrating tubes 2_x
    CalibratedComponent = ['MERLIN/door3/tube_2_%d' % (i) for i in range(1,9)]
    # the knownpositions were given with the center of the bigger tube as origin, to convert
    # to the center of the lower tube as origin is necessary to sum them with  (len_big - len_small)/2
    doorpos = knownPositions[[0, 1, 2, 3]] + half_diff_center
    doorfunc = [2, 2, 1, 1]

    # for the smal tubes, automatically searching for the peak position in pixel was not working quite well,
    # so we will give the approximate position for these tubes through fitPar argument
    fitPar = TubeCalibFitParams([50, 202, 664, 815])
    fitPar.setAutomatic(True)

    calibrationTable, peakTable = tube.calibrate(CalibInstWS, CalibratedComponent, doorpos,
                                                 doorfunc,
                                                 outputPeak=True,
                                                 calibTable=calibrationTable,
                                                 fitPar=fitPar,
                                                 margin=30)

    analisePeakTable(peakTable, 'door3_tube2_peaks')

    # calibrating tubes 3_3,3_2,3_1
    CalibratedComponent = ['MERLIN/door3/tube_3_%d' % (i) for i in [1, 2, 3]]
    doorpos = knownPositions[[0, 1, 2, 3, 5, 6, 7, 8]]
    doorfunc = funcForm[[0, 1, 2, 3, 5, 6, 7, 8]]
    calibrationTable, peakTable = tube.calibrate(CalibInstWS, CalibratedComponent, doorpos,
                                                 doorfunc,
                                                 outputPeak=True,
                                                 calibTable=calibrationTable,
                                                 margin=30)
    analisePeakTable(peakTable, 'door3_123_peaks')

    # calibrating others inside door3
    # 5_8, 5_7, 5_6, 5_5, 5_4, 5_3, 5_2, 5_1, 4_8, 4_7, 4_6, 4_5, 4_4, 4_3, 4_2, 4_1, 3_8, 3_7, 3_6, 3_5, 3_4
    part_3 = ['MERLIN/door3/tube_3_%d' % (i) for i in [4, 5, 6, 7, 8]]
    part_4 = ['MERLIN/door3/tube_4_%d' % (i) for i in range(1, 9)]
    part_5 = ['MERLIN/door3/tube_5_%d' % (i) for i in range(1, 9)]
    CalibratedComponent = part_3 + part_4 + part_5
    doorpos = knownPositions
    doorfunc = funcForm
    calibrationTable, peakTable = tube.calibrate(CalibInstWS, CalibratedComponent, doorpos,
                                                 doorfunc,
                                                 outputPeak=True,
                                                 calibTable=calibrationTable,
                                                 margin=30)
    analisePeakTable(peakTable, 'door3_peaks')

    # == Apply the Calibation ==
    mantid.ApplyCalibration(Workspace=CalibInstWS, CalibrationTable=calibrationTable)
    print("Applied calibration")