def SaveSLS(self, IofR, NormF, AllExpData=None): """ Saves output of SLS analysis Parameters ---------- IofR : 2D array of shape (NumTimes(), NumROIs()) NormF : 1D array with ROI normalization factors AllExpData : None or [I, exptime], data with all exposure times """ roi_norms = np.zeros((IofR.shape[-1], 1)) roi_norms[:len(NormF), 0] = NormF np.savetxt(os.path.join(self.outFolder, 'ROIcoords.dat'), np.append(self.ROIcoords, roi_norms, axis=1), header='r[px]' + TXT_DELIMITER + 'phi[rad]' + TXT_DELIMITER + 'dr[px]' + TXT_DELIMITER + 'dphi[rad]' + TXT_DELIMITER + 'norm', **self.savetxt_kwargs) MI.WriteBinary(os.path.join(self.outFolder, 'ROI_mask.raw'), self.ROIs, 'i') str_hdr_Ir = 'r[px]' + TXT_DELIMITER + 'phi[rad]' + ''.join([ TXT_DELIMITER + 't{0:.2f}'.format(self.imgTimes[i]) for i in range(0, self.ImageNumber(), self.NumExpTimes()) ]) np.savetxt(os.path.join(self.outFolder, SLS_FNAME), np.append(self.ROIcoords[:IofR.shape[1], :2], IofR.T, axis=1), header=str_hdr_Ir, **self.savetxt_kwargs) if AllExpData is not None: ROIavgs_allExp, BestExptime_Idx = AllExpData np.savetxt(os.path.join(self.outFolder, 'exptimes.dat'), np.append(self.ROIcoords[:, :2], BestExptime_Idx.T, axis=1), header=str_hdr_Ir, **self.savetxt_kwargs) str_hdr_raw = 'r[px]' + TXT_DELIMITER + 'phi[rad]' + ''.join([ TXT_DELIMITER + 't{0:.2f}_e{1:.3f}'.format( self.imgTimes[i], self.expTimes[i % len(self.expTimes)]) for i in range(len(self.imgTimes)) ]) np.savetxt(os.path.join(self.outFolder, SLS_RAW_FNAME), np.append(self.ROIcoords[:, :2], ROIavgs_allExp.reshape( (-1, ROIavgs_allExp.shape[-1])).T, axis=1), header=str_hdr_raw, **self.savetxt_kwargs)
def LoadFromConfig(ConfigFile, outFolder=None): """Loads a CorrMaps object from a config file like the one exported with CorrMaps.ExportConfiguration() Parameters ---------- ConfigFile : full path of the config file to read outFolder : folder containing correlation maps. if None, the value from the config file will be used if not None, the value from the config file will be discarded Returns ------- a CorrMaps object with an "empty" image MIfile (containing metadata but no actual image data) """ config = cf.Config(ConfigFile) if (outFolder is None): outFolder = config.Get('corrmap_parameters', 'out_folder') kernel_specs = DSH.Kernel.Kernel(config.ToDict(section='kernel')) return CorrMaps(MI.MIfile(None,config.ToDict(section='imgs_metadata')),\ outFolder, config.Get('corrmap_parameters', 'lags', [], int),\ kernel_specs, config.Get('corrmap_parameters', 'img_range', None, int),\ config.Get('corrmap_parameters', 'crop_roi', None, int))
def LoadFiles(self, mi_fnames, metadata_section='MIfile', open_mifiles=True, replace_previous=False): """Load list of filenames Parameters ---------- mi_fnames : list of filenames (full path, str) open_mifiles : if True, open each MIfile for reading replace_previous : if True, replace eventual preexisting list of MIfile """ if (replace_previous or self.MIfiles is None): self.MIfiles = [] self.IdxList = [] for i in range(len(mi_fnames)): self.IdxList.append(sf.LastIntInStr(mi_fnames[i])) self.MIfiles.append( MI.MIfile(mi_fnames[i], self.MetaData.ToDict(section=metadata_section))) if open_mifiles: self.MIfiles[-1].OpenForReading() self._loaded = True
def Validate_zRange(self, zRange, replaceNone=True): return MI.Validate_zRange(zRange, self.ImageNumber(), replaceNone)
def ValidateROI(self, ROI): return MI.ValidateROI(ROI, self.ImageShape())
# Read current input section mi_fname = os.path.join(froot, conf.Get(cur_sec, 'mi_file')) if ('-silent' not in cmd_list): print(' - ' + str(cur_sec) + ': working with ' + str(mi_fname) + '...') meta_fname = os.path.join(froot, conf.Get(cur_sec, 'meta_file')) out_folder = os.path.join(froot, conf.Get(cur_sec, 'out_folder')) img_range = conf.Get(cur_sec, 'img_range', None, int) crop_roi = conf.Get(cur_sec, 'crop_roi', None, int) SharedFunctions.CheckCreateFolder(out_folder) logging.basicConfig(filename=os.path.join(out_folder, 'DSH' + str(g_params['log_suffix']) + '.log'),\ level=logging.DEBUG, format='%(asctime)s | %(levelname)s:%(message)s') logging.info('Now starting analysis in folder ' + str(out_folder)) # Initialize image and correlation files mi_file = MIfile.MIfile(mi_fname, meta_fname) corr_maps = CorrMaps.CorrMaps(mi_file, out_folder, lag_list, kernel_specs, img_range, crop_roi) # Calculate correlation maps if ('-skip_cmap' not in cmd_list): if ('-silent' not in cmd_list): print(' - Computing correlation maps (multiprocess mode to be implemented)') corr_maps.Compute(silent=True, return_maps=False) if (('-skip_vmap' not in cmd_list) or (num_proc > 1 and '-skip_vmap_assemble' not in cmd_list) or ('-skip_displ' not in cmd_list) or ('-skip_grad' not in cmd_list)): # Read options for velocity calculation vmap_kw = VelMaps._get_kw_from_config(conf, section='velmap_parameters') # Initialize MelMaps object vel_maps = VelMaps.VelMaps(corr_maps, **SharedFunctions.filter_kwdict_funcparams(vmap_kw, VelMaps.VelMaps.__init__))
def LoadFromConfig(ConfigFile, input_sect='input', outFolder=None): """Loads a SALS object from a config file like the one exported with VelMaps.ExportConfig() Parameters ---------- ConfigFile : full path of the config file to read outFolder : folder containing velocity and correlation maps. if None, the value from the config file will be used if not None, the value from the config file will be discarded Returns ------- a SALS object, eventually with an "empty" image MIfile (containing metadata but no actual image data) """ config = cf.Config(ConfigFile) froot = config.Get('global', 'root', '', str) miin_fname = config.Get(input_sect, 'mi_file', None, str) miin_meta_fname = config.Get(input_sect, 'meta_file', None, str) input_stack = False if (miin_fname is not None): # if miin_fname is a string, let's use a single MIfile as input. # otherwise, it can be a list: in that case, let's use a MIstack as input if (isinstance(miin_fname, str)): miin_fname = os.path.join(froot, miin_fname) else: input_stack = True for i in range(len(miin_fname)): miin_fname[i] = os.path.join(froot, miin_fname[i]) if (miin_meta_fname is not None): miin_meta_fname = os.path.join(froot, miin_meta_fname) elif input_stack: logging.error( 'SALS.LoadFromConfig ERROR: medatada filename must be specified when loading a MIstack' ) return None if input_stack: MIin = MIs.MIstack(miin_fname, miin_meta_fname, Load=True, StackType='t') else: MIin = MI.MIfile(miin_fname, miin_meta_fname) ctrPos = config.Get('SALS_parameters', 'center_pos', None, float) if (ctrPos is None): logging.error( 'SALS.LoadFromConfig ERROR: no SALS_parameters.center_pos parameter found in config file ' + str(ConfigFile)) return None else: r_max = ppf.MaxRadius(MIin.ImageShape(), ctrPos) radRange = sf.ValidateRange(config.Get('SALS_parameters', 'r_range', None, float), r_max, MinVal=1, replaceNone=True) angRange = sf.ValidateRange(config.Get('SALS_parameters', 'a_range', None, float), 2 * np.pi, replaceNone=True) rSlices = np.geomspace(radRange[0], radRange[1], int(radRange[2]) + 1, endpoint=True) aSlices = np.linspace(angRange[0], angRange[1], int(angRange[2]) + 1, endpoint=True) if (outFolder is None): outFolder = config.Get(input_sect, 'out_folder', None, str) if (outFolder is not None): outFolder = os.path.join(config.Get('global', 'root', '', str), outFolder) mask = config.Get('SALS_parameters', 'px_mask', None, str) mask = MI.ReadBinary( sf.PathJoinOrNone(froot, config.Get(input_sect, 'px_mask', mask, str)), MIin.ImageShape(), MIin.DataFormat(), 0) dark = MI.ReadBinary( sf.PathJoinOrNone(froot, config.Get(input_sect, 'dark_bkg', None, str)), MIin.ImageShape(), MIin.DataFormat(), 0) opt = MI.ReadBinary( sf.PathJoinOrNone(froot, config.Get(input_sect, 'opt_bkg', None, str)), MIin.ImageShape(), MIin.DataFormat(), 0) PD_data = sf.PathJoinOrNone( froot, config.Get(input_sect, 'pd_file', None, str)) if (PD_data is not None): PD_data = np.loadtxt(PD_data, dtype=float) img_times = config.Get(input_sect, 'img_times', None, str) if img_times is not None: # if miin_fname is a string, let's use a single text file as input. # otherwise, it can be a list: in that case, let's open each text file and append all results if (isinstance(img_times, str)): img_times = np.loadtxt(os.path.join(froot, img_times), dtype=float, usecols=config.Get( 'format', 'img_times_colidx', 0, int), skiprows=1) else: tmp_times = np.empty(shape=(0, ), dtype=float) for cur_f in img_times: tmp_times = np.append( tmp_times, np.loadtxt(os.path.join(froot, cur_f), dtype=float, usecols=config.Get('format', 'img_times_colidx', 0, int), skiprows=1)) img_times = tmp_times exp_times = sf.PathJoinOrNone( froot, config.Get(input_sect, 'exp_times', None, str)) if (exp_times is not None): exp_times = np.unique( np.loadtxt(exp_times, dtype=float, usecols=config.Get('format', 'exp_times_colidx', 0, int))) dlsLags = config.Get('SALS_parameters', 'dls_lags', None, int) tavgT = config.Get('SALS_parameters', 'timeavg_T', None, int) return SALS(MIin, outFolder, ctrPos, [rSlices, aSlices], mask, [dark, opt, PD_data], exp_times, dlsLags, img_times, tavgT)
def Compute(self, silent=True, return_maps=False): """Computes correlation maps Parameters ---------- silent : bool. If set to False, procedure will print to output every time steps it goes through. otherwise, it will run silently return_maps : bool. If set to True, procedure will return the array with correlation maps. Warning: no memory check is done when this happens, so be aware of memory consumption Returns ------- res_4D : list of correlation maps (np.float32), if return_maps==True """ if not silent: start_time = time.time() print('Computing correlation maps:') sf.CheckCreateFolder(self.outFolder) self.ExportConfiguration() if not silent: print( ' STEP 1: Loading images and computing average intensity...') # This will contain image data, eventually zero-padded Intensity = np.empty(self.inputShape) # This will contain kernel-averaged intensity data AvgIntensity = np.empty( [self.inputShape[0], self.outputShape[1], self.outputShape[2]]) # This will contain autocorrelation data ("d0") AutoCorr = np.empty(self.outputShape) # 2D Kernel to convolve to spatially average images ker2D = self.Kernel.ToMatrix() # This is to properly normalize correlations at the edges ConvNorm = signal.convolve2d(np.ones_like(Intensity[0]), ker2D, mode=self.Kernel.convolveMode, **self.Kernel.convolve_kwargs) # Now load all images we need self.MIinput.OpenForReading() for utidx in range(len(self.UniqueIdx)): Intensity[utidx] = self.MIinput.GetImage( img_idx=self.UniqueIdx[utidx], cropROI=self.cropROI) AvgIntensity[utidx] = signal.convolve2d( Intensity[utidx], ker2D, mode=self.Kernel.convolveMode, **self.Kernel.convolve_kwargs) if (self.Kernel.convolveMode == 'same'): AvgIntensity[utidx] = np.true_divide(AvgIntensity[utidx], ConvNorm) self.MIinput.Close() if not silent: print(' STEP 2: Computing contrast...') for tidx in range(self.outputShape[0]): AutoCorr[tidx] = signal.convolve2d(np.square(Intensity[self.imgIdx[tidx,0,0]]),\ ker2D, mode=self.Kernel.convolveMode, **self.Kernel.convolve_kwargs) if (self.Kernel.Padding): AutoCorr[tidx] = np.true_divide(AutoCorr[tidx], ConvNorm) AutoCorr[tidx] = np.subtract( np.true_divide(AutoCorr[tidx], np.square(AvgIntensity[tidx])), 1) MI.MIfile(os.path.join(self.outFolder, 'CorrMap_d0.dat'), self.outMetaData).WriteData(AutoCorr) if not silent: print(' STEP 3: Computing correlations...') if return_maps: res_4D = [np.asarray(AutoCorr, dtype=np.float32)] for lidx in range(self.numLags): if not silent: print(' ...lag ' + str(self.lagList[lidx])) CorrMap = np.empty_like(AutoCorr) for tidx in range(self.imgNumber - self.lagList[lidx]): CorrMap[tidx] = signal.convolve2d(np.multiply(Intensity[self.imgIdx[tidx,lidx,0]], Intensity[self.imgIdx[tidx,lidx,1]]),\ ker2D, mode=self.Kernel.convolveMode, **self.Kernel.convolve_kwargs) if (self.Kernel.Padding): CorrMap[tidx] = np.true_divide(CorrMap[tidx], ConvNorm) CorrMap[tidx] = np.true_divide(np.subtract(np.true_divide(CorrMap[tidx],\ np.multiply(AvgIntensity[self.imgIdx[tidx,lidx,0]],\ AvgIntensity[self.imgIdx[tidx,lidx,1]])),\ 1),\ AutoCorr[tidx]) # NOTE: in principle a better normalization for CorrMap is with # 0.5 * (AutoCorr[t] + AutoCorr[t+tau]) MI.MIfile( os.path.join( self.outFolder, 'CorrMap_d' + str(self.lagList[lidx]).zfill(4) + '.dat'), self.outMetaData).WriteData(CorrMap) if return_maps: res_4D.append(np.asarray(CorrMap, dtype=np.float32)) if not silent: print( 'Procedure completed in {0:.1f} seconds!'.format(time.time() - start_time)) if return_maps: return res_4D else: return None
def Compute(self): sf.CheckCreateFolder(self.outFolder) logging.info( 'NonAffMaps.Compute() started! Result will be saved in folder ' + str(self.outFolder)) # Search for correlation map MIfiles, skip autocorrelation maps fw_mistack = self.cmaps_fw.GetCorrMaps(openMIfiles=True) bk_mistack = self.cmaps_bk.GetCorrMaps(openMIfiles=True) common_lags = list( set(fw_mistack.IdxList).intersection(bk_mistack.IdxList)) if self.lag_range is None: if 0 in common_lags: common_lags.remove(0) else: if self.lag_range[1] < 0: self.lag_range[1] = np.max(common_lags) + 1 common_lags = [ lag for lag in common_lags if (lag != 0 and lag >= self.lag_range[0] and lag <= self.lag_range[1]) ] self.lagList = common_lags # Export configuration self.ExportConfiguration() if self.trans_bk_matrix is not None: tr_matrix = np.reshape(np.asarray(self.trans_bk_matrix), (2, 2)) logging.debug( 'Backscattered correlation maps will be transformed using matrix ' + str(tr_matrix) + ' and offset ' + str(self.trans_bk_offset)) # For each couple of correlation maps (with equal lagtime) for lidx in range(len(self.lagList)): logging.info('Now working on lagtime ' + str(lidx) + '/' + str(len(self.lagList)) + ' (d' + str(self.lagList[lidx]) + ')') fw_lidx = fw_mistack.IdxList.index(self.lagList[lidx]) bk_lidx = bk_mistack.IdxList.index(self.lagList[lidx]) # eventually compute normalization factors if self.norm_range is not None: fw_norm_factor = np.mean(fw_mistack.MIfiles[fw_lidx].Read( zRange=self.norm_range[:2], cropROI=self.norm_range[2:], closeAfter=False)) if self.trans_bk_matrix is None and self.trans_bk_offset is None: bk_norm_factor = np.mean(bk_mistack.MIfiles[bk_lidx].Read( zRange=self.norm_range[:2], cropROI=self.norm_range[2:], closeAfter=False)) else: bk_norm_data = bk_mistack.MIfiles[bk_lidx].Read( zRange=self.norm_range[:2], cropROI=None, closeAfter=False) if len(bk_norm_data.shape) > 2: bk_norm_data = np.mean(bk_norm_data, axis=0) logging.debug('shape before transformation: ' + str(bk_norm_data.shape)) bk_norm_data = sp.ndimage.affine_transform(bk_norm_data, tr_matrix, offset=self.trans_bk_offset,\ output_shape=bk_norm_data.shape, order=1, mode='constant', cval=1.0) norm_cropROI = MI.ValidateROI(self.norm_range[2:], bk_norm_data.shape, replaceNone=True) logging.debug('shape after transformation: ' + str(bk_norm_data.shape) + ' will be cropped with ROI ' + str(norm_cropROI)) bk_norm_factor = np.mean(bk_norm_data[norm_cropROI[1]:norm_cropROI[1]+norm_cropROI[3],\ norm_cropROI[0]:norm_cropROI[0]+norm_cropROI[2]]) bk_norm_data = None else: fw_norm_factor, bk_norm_factor = 1, 1 logging.info('Normalization factors: ' + str(fw_norm_factor) + ' (front) and ' + str(bk_norm_factor) + ' (back)') # load, normalize and eventually smooth correlation maps. fw_data = np.true_divide( fw_mistack.MIfiles[fw_lidx].Read(zRange=self.t_range, cropROI=self.cropROI, closeAfter=True), fw_norm_factor) bk_data = np.true_divide( bk_mistack.MIfiles[bk_lidx].Read(zRange=self.t_range, cropROI=self.cropROI, closeAfter=True), bk_norm_factor) if self.smooth_kernel_specs is not None: Kernel3D = self.LoadKernel(self.smooth_kernel_specs) logging.debug('Smoothing with kernel with shape ' + str(Kernel3D.shape)) fw_data = signal.convolve(fw_data, Kernel3D, mode='same') bk_data = signal.convolve(bk_data, Kernel3D, mode='same') # transform backscattered images if self.trans_bk_matrix is not None: tr_matrix3D = np.asarray( [[1, 0, 0], [0, tr_matrix[0, 0], tr_matrix[0, 1]], [0, tr_matrix[1, 0], tr_matrix[1, 1]]]) tr_offset3D = np.asarray( [0, self.trans_bk_offset[0], self.trans_bk_offset[1]]) bk_data = sp.ndimage.affine_transform(bk_data, tr_matrix3D, offset=tr_offset3D,\ output_shape=fw_data.shape, order=1, mode='constant', cval=1.0) # sigma2 = ln(forward-scattering corr / backscattering corr) * 6 / (qz_bk^2 - qz_fw^2) sigma2 = np.log(np.true_divide( fw_data, bk_data)) * 6.0 / (self.qz_bk**2 - self.qz_fw**2) # For the first lagtime, generate and export metadata if (lidx == 0): out_meta = fw_mistack.MIfiles[fw_lidx].GetMetadata().copy() out_meta['hdr_len'] = 0 out_meta['gap_bytes'] = 0 out_meta['shape'] = list(sigma2.shape) if ('fps' in out_meta): val_tRange = fw_mistack.MIfiles[fw_lidx].Validate_zRange( self.t_range) out_meta['fps'] = float( out_meta['fps']) * 1.0 / val_tRange[2] exp_config = cf.Config() exp_config.Import(out_meta, section_name='MIfile') metadata_fname = os.path.join(self.outFolder, 'NAffMap_metadata.ini') exp_config.Export(metadata_fname) logging.info('Metadata exported to file ' + str(metadata_fname)) # export data cur_fname = 'NaffMap_d' + str(self.lagList[lidx]).zfill(4) + '.dat' MI.MIfile(os.path.join(self.outFolder, cur_fname), metadata_fname).WriteData(sigma2) logging.info('Result saved to file ' + str(cur_fname)) fw_mistack.MIfiles[fw_lidx].Close() bk_mistack.MIfiles[bk_lidx].Close()
def GetCorrMaps(self, openMIfiles=True, getAutocorr=True, check_lagtimes=False): """Searches for MIfile correlation maps Parameters ---------- openMIfiles: if true, it opens all MIfiles for reading. getAutocorr: if True, returns d0 in the list of correlation maps otherwise, returns None instead of the autocorrelation map check_lagtimes: if true, checks that the lagtimes extracted from the filenames match with self.lagList Returns ------- corr_config: configuration file for correlation maps corr_mifiles: list of correlation maps, one per time delay lag_list: list of lagtimes """ if not self._corrmaps_loaded: assert os.path.isdir( self.outFolder), 'Correlation map folder ' + str( self.outFolder) + ' not found.' config_fname = os.path.join(self.outFolder, 'CorrMapsConfig.ini') assert os.path.isfile(config_fname), 'Configuration file ' + str( config_fname) + ' not found' self.conf_cmaps = cf.Config(config_fname) all_cmap_fnames = sf.FindFileNames(self.outFolder, Prefix='CorrMap_d', Ext='.dat', Sort='ASC', AppendFolder=True) self.cmap_mifiles = [] self.all_lagtimes = [] for i in range(len(all_cmap_fnames)): cur_lag = sf.LastIntInStr(all_cmap_fnames[i]) self.all_lagtimes.append(cur_lag) self.cmap_mifiles.append( MI.MIfile( all_cmap_fnames[i], self.conf_cmaps.ToDict(section='corrmap_metadata'))) self.cmap_mifiles[-1].OpenForReading() # Check lagtimes for consistency if (check_lagtimes): print( 'These are all lagtimes. They should be already sorted and not contain 0:' ) print(self.all_lagtimes) for cur_lag in self.lagList: if (cur_lag not in self.all_lagtimes): print( 'WARNING: no correlation map found for lagtime ' + str(cur_lag)) self._corrmaps_loaded = True if (self.all_lagtimes[0] == 0 and getAutocorr == False): return self.conf_cmaps, [ None ] + self.cmap_mifiles[1:], self.all_lagtimes else: return self.conf_cmaps, self.cmap_mifiles, self.all_lagtimes