def normalize_transmission(self, im: Exposure, datared: Dict): transmission = im.header.transmission im /= im.header.transmission datared['history'].append('Divided by transmission: ' + str(im.header.transmission)) datared['statistics']['04_normalize_transmission'] = im.get_statistics() self._logger.debug('Done normalizing by transmission FSN {:d}'.format(im.header.fsn)) return im, datared
def subtractemptybeambackground(self, im: Exposure, datared: Dict): if im.header.title == self.config['datareduction']['backgroundname']: self._lastbackground = im self._logger.debug('Done bgsub FSN {:d}: this is background'.format(im.header.fsn)) datared['history'].append('This is an empty beam measurement.') raise DataReductionEnd() if ((im.header.distance - self._lastbackground.header.distance).abs() < self.config['datareduction']['distancetolerance']): im -= self._lastbackground datared['history'].append( 'Subtracted background FSN #{:d}'.format(self._lastbackground.header.fsn)) datared['emptybeamFSN'] = self._lastbackground.header.fsn else: raise ServiceError('Last seen background measurement does not match the exposure under reduction.') datared['statistics']['05_subtractbackground'] = im.get_statistics() self._logger.debug('Done bgsub FSN {:d}'.format(im.header.fsn)) return im, datared
def subtractdarkbackground(self, im: Exposure, datared: Dict): if im.header.title == self.config['datareduction']['darkbackgroundname']: self._lastdarkbackground = im.mean() self._logger.debug('Determined background level: {:g} cps per pixel'.format(self._lastdarkbackground)) self._logger.debug('Done darkbgsub FSN {:d}: this is dark background'.format(im.header.fsn)) datared['history'].append( 'This is a dark background measurement. Level: {:g} cps per pixel (overall {:g} cps)'.format( self._lastdarkbackground, self._lastdarkbackground * im.shape[0] * im.shape[1])) raise DataReductionEnd() # otherwise subtract the background. im -= self._lastdarkbackground datared['history'].append( 'Subtracted dark background level: {:g} cps per pixel (overall {:g} cps)'.format( self._lastdarkbackground, self._lastdarkbackground * im.shape[0] * im.shape[1])) datared['darkbackgroundlevel'] = self._lastdarkbackground datared['statistics']['03_subtractdarkbackground'] = im.get_statistics() self._logger.debug('Done darkbgsub FSN {:d}'.format(im.header.fsn)) return im, datared
def correctgeometry(self, im: Exposure, datared: Dict): tth = im.twotheta assert isinstance(tth, ErrorValue) datared['tthval_statistics'] = self.get_matrix_statistics(tth.val) datared['ttherr_statistics'] = self.get_matrix_statistics(tth.err) assert im.header.pixelsizex == im.header.pixelsizey corr_sa = solidangle(tth.val, tth.err, im.header.distance.val, im.header.distance.err, im.header.pixelsizex) im *= corr_sa datared['history'].append('Corrected for solid angle') datared['solidangle_matrixval_statistics'] = self.get_matrix_statistics(corr_sa.val) datared['solidangle_matrixerr_statistics'] = self.get_matrix_statistics(corr_sa.err) corr_ada = angledependentabsorption(tth.val, tth.err, im.header.transmission.val, im.header.transmission.err) im *= corr_ada datared['angledependentabsorption_matrixval_statistics'] = self.get_matrix_statistics( corr_ada.val) datared['angledependentabsorption_matrixerr_statistics'] = self.get_matrix_statistics( corr_ada.err) datared['history'].append('Corrected for angle-dependent absorption') try: vacuum = im.header.vacuum except KeyError: datared['history'].append( 'Skipped angle-dependent air absorption correction: no pressure value.') else: corr_adat = angledependentairtransmission(tth.val, tth.err, vacuum, im.header.distance.val, im.header.distance.err, self.config['datareduction']['mu_air'], self.config['datareduction']['mu_air.err']) im *= corr_adat datared[ 'angledependentairtransmission_matrixval_statistics'] = self.get_matrix_statistics(corr_adat.val) datared[ 'angledependentairtransmission_matrixerr_statistics'] = self.get_matrix_statistics(corr_adat.err) datared['history'].append( 'Corrected for angle-dependent air absorption. Pressure: {:f} mbar'.format( im.header.vacuum)) datared['statistics']['06_correctgeometry'] = im.get_statistics() self._logger.debug('Done correctgeometry FSN {:d}'.format(im.header.fsn)) return im, datared
def datareduction(self, intensity: np.ndarray, mask: np.ndarray, params: dict): im = Exposure(intensity, intensity ** 0.5, Header(params), mask) im.mask_negative() im.mask_nonfinite() im.mask_nan() self._logger.debug('Commencing data reduction of FSN #{:d} (sample {}).'.format(im.header.fsn, im.header.title)) datared = {'history': [], 'statistics': {'01_initial': im.get_statistics()}} try: self.normalize_flux(im, datared) self.subtractdarkbackground(im, datared) self.normalize_transmission(im, datared) self.subtractemptybeambackground(im, datared) self.correctgeometry(im, datared) self.dividebythickness(im, datared) self.absolutescaling(im, datared) except DataReductionEnd: pass self._logger.info('Data reduction history for FSN #{:d}:\n '.format(im.header.fsn) + '\n '.join(h for h in datared['history'])) im.header.param['datareduction'] = datared return im
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
def dividebythickness(self, im: Exposure, datared: Dict): im /= im.header.thickness datared['history'].append('Divided by thickness {:g} cm'.format(im.header.thickness)) datared['statistics']['07_dividebythickness'] = im.get_statistics() self._logger.debug('Done dividebythickness FSN {:d}'.format(im.header.fsn)) return im, datared
def normalize_flux(self, im: Exposure, datared: Dict): im /= im.header.exposuretime datared['history'].append('Divided by exposure time') datared['statistics']['02_normalize_flux'] = im.get_statistics() self._logger.debug('Done normalizing by flux FSN {:d}'.format(im.header.fsn)) return im, datared