Exemple #1
0
def test_listof():
    assert listof(int)([0., 1, '2']) == [0, 1, 2]
    assert listof(int)() == []
    # should also accept tuples
    assert listof(int)((1, 2, 3)) == [1, 2, 3]
    assert raises(ValueError, listof(int), 10)
    # assert that the list is read-only
    assert raises(TypeError, listof(int)([0, 1, 2]).__setitem__, 0, 1)
Exemple #2
0
class CacheKeyFilter(DeviceMixinBase):
    """Mixin for filtering cache keys that might be forwarded.

    This is used on the source side (Collector device), as well as on
    individual sinks (ForwarderBase devices) for maximum flexibility.
    """

    parameters = {
        'keyfilters':
        Param(
            'Filter keys to send (regexps); if empty, all '
            'keys are accepted',
            type=listof(str)),
    }

    def _initFilters(self):
        self._prefixfilters = ()
        self._regexfilters = []
        for regex in self.keyfilters:
            # special case: prefixes
            if PREFIX_RE.match(regex):
                self._prefixfilters += (regex[:-2], )
            else:
                self._regexfilters.append(re.compile(regex))

    def _checkKey(self, key):
        if not self._prefixfilters and not self._regexfilters:
            return True
        if key.startswith(self._prefixfilters):
            return True
        for keyfilter in self._regexfilters:
            if keyfilter.match(key):
                return True
        return False
Exemple #3
0
class DetectorDistance(Readable):
    """Calculate detector distance based on the detector tubes position"""

    attached_devices = {
        'detectubes': Attach('Pilatus detector tubes', Readable, multiple=4)
    }

    parameters = {
        'offset':
        Param('Minimum distance between Pilatus and sample',
              type=int,
              settable=True),
        'tubelength':
        Param('List of tube length',
              type=listof(int),
              settable=False,
              default=[450, 450, 900, 900]),
    }

    hardware_access = False

    def doInit(self, mode):
        self.log.debug('Detector distance init')
        self.read()

    def doRead(self, maxage=0):
        distance = 0
        for tube, l in zip(self._attached_detectubes, self.tubelength):
            # tubes can only be set in correct sequence
            if tube.read(maxage) != 'up':
                break
            distance += l
        return self.offset + distance
Exemple #4
0
class HexapodSpecial(PyTangoDevice, Device):
    """Ohe Hexapod Device for Workspace Configuration."""

    parameters = {
        "workspaces": Param("Hexapod workspaces list containing tuples of "
                            "(id, [xn, xp, yn, yp, zn, zp, rzn, rzp, ryn, ryp, "
                            "rxn, rxp, tx, ty, tz, rz, ry, rx])",
                            type=listof(tupleof(int, listof(float))),
                            mandatory=True, settable=False)
    }

    def doInit(self, mode):
        if any(idx < 10 or idx > 19 for idx, _ in self.workspaces):
            raise ConfigurationError("Workspace ids muste be in 10..19 "
                                     "(Jülich workspace range)")
        if mode != SIMULATION:
            workspaces = self._dev.workspaces  # Tango get workspaces
            for wsid, ws in self.workspaces:
                workspaces[wsid] = ws
            self._dev.workspaces = workspaces  # Tango set workspaces
Exemple #5
0
class MultiCounter(BaseImageChannel):
    """Channel for QMesyDAQ that allows to access selected channels in a
    multi-channel setup.
    """

    parameters = {
        'channels': Param('Tuple of active channels (1 based)', settable=True,
                          type=listof(int)),
    }

    def doRead(self, maxage=0):
        if self._mode == SIMULATION:
            res = [0] * (max(self.channels) + 3)
        else:
            # read data via Tango and transform it
            val = self._dev.value
            res = val.tolist() if isinstance(val, numpy.ndarray) else val
        expected = 3 + max(self.channels or [0])
        # first 3 values are sizes of dimensions
        if len(res) >= expected:
            data = res[3:]
            # ch is 1 based, data is 0 based
            total = sum([data[ch - 1] for ch in self.channels])
        else:
            self.log.warning('not enough data returned, check config! '
                             '(got %d elements, expected >=%d)',
                             len(res), expected)
            data = None
            total = 0
        resultlist = [total]
        if data is not None:
            for ch in self.channels:
                # ch is 1 based, data is 0 based
                resultlist.append(data[ch - 1])
        return resultlist

    def valueInfo(self):
        resultlist = [Value('ch.sum', unit='cts', errors='sqrt',
                            type='counter', fmtstr='%d')]
        for ch in self.channels:
            resultlist.append(Value('ch%d' % ch, unit='cts', errors='sqrt',
                                    type='counter', fmtstr='%d'))
        return tuple(resultlist)

    def doReadIsmaster(self):
        return False

    def doReadFmtstr(self):
        return ', '.join(['sum %d'] + ['ch%d %%d' % ch for ch in self.channels])
Exemple #6
0
class FileSink(DataSink):
    """Base class for sinks that save data into files."""

    parameters = {
        'subdir':           Param('Filetype specific subdirectory name',
                                  type=subdir, mandatory=False, default=''),
        'filenametemplate': Param('List of templates for data file names '
                                  '(will be hardlinked), can contain '
                                  'subdirectories',
                                  ext_desc=TEMPLATE_DESC, type=listof(str),
                                  default=['%(pointcounter)08d.dat'],
                                  settable=False, prefercache=False),
        'filemode':         Param('File access rights after closing the file, '
                                  "if set to 'none' (default) the OS defaults "
                                  'will be used',
                                  type=none_or(intrange(0o000, 0o777),)),
    }
Exemple #7
0
class FileSink(DataSink):
    """Base class for sinks that save data into files."""

    parameters = {
        'subdir':
        Param('Filetype specific subdirectory name',
              type=subdir,
              mandatory=False,
              default=''),
        'filenametemplate':
        Param(
            'List of templates for data file names '
            '(will be hardlinked), can contain '
            'subdirectories',
            ext_desc=TEMPLATE_DESC,
            type=listof(str),
            default=['%(pointcounter)08d.dat'],
            settable=False,
            prefercache=False),
    }
Exemple #8
0
 def _array(members, minlen=0, **kwds):
     # ignore maxlen and minlen > 1
     members = get_validator(**members)
     return nonemptylistof(members) if minlen else listof(members)
Exemple #9
0
class DataSink(Device):
    """The base class for data sinks.

    Each sink represents one way of processing incoming data.

    This is a device to be instantiated once per setup so that it can be
    configured easily through NICOS setups.  Actual processing is done by a
    `DataSinkHandler` class, of which one or more instances are created for
    each dataset that is processed with this sink.

    Usually, sinks are specific to a certain type of dataset (e.g. points or
    scans) and therefore override the `settypes` parameter with a default value
    that reflects this.

    .. attribute:: handlerclass

       This class attribute must be set by subclasses.  It selects the subclass
       of `.DataSinkHandler` that is to be used for handling datasets with this
       sink.

    .. attribute:: activeInSimulation

       This is a class attribute that selects whether this sink can be used in
       simulation mode.  This should only be true for sinks that write no data,
       such as a "write scan data to the console" sink.

    .. automethod:: isActive
    """

    parameters = {
        'detectors': Param('List of detector names to activate this sink '
                           '(default is always activated)', type=listof(str)),
        'settypes':  Param('List of dataset types to activate this sink '
                           '(default is for all settypes the sink supports)',
                           type=setof(*SETTYPES)),
    }

    parameter_overrides = {
        'lowlevel': Override(default=True, mandatory=False),
    }

    # Set to true in subclasses that are safe for simulation.
    activeInSimulation = False

    # Set this to the corresponding Handler class.
    handlerclass = None

    def isActive(self, dataset):
        """Should return True if the sink can and should process this dataset.

        The default implementation, which should always be called in overrides,
        checks for simulation mode and for a match with the settypes and the
        detectors selected by the respective parameters.

        Derived classes can add additional checks, such as the dataset
        producing an array that can be written to an image file.
        """
        if session.mode == SIMULATION and not self.activeInSimulation:
            return False
        if self.settypes and dataset.settype not in self.settypes:
            return False
        if self.detectors and \
           not ({d.name for d in dataset.detectors} & set(self.detectors)):
            return False
        return True

    def createHandlers(self, dataset):
        """Start processing the given dataset (a BaseDataset).

        Creates the corresponding DataSinkHandler instances to use for this
        dataset determined via `handlerclass` and returns them.
        """
        if self.handlerclass is None:
            raise NotImplementedError('Must set an "handlerclass" attribute '
                                      'on %s' % self.__class__)
        # pylint: disable=not-callable
        if dataset.settype == POINT:
            dets = {d.name for d in dataset.detectors}
            if self.detectors:
                dets &= set(self.detectors)
            return [self.handlerclass(self, dataset, session.getDevice(det))
                    for det in dets]
        else:
            return [self.handlerclass(self, dataset, None)]
Exemple #10
0
class Flux(VectorInput):
    """Device which stores the flux averages over the relevant detectors.
    """

    parameters = {
        'fluxvalues':
        Param('Raw flux values', internal=True, type=listof(listof(int)))
    }

    def init(self):
        VectorInput.init(self)
        self._fluxvalues = [[], [], []]

    def doPoll(self, i, maxage):
        val = self.doRead()
        self._pollParam('fluxvalues')

        return self.status(), val

    def doReadFluxvalues(self):
        if not hasattr(self, '_fluxvalues'):
            self.doRead()
        return self._fluxvalues

    def doRead(self, maxage=0):
        flux = self._dev.GetFlux()

        if len(flux) != 16 * 6:
            self.log.warning('SIS returned %d flux values, expected %d',
                             len(flux), 16 * 6)
            return [0, 0, 0]

        # pylint: disable=unbalanced-tuple-unpacking
        cElast, cInelast, cDir, tElast, tInelast, tDir = self.split(flux, 16)
        rDets = self._dev.GetRegularDetectors()

        self._fluxvalues = [cElast, cInelast, cDir]

        elast = [
            sum([x for i, x in enumerate(cElast) if i in rDets]),
            sum([x for i, x in enumerate(tElast) if i in rDets])
        ]
        inelast = [
            sum([x for i, x in enumerate(cInelast) if i in rDets]),
            sum([x for i, x in enumerate(tInelast) if i in rDets])
        ]
        direct = [
            sum([x for i, x in enumerate(cDir) if i in rDets]),
            sum([x for i, x in enumerate(tDir) if i in rDets])
        ]

        if not elast[1]:
            elastic = 0
        else:
            elastic = int(elast[0] / 2e-5 / elast[1])

        if not inelast[1]:
            inelastic = 0
        else:
            inelastic = int(inelast[0] / 2e-5 / inelast[1])
        if not direct[1]:
            direct = 0
        else:
            direct = int(direct[0] / 2e-5 / direct[1])

        return [elastic, inelastic, direct]

    def split(self, inp, chunksize):
        output = []
        index = 0
        listsize = len(inp)

        while index < listsize:
            output.append([int(x) for x in inp[index:index + chunksize]])
            index += chunksize

        return output
Exemple #11
0
class CascadeDetector(VirtualImage):

    _perfoil = 16

    parameters = {
        'mode':
        Param('Data acquisition mode (tof or image)',
              type=oneof('tof', 'image'),
              settable=True,
              default='image',
              category='presets'),
        'roi':
        Param('Region of interest, given as (x1, y1, x2, y2)',
              type=tupleof(int, int, int, int),
              default=(-1, -1, -1, -1),
              settable=True),
        'tofchannels':
        Param('Total number of TOF channels to use',
              type=intrange(1, 1024),
              default=128,
              settable=True,
              category='presets'),
        'foilsorder':
        Param('Usable foils, ordered by number.',
              type=listof(intrange(0, 31)),
              settable=False,
              default=[0, 1, 2, 3, 4, 5, 6, 7],
              category='instrument'),
        'fitfoil':
        Param('Foil for contrast fitting (number BEFORE '
              'resorting)',
              type=int,
              default=0,
              settable=True),
    }

    def doInit(self, mode):
        self._buf = self._generate(0).astype('<u4')

    def doUpdateMode(self, value):
        self._dataprefix = (value == 'image') and 'IMAG' or 'DATA'
        self._datashape = (value == 'image') and self.sizes or \
            (self._perfoil * len(self.foilsorder), ) + self.sizes
        # (self.tofchannels,)
        self._tres = (value == 'image') and 1 or self.tofchannels

    def doStart(self):
        self.readresult = [0, 0]
        VirtualImage.doStart(self)

    def valueInfo(self):
        if self.mode == 'tof':
            return (Value(self.name + '.roi',
                          unit='cts',
                          type='counter',
                          errors='sqrt',
                          fmtstr='%d'),
                    Value(self.name + '.total',
                          unit='cts',
                          type='counter',
                          errors='sqrt',
                          fmtstr='%d'),
                    Value('fit.contrast',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.3f'),
                    Value('fit.contrastErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.3f'),
                    Value('fit.avg',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.1f'),
                    Value('fit.avgErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.1f'),
                    Value('roi.contrast',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.3f'),
                    Value('roi.contrastErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.3f'),
                    Value('roi.avg',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.1f'),
                    Value('roi.avgErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.1f'))
        return (Value(self.name + '.roi',
                      unit='cts',
                      type='counter',
                      errors='sqrt',
                      fmtstr='%d'),
                Value(self.name + '.total',
                      unit='cts',
                      type='counter',
                      errors='sqrt',
                      fmtstr='%d'))

    @property
    def arraydesc(self):
        if self.mode == 'image':
            return ArrayDesc('data', self._datashape, '<u4', ['X', 'Y'])
        return ArrayDesc('data', self._datashape, '<u4', ['T', 'X', 'Y'])

    def doReadArray(self, quality):
        # get current data array from detector, reshape properly
        data = VirtualImage.doReadArray(self, quality)
        # determine total and roi counts
        total = data.sum()
        if self.roi != (-1, -1, -1, -1):
            x1, y1, x2, y2 = self.roi
            roi = data[..., y1:y2, x1:x2].sum()
        else:
            x1, y1, x2, y2 = 0, 0, data.shape[-1], data.shape[-2]
            roi = total

        if self.mode == 'image':
            self.readresult = [roi, total]
            return data

        data = np.array([data] * self._datashape[0])

        # demux timing into foil + timing
        nperfoil = self._datashape[0] // len(self.foilsorder)
        shaped = data.reshape((len(self.foilsorder), nperfoil) +
                              self._datashape[1:])
        # nperfoil = self.tofchannels // self.foils
        # shaped = data.reshape((self.foils, nperfoil) + self._datashape[1:])

        x = np.arange(nperfoil)

        ty = shaped[self.fitfoil].sum((1, 2))
        ry = shaped[self.fitfoil, :, y1:y2, x1:x2].sum((1, 2))

        self.log.debug('fitting %r and %r' % (ty, ry))

        self.readresult = [
            roi,
            total,
        ]

        # also fit per foil data and pack everything together to be send
        # via cache for display
        payload = []
        for foil in self.foilsorder:
            foil_tot = shaped[foil].sum((1, 2))
            foil_roi = shaped[foil, :, y1:y2, x1:x2].sum((1, 2))
            tpopt, tperr, _ = fit_a_sin_fixed_freq(x, foil_tot)
            rpopt, rperr, _ = fit_a_sin_fixed_freq(x, foil_roi)
            payload.append([
                tpopt, tperr,
                foil_tot.tolist(), rpopt, rperr,
                foil_roi.tolist()
            ])

        self._cache.put(self.name, '_foildata', payload, flag=FLAG_NO_STORE)
        return data
Exemple #12
0
class ImageChannel(QMesyDAQImage, BaseImageChannel):

    parameters = {
        'readout':
        Param('Readout mode of the Detector',
              settable=True,
              type=oneof('raw', 'mapped', 'amplitude'),
              default='mapped',
              mandatory=False,
              chatty=True),
        'flipaxes':
        Param('Flip data along these axes after reading from det',
              type=listof(int),
              default=[],
              unit=''),
        'transpose':
        Param('Whether to transpose the image', type=bool, default=False),
    }

    # Use the configuration from QMesyDAQ
    parameter_overrides = {
        'listmode': Override(volatile=True),
        'histogram': Override(volatile=True),
    }

    def doWriteListmode(self, value):
        self._dev.SetProperties(['writelistmode', ('%s' % value).lower()])
        return self.doReadListmode()

    def doReadListmode(self):
        return {
            'false': False,
            'true': True
        }[self._getProperty('writelistmode')]

    def doWriteHistogram(self, value):
        self._dev.SetProperties(['writehistogram', ('%s' % value).lower()])
        return self.doReadHistogram()

    def doReadHistogram(self):
        return {
            'false': False,
            'true': True
        }[self._getProperty('writehistogram')]

    def doWriteReadout(self, value):
        self._dev.SetProperties(['histogram', value])
        return self._getProperty('histogram')

    def doWriteListmodefile(self, value):
        self._dev.SetProperties(['lastlistfile', value])
        return self._getProperty('lastlistfile')

#   def doReadListmodefile(self):
#       return self._getProperty('lastlistfile')

    def doWriteHistogramfile(self, value):
        self._dev.SetProperties(['lasthistfile', value])
        return self._getProperty('lasthistfile')


#   def doReadHistogramfile(self):
#       return self._getProperty('lasthistfile')

    def doReadConfigfile(self):
        return self._getProperty('configfile')

    def doReadCalibrationfile(self):
        return self._getProperty('calibrationfile')

    def doReadArray(self, quality):
        narray = BaseImageChannel.doReadArray(self, quality)
        if self.transpose:
            narray = np.transpose(narray)
        for axis in self.flipaxes:
            narray = np.flip(narray, axis)
        return narray

    def doFinish(self):
        self.doStatus(0)
        return BaseImageChannel.doFinish(self)

    def doStop(self):
        self.doStatus(0)
        return BaseImageChannel.doStop(self)
Exemple #13
0
class SISChannel(BaseImageChannel):
    """
    Spheres SIS ImageChannel
    """

    parameters = {
        'analyzers':
        Param('Analyzer Crystal',
              type=oneof('Si111', 'Si311'),
              default='Si111'),
        'monochromator':
        Param('Monochromator Crystal',
              type=oneof('Si111', 'Si311'),
              default='Si111'),
        'incremental':
        Param('Incremental Mode', type=bool, settable=True),
        'inelasticinterval':
        Param('Interval for the inelastic scan',
              type=int,
              settable=True,
              default=1200),
        'regulardets':
        Param('relevant detectors for the monitor',
              type=listof(int),
              volatile=True),
        'elasticparams':
        Param('Interval and amount for one elastic scan '
              'datafile',
              type=listof(int),
              settable=True,
              volatile=True),
        'detamount':
        Param('Amount of detectors for the reshaping '
              'of the read data.',
              type=int,
              default=16),
        'backgroundmode':
        Param('Mode of the background chopper', type=float, volatile=True),
        'backgroundoffset':
        Param(
            'Count offset in relation to the first PST '
            'zero after each background zero.',
            type=float,
            settable=True,
            volatile=True),
        'chopperopen':
        Param(
            'Chopper is open in this range. If the '
            'first value is bigger then the second the '
            'area is wrapped around 360 deg',
            type=listof(float),
            settable=True,
            volatile=True),
        'chopperreflecting':
        Param(
            'Chopper is reflecting in this range. If '
            'the first value is bigger then the second '
            'the area is wrapped around 360 deg',
            type=listof(float),
            settable=True,
            volatile=True),
        'chopstatisticlen':
        Param('Revolutions for Background chopper '
              'statistics',
              type=int,
              settable=True,
              volatile=True),
        'backzerorange':
        Param(
            'Range of the pst zero passes for the last'
            'chopstatisticlen pst revolutions',
            type=listof(float),
            volatile=True),
        'measuremode':
        Param('Mode in which the detector is measuring',
              type=oneof(ELASTIC, INELASTIC, SIMULATION),
              volatile=True),
    }

    def __init__(self, name, **config):
        BaseImageChannel.__init__(self, name, **config)

        self._block = []
        self._reason = ''

        self.clearAccumulated()

    def clearAccumulated(self):
        self._last_edata = None
        self._last_cdata = None

    def doReadElasticparams(self):
        return [self._dev.tscan_interval, self._dev.tscan_amount]

    def doWriteElasticparams(self, val):
        self._dev.tscan_interval = val[0]
        self._dev.tscan_amount = val[1]

    def doReadBackgroundmode(self):
        return self._dev.backgr_mode

    def doReadBackgroundoffset(self):
        return self._dev.backgr_offset

    def doWriteBackgroundoffset(self, value):
        self._dev.backgr_offset = value

    def doReadChopperopen(self):
        return [self._dev.chop_open_f, self._dev.chop_open_t]

    def doWriteChopperopen(self, value):
        if len(value) != 2:
            raise UsageError('Chopperopen needs exactly 2 values: '
                             '"from" and "to"')

        self._dev.chop_open_f = value[0]
        self._dev.chop_open_t = value[1]

    def doReadChopperreflecting(self):
        return [self._dev.chop_refl_f, self._dev.chop_refl_t]

    def doWriteChopperreflecting(self, value):
        if len(value) != 2:
            raise UsageError('Chopperreflecting needs exactly 2 values: '
                             '"from" and "to"')

        self._dev.chop_refl_f = value[0]
        self._dev.chop_refl_t = value[1]

    def doReadChopstatisticlen(self):
        return self._dev.chop_statisticlen

    def doWriteChopstatisticlen(self, value):
        self._dev.chop_statisticlen = value

    def doReadBackzerorange(self):
        return [self._dev.backgr_zero_min, self._dev.backgr_zero_max]

    def doReadMeasuremode(self):
        if session.sessiontype == SIMULATION:
            return SIMULATION
        return self._dev.GetMeasureMode()

    def setTscanAmount(self, amount):
        if session.sessiontype == SIMULATION:
            return
        if self.status()[0] == status.OK:
            self._dev.setProperties(['tscan_amount', str(amount)])

    def doPrepare(self):
        self._checkShutter()
        self._dev.Prepare()
        self._hw_wait()

    def doReadArray(self, quality):
        mode = self.measuremode

        if mode == SIMULATION:
            return []

        if quality == LIVE:
            return [self._readLiveData()]
        else:
            self._reason = quality

        if mode == ELASTIC:
            return self._readElastic()
        elif mode == INELASTIC:
            return self._readInelastic()

    def doReadRegulardets(self):
        if session.sessiontype == SIMULATION:
            return []
        return list(self._dev.GetRegularDetectors())

    def valueInfo(self):
        return Value(name=TOTAL, type="counter", fmtstr="%d", unit="cts"),

    def _readLiveData(self):
        if self.measuremode == INELASTIC:
            if self._last_edata is not None:
                if self.incremental:
                    live = self._readData(ENERGY)
                    self._mergeCounts(live, self._last_edata)
                else:
                    live = self._last_edata
            else:
                live = self._readData(ENERGY)
        else:
            live = []

        return live

    def _readElastic(self):
        live = self._readLiveData()
        params = self._dev.GetParams() + \
            ['type', 'elastic'] + \
            self.getAdditionalParams()
        data = self._readData(TIME)

        return live, params, data

    def _readInelastic(self):
        live = self._readLiveData()
        params = self._dev.GetParams() + \
            ['type', 'inelastic'] + \
            self.getAdditionalParams()
        edata = self._readData(ENERGY)
        cdata = self._readData(CHOPPER)

        if self.incremental:
            if self._reason == FINAL:
                self._processCounts(edata, cdata)
                edata = self._last_edata
                cdata = self._last_cdata
            else:
                self._mergeCounts(edata, self._last_edata)
                self._mergeCounts(cdata, self._last_cdata)

        return live, params, edata, cdata

    def _readData(self, target):
        '''Read the requested data from the hardware and generate the according
        histogram tuples to make further processing easier.
        '''

        if target == ENERGY:
            targettuple = EnergyHisto
        elif target == TIME:
            targettuple = TimeHisto
        elif target == CHOPPER:
            targettuple = ChopperHisto
        else:
            raise NicosError('Can not read "%s"-data. Target not supported' %
                             target)

        xvals = self._dev.GetTickData(target)
        xvalsize = len(xvals)
        rawdata = self._dev.GetData(target)
        rawdatasize = len(rawdata)

        data = []
        amount = rawdatasize // (xvalsize * self.detamount * 2)
        if target in [ENERGY, TIME]:
            self.readresult = [sum(rawdata[:rawdatasize // 2])]
        counts = rawdata[:rawdatasize // 2].reshape(amount, xvalsize,
                                                    self.detamount)
        times = rawdata[rawdatasize // 2:].reshape(amount, xvalsize,
                                                   self.detamount)

        # to filter out the superfluous zero arrays in the elastic scan
        # we only iterate over the amount of unique xvals. The arrays not yet
        # 'triggered' all have the corresponding xval of 0, same as the first
        # array. Thus every array corresponding to the 2nd+ 0 xval will not be
        # added.
        for i in range(len(set(xvals))):
            # first insert the xvalue
            block = [float(xvals[i])]
            # then add the i-th count array from each of the count blocks
            for h in range(amount):
                block.append(counts[h, i, :])
            # then add the corresponding timesteps the same way
            for h in range(amount):
                block.append(times[h, i, :])
            data.append(targettuple._make(block))

        return data

    def getAdditionalParams(self):
        return [
            'monochromator', self.monochromator, 'analyzers', self.analyzers,
            'reason', self._reason, 'incremental', self.incremental,
            'dets4mon', [self.regulardets[0], self.regulardets[-1]]
        ]

    def _mergeCounts(self, total, increment):
        """
        Increments the first array, entry by entry with the corresponding
        entries from the second array.
        """
        if not increment:
            return

        for i, entry in enumerate(total):
            for j, arr in enumerate(entry):
                if j == 0:
                    continue
                arr.__iadd__(increment[i][j])

    def _processCounts(self, edata, cdata):
        """
        Set data arrays to the right values for further processing.
        """

        if self._last_edata is None:
            self._last_edata = edata
            self._last_cdata = cdata
            return

        try:
            self._mergeCounts(self._last_edata, edata)
            self._mergeCounts(self._last_cdata, cdata)
        except IndexError:
            self.resetIncremental(
                'Error while merging arrays. '
                'Lenght of accumulated(%d, %d) differs '
                'from provided(%d, %d) array. '
                'Switching to non incremental mode.' %
                (len(self._last_edata), len(
                    self._last_cdata), len(edata), len(cdata)))
            return

    def resetIncremental(self, message):
        self.log.warning(message + ' Switching to non incremental mode.')
        self.incremental = False
        self._last_edata = None
        self._last_cdata = None

    def setDummyDoppler(self, speed):
        self._dev.dummy_doppvel = speed