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 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 on_image(self, exposureanalyzer, prefix, fsn, matrix, params, mask): im = Exposure(matrix, header=Header(params), mask=mask) try: sample = im.header.title except KeyError: sample = "unknown sample" legend = "FSN #{:d}, {} at {:.2f} mm".format(im.header.fsn, sample, float(im.header.distance)) if self.builder.get_object("plotimage_check").get_active(): if self.builder.get_object("reuseimage_check").get_active(): imgwin = PlotImageWindow.get_latest_window() else: imgwin = PlotImageWindow() imgwin.set_image(im.intensity) imgwin.set_mask(im.mask) imgwin.set_distance(im.header.distance) imgwin.set_beampos(im.header.beamcenterx, im.header.beamcentery) assert im.header.pixelsizex == im.header.pixelsizey imgwin.set_pixelsize(im.header.pixelsizex) imgwin.set_wavelength(im.header.wavelength) imgwin.set_title(legend) if self.builder.get_object("plotradial_check").get_active(): if self.builder.get_object("reuseradial_check").get_active(): curvewin = PlotCurveWindow.get_latest_window() else: curvewin = PlotCurveWindow() curve = im.radial_average() assert im.header.pixelsizex == im.header.pixelsizey curvewin.addcurve( curve.q, curve.Intensity, curve.qError, curve.Error, legend, "q", im.header.pixelsizex, im.header.distance, im.header.wavelength, ) self._images_done += 1 if self._images_done >= self._nimages: self.instrument.services["exposureanalyzer"].disconnect(self._expanalyzerconnection) self._expanalyzerconnection = None
def load_exposure(self, prefix: str, fsn: int) -> Exposure: header = self.load_header(prefix, fsn) cbfbasename = self.exposurefileformat(prefix, fsn) + '.cbf' imgpath = self.instrument.config['path']['directories']['images'] for path in [os.path.join(imgpath, prefix), imgpath]: try: return Exposure.new_from_file( os.path.join(path, cbfbasename), header, self.get_mask(header.maskname)) except FileNotFoundError: continue raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), cbfbasename)
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 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 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 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