Example #1
0
def _merge_two_curves(curve1: Curve, curve2: Curve, qmin, qmax, qsep, use_additive_constant=False):
    """Merge two scattering curves

    :param curve1: the first curve (longer distance)
    :type curve1: sastool.classes.curve.GeneralCurve
    :param curve2: the second curve (shorter distance)
    :type curve2: sastool.classes.curve.GeneralCurve
    :param qmin: lower bound of the interval for determining the scaling factor
    :type qmin: float
    :param qmax: upper bound of the interval for determining the scaling factor
    :type qmax: float
    :param qsep: separating (tailoring) point for the merge
    :type qsep: float
    :return: merged_curve, factor, background, stat
    :rtype tuple of a sastool.classes2.curve.Curve and a float
    """
    curve1=curve1.sanitize()
    curve2=curve2.sanitize()
    if len(curve1.trim(qmin, qmax)) > len(curve2.trim(qmin, qmax)):
        curve2_interp = curve2.trim(qmin, qmax)
        curve1_interp = curve1.interpolate(curve2_interp.q)
    else:
        curve1_interp = curve1.trim(qmin, qmax)
        curve2_interp = curve2.interpolate(curve1_interp.q)
    if use_additive_constant:
        bg_init = 0
    else:
        bg_init = FixedParameter(0)
    factor, bg, stat = nonlinear_odr(curve2_interp.Intensity, curve1_interp.Intensity,
                                     curve2_interp.Error, curve1_interp.Error,
                                     lambda x, factor, bg: x * factor + bg, [1.0, bg_init])
    return Curve.merge(curve1 - bg, curve2 * factor, qsep), factor, bg, stat
Example #2
0
def _scale_two_exposures(exp1, exp2, qmin, qmax, N=10, use_additive_constant=False):
    qrange = np.linspace(qmin, qmax, N)
    rad1 = exp1.radial_average(qrange=qrange, raw_result=False)
    rad2 = exp2.radial_average(qrange=qrange, raw_result=False)
    if use_additive_constant:
        bg_init = 0
    else:
        bg_init = FixedParameter(0)
    factor, bg, stat = nonlinear_odr(rad2.y, rad1.y, rad2.dy, rad1.dy, lambda x, factor, bg: x * factor + bg,
                                     [1, bg_init])
    return factor, bg
Example #3
0
    def odrfit(self, function, parameters_init, xname='x', yname='y', dyname='dy', dxname='dx', **kwargs):
        """Orthogonal distance regression to the dataset.

        Inputs:
        -------
            `function`: a callable, corresponding to the function to be fitted.
                Should have the following signature::

                    >>> function(x, par1, par2, par3, ...)

                where ``par1``, ``par2``, etc. are the values of the parameters
                to be fitted.

            `parameters_init`: a sequence (tuple or list) of the initial values
                for the parameters to be fitted. Their ordering should be the
                same as that of the arguments of `function`

            other keyword arguments are given to `nonlinear_odr()`
                without any modification.

        Outputs:
        --------
            `par1_fit`, `par2_fit`, etc.: the best fitting values of the parameters.
            `statdict`: a dictionary with various status data, such as `R2`, `DoF`,
                `Chi2_reduced`, `Covariance`, `Correlation_coeffs` etc. For a full
                list, see the help of `sastool.misc.easylsq.odr_fit()`
            `func_value`: the value of the function at the best fitting parameters,
                represented as an instance of the same class as this curve.

        Notes:
        ------
            The fitting itself is done via sastool.misc.easylsq.nonlinear_odr()

        """
        obj = self.sanitize(fieldname=yname).sanitize(fieldname=xname)
        if not hasattr(obj, dyname):
            dy = None
        else:
            dy = getattr(obj, dyname)
        if not hasattr(obj, dxname):
            dx = None
        else:
            dx = getattr(obj, dxname)
        ret = nonlinear_odr(getattr(obj, xname), getattr(
            obj, yname), dx, dy, function, parameters_init, **kwargs)
        funcvalue = type(self)(getattr(obj, xname), ret[-1]['func_value'])
        return ret + (funcvalue,)
Example #4
0
    def do_getdistance(self):
        model = self.builder.get_object('pairstore')
        uncalval = np.array([row[2] for row in model])
        uncalerr = np.array([row[3] for row in model])
        calval = np.array([row[4] for row in model])
        calerr = np.array([row[5] for row in model])
        logger.debug('Uncalval: ' + str(uncalval))
        logger.debug('Uncalerr: ' + str(uncalerr))
        logger.debug('Calval: ' + str(calval))
        logger.debug('Calerr: ' + str(calerr))
        assert isinstance(self._exposure, Exposure)
        assert self._exposure.header.pixelsizex == self._exposure.header.pixelsizey
        if len(uncalval) > 1:
            def fitfunc(pix_: np.ndarray, dist: float):
                return qfrompix(pix_, pixelsize=self._exposure.header.pixelsizex,
                                beampos=0, alpha=np.pi * 0.5,
                                wavelength=self._exposure.header.wavelength,
                                dist=dist)

            self._dist, stat = nonlinear_odr(uncalval, calval, uncalerr, calerr, fitfunc, [100])
            x = np.linspace(uncalval.min(), uncalval.max(), len(uncalval) * 100)
            self.figpairsaxes.plot(x, fitfunc(x, self._dist.val), 'r-')
        elif len(uncalval) == 1:
            q = ErrorValue(float(calval[0]), float(calerr[0]))
            pix = ErrorValue(float(uncalval[0]), float(uncalerr[0]))
            wl = ErrorValue(
                self._exposure.header.wavelength,
                0)  # wavelength error is not considered here:
            # it has already been considered in the pixel value (peak position)
            pixsize = self._exposure.header.pixelsizex
            self._dist = (pix * pixsize) / (2.0 * (wl * q / 4.0 / np.pi).arcsin()).tan()
        else:
            self._dist = None
            self.builder.get_object('distance_label').set_text('--')
            self.builder.get_object('savedistance_button').set_sensitive(True)
            return
        self.builder.get_object('distance_label').set_text(self._dist.tostring(plusminus=' \u00b1 ') + ' mm')
        self.builder.get_object('savedistance_button').set_sensitive(True)
        self.figpairscanvas.draw()
Example #5
0
 def absolutescaling(self, im: Exposure, datared: Dict):
     if im.header.title == self.config['datareduction']['absintrefname']:
         self._logger.debug('History: {}'.format('\n'.join([h for h in datared['history']])))
         dataset = np.loadtxt(self.config['datareduction']['absintrefdata'])
         self._logger.debug('Q-range of absint dataset: {:g} to {:g}, {:d} points.'.format(
             dataset[:, 0].min(), dataset[:, 0].max(), len(dataset[:, 0])))
         testradavg = im.radial_average()
         self._logger.debug('Auto-Q-range of the measured dataset: {:g} to {:g}, {:d} points.'.format(
             testradavg.q.min(), testradavg.q.max(), len(testradavg)))
         # noinspection PyPep8Naming,PyPep8Naming
         q, dq, I, dI, area = im.radial_average(qrange=dataset[:, 0], raw_result=True)
         dataset = dataset[area > 0, :]
         # noinspection PyPep8Naming
         I = I[area > 0]
         # noinspection PyPep8Naming
         dI = dI[area > 0]
         q = q[area > 0]
         self._logger.debug('Common q-range: {:g} to {:g}, {:d} points.'.format(q.min(), q.max(), len(q)))
         scalingfactor, stat = nonlinear_odr(I, dataset[:, 1], dI, dataset[:, 2], lambda x, a: a * x, [1])
         datared['absintscaling'] = {'q': q, 'area': area, 'Imeas': I, 'dImeas': dI,
                                     'Iref': dataset[:, 1], 'dIref': dataset[:, 2],
                                     'factor.val': scalingfactor.val,
                                     'factor.err': scalingfactor.err, 'stat': stat}
         self._logger.debug('Scaling factor: ' + str(scalingfactor))
         self._logger.debug('Chi2: {:f}'.format(stat['Chi2_reduced']))
         self._lastabsintref = im
         self._absintscalingfactor = scalingfactor
         self._absintstat = stat
         self._absintqrange = q
         datared['history'].append(
             'This is an absolute intensity reference measurement. '
             'Determined absolute intensity scaling factor: {}. Reduced Chi2: {:f}. DoF: {:d}. '
             'This corresponds to beam flux {} photons*eta/sec'.format(
                 self._absintscalingfactor, self._absintstat['Chi2_reduced'], self._absintstat['DoF'],
                 1 / self._absintscalingfactor))
     if ((im.header.distance - self._lastabsintref.header.distance).abs() <
             self.config['datareduction']['distancetolerance']):
         im *= self._absintscalingfactor
         datared['statistics']['08_absolutescaling'] = im.get_statistics()
         datared['history'].append(
             'Using absolute intensity factor {} from measurement FSN #{:d} '
             'for absolute intensity calibration.'.format(
                 self._absintscalingfactor, self._lastabsintref.header.fsn))
         datared['history'].append('Absint factor was determined with Chi2 {:f} (DoF {:d})'.format(
             self._absintstat['Chi2_reduced'], self._absintstat['DoF']))
         datared['history'].append('Estimated flux: {} photons*eta/sec'.format(
             self._absintscalingfactor.__reciprocal__()))
         datared['absintrefFSN'] = self._lastabsintref.header.fsn
         datared['flux'] = self._absintscalingfactor.__reciprocal__().val
         datared['flux.err'] = self._absintscalingfactor.__reciprocal__().err
         datared['absintchi2'] = self._absintstat['Chi2_reduced']
         datared['absintdof'] = self._absintstat['DoF']
         datared['absintfactor'] = self._absintscalingfactor.val
         datared['absintfactor.err'] = self._absintscalingfactor.err
         datared['absintqmin'] = self._absintqrange.min()
         datared['absintqmax'] = self._absintqrange.max()
     else:
         raise ServiceError(
             'S-D distance of the last seen absolute intensity reference measurement '
             'does not match the exposure under reduction.')
     self._logger.debug('Done absint FSN ' + str(im.header.fsn))
     return im, datared