diff --git a/pearl/pearl-anglescan-process.ipf b/pearl/pearl-anglescan-process.ipf index 94d5e03..d6e1c49 100644 --- a/pearl/pearl-anglescan-process.ipf +++ b/pearl/pearl-anglescan-process.ipf @@ -6,14 +6,14 @@ #include "pearl-polar-coordinates" #include -// $Id$ -// -// copyright (c) 2013-15 Paul Scherrer Institut +// copyright (c) 2013-16 Paul Scherrer Institut // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http:///www.apache.org/licenses/LICENSE-2.0 +// +// Please acknowledge the use of this code. /// @file /// @brief processing and holographic mapping of angle scanned XPD data. @@ -64,7 +64,7 @@ /// /// @author matthias muntwiler, matthias.muntwiler@psi.ch /// -/// @copyright 2013-15 Paul Scherrer Institut @n +/// @copyright 2013-16 Paul Scherrer Institut @n /// Licensed under the Apache License, Version 2.0 (the "License"); @n /// you may not use this file except in compliance with the License. @n /// You may obtain a copy of the License at @@ -79,15 +79,38 @@ /// /// PearlAnglescanProcess is declared in @ref pearl-anglescan-process.ipf. -/// @warning experimental -function strip_remove_frames(strip, yscale, ylo, yhi) + +/// delete a contiguous range of frames from a strip. +/// +/// this can be used to remove a region of bad frames due to, e.g., measurement problems. +/// the function operates on 2D intensity data and manipulator coordinates at the same time. +/// +/// @param[in,out] strip 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan. +/// the result is written to the original wave. +/// +/// @param[in,out] theta 1D data, manipulator scan. +/// the result is written to the original wave. +/// +/// @param[in,out] tilt 1D data, manipulator scan. +/// the result is written to the original wave. +/// +/// @param[in,out] phi 1D data, manipulator scan. +/// the result is written to the original wave. +/// +/// @param[in] qlo point index of first frame to delete. +/// +/// @param[in] qhi point index of last frame to delete. +/// qhi must be greater or equal than qlo. +/// +function strip_delete_frames(strip, qlo, qhi, theta, tilt, phi) wave strip // 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan - wave /z yscale // Y scaling, e.g. ManipulatorPhi - // if unassigned, point scaling is assumed - variable ylo - variable yhi + variable qlo + variable qhi + wave theta + wave tilt + wave phi - if (ylo > yhi) + if (qlo > qhi) return -1 endif @@ -95,8 +118,8 @@ function strip_remove_frames(strip, yscale, ylo, yhi) variable snx = dimsize(strip, 0) variable sny = dimsize(strip, 1) variable sq1lo = 0 - variable sq1hi = max(round((ylo - dimoffset(strip, 1)) / dimdelta(strip, 1)), 0) - variable sq2lo = min(round((ylo - dimoffset(strip, 1)) / dimdelta(strip, 1)), sny - 1) + variable sq1hi = max(qlo-1, 0) + variable sq2lo = min(qhi+1, sny - 1) variable sq2hi = dimsize(strip, 1) - 1 // dest indices @@ -111,10 +134,24 @@ function strip_remove_frames(strip, yscale, ylo, yhi) duplicate /free strip, strip_copy redimension /n=(dnx,dny) strip - strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs] strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs] + duplicate /free theta, theta_copy + redimension /n=(dny) theta + theta[dq1lo,dq1hi] = theta_copy[p + q1ofs] + theta[dq2lo,dq2hi] = theta_copy[p + q2ofs] + + duplicate /free tilt, tilt_copy + redimension /n=(dny) tilt + tilt[dq1lo,dq1hi] = tilt_copy[p + q1ofs] + tilt[dq2lo,dq2hi] = tilt_copy[p + q2ofs] + + duplicate /free phi, phi_copy + redimension /n=(dny) phi + phi[dq1lo,dq1hi] = phi_copy[p + q1ofs] + phi[dq2lo,dq2hi] = phi_copy[p + q2ofs] + return 0 end @@ -144,6 +181,7 @@ end /// @return if check waves are enabled, the following waves are created (overwritten if existing): /// @arg check_dist average X distribution /// @arg check_smoo smoothed distribution used to normalize the strip +/// function normalize_strip_x(strip, [smooth_method, smooth_factor, check]) wave strip variable smooth_method @@ -233,6 +271,7 @@ end /// @return if check waves are enabled, the following waves are created (overwritten if existing): /// @arg check_dist average theta distribution /// @arg check_smoo smoothed distribution used to normalize the strip +/// function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smooth_factor, check]) wave strip wave theta @@ -300,6 +339,70 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot endif end +/// divide the strip by a two-dimensional normalization function. +/// +/// @warning experimental. this function is under development. +/// +/// @param check enable output of intermediate results +/// @arg 0 (default) don't create additional waves +/// @arg 1 create check waves in the current folder +/// @arg 2 calculate check waves only, do not modify strip +/// +/// @return if check waves are enabled, the following waves are created (overwritten if existing): +/// @arg check_dist average theta distribution +/// @arg check_smoo smoothed distribution used to normalize the strip +/// +function normalize_strip_2d(strip, theta, [theta_offset, smooth_method, smooth_factor, check]) + wave strip + wave theta + variable theta_offset + variable smooth_method + variable smooth_factor + variable check + + if (ParamIsDefault(check)) + check = 0 + endif + if (ParamIsDefault(theta_offset)) + theta_offset = 0 + endif + if (ParamIsDefault(smooth_method)) + smooth_method = 4 + endif + if (ParamIsDefault(smooth_factor)) + smooth_factor = 0.5 + endif + + variable nx = dimsize(strip, 0) + variable ny = dimsize(strip, 1) + + duplicate /free strip, dist, alpha_int, theta_int + theta_int = theta[q] - theta_offset + alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0) + redimension /n=(nx * ny) dist, alpha_int, theta_int + + switch(smooth_method) + case 4: + loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={alpha_int, theta_int} + redimension /n=(nx, ny) dist_smoo + break + default: + Abort "undefined smooth method" + break + endswitch + + // divide + if (check != 2) + strip /= dist_smoo + endif + + // check + if (check) + //duplicate /o dist, check_dist + duplicate /o dist_smoo, check_smoo + endif +end + /// crop a strip at the sides. /// /// the strip is cropped in place, data outside the region of interest is lost. diff --git a/pearl/pearl-area-display.ipf b/pearl/pearl-area-display.ipf index 7c2bb98..8be128e 100644 --- a/pearl/pearl-area-display.ipf +++ b/pearl/pearl-area-display.ipf @@ -52,6 +52,25 @@ /// PearlAreaDisplay is declared in @ref pearl-area-display.ipf. /// +/// compose a valid and unique graph name from a data folder reference +static function /s graphname_from_dfref(df, prefix) + dfref df + string prefix + + string name + + name = GetDataFolder(1, df) + name = ReplaceString("root:", name, "") + name = name[0, strlen(name) - 2] + name = ReplaceString(" ", name, "") + name = CleanupName(prefix + name, 0) + if (CheckName(name, 6)) + name = UniqueName(name, 6, 0) + endif + + return name +end + /// open a new graph window with a 2D image. /// /// this is essentially display; appendimage. @@ -72,7 +91,7 @@ function /s ad_display(image) string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string graphtitle = dfname + " View" - string /g view_graphname = CleanupName("view_" + dfname, 0) + string /g view_graphname = graphname_from_dfref(imagedf, "view_") svar graphname = view_graphname display /k=1/n=$graphname as graphtitle graphname = s_name @@ -104,7 +123,7 @@ function /s ad_display_histogram(image) string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string graphtitle = dfname + " Histogram" - string /g hist_graphname = CleanupName("hist_" + dfname, 0) + string /g hist_graphname = graphname_from_dfref(imagedf, "hist_") svar graphname = hist_graphname display /k=1/n=$graphname as graphtitle graphname = s_name @@ -177,9 +196,9 @@ function /s ad_display_profiles(image, [filter]) view_filter_options = "" variable /g view_filter_smoothing_x = 1 variable /g view_filter_smoothing_y = 1 - string dfname = GetDataFolder(0, imagedf) - string graphtitle = dfname + ":" + NameOfWave(image) + " Profiles" - string /g prof_graphname = CleanupName("prof_" + dfname, 0) + string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") + string graphtitle = dfname + NameOfWave(image) + " Profiles" + string /g prof_graphname = graphname_from_dfref(imagedf, "prof_") svar graphname = prof_graphname variable /g graph_avg // average value in ROI (ROI is defined by the crosshairs A and B) variable /g graph_min // minimum value in ROI @@ -1004,7 +1023,7 @@ function /s ad_display_brick(data) setdatafolder viewdf string dfname = ReplaceString("root:", s_datadf, "") string graphtitle = dfname + " Gizmo" - string /g gizmo_graphname = CleanupName("giz_" + dfname, 0) + string /g gizmo_graphname = graphname_from_dfref(datadf, "giz_") svar graphname = gizmo_graphname if ((strlen(graphname) > 0) && (wintype(graphname) == 13)) diff --git a/pearl/pearl-data-explorer.ipf b/pearl/pearl-data-explorer.ipf index ae09efa..e44a185 100644 --- a/pearl/pearl-data-explorer.ipf +++ b/pearl/pearl-data-explorer.ipf @@ -1450,7 +1450,7 @@ static function bp_dataset_folder(ba) : ButtonControl string cmd sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset) execute /q /z cmd - cmd = "setdatafolder :scan_1" + cmd = "setdatafolder :scan1" execute /q /z cmd sprintf cmd, "setdatafolder %s", GetDataFolder(1) print cmd diff --git a/pearl/pearl-pshell-import.ipf b/pearl/pearl-pshell-import.ipf index 32e796a..aebf98d 100644 --- a/pearl/pearl-pshell-import.ipf +++ b/pearl/pearl-pshell-import.ipf @@ -183,7 +183,9 @@ function /s psh5_load_complete(ANickName, APathName, AFileName, [load_data, load for (ig = 0; ig < ng; ig += 1) sg = StringFromList(ig, s_scanpaths, ";") - folder = CleanupName(ReplaceString("/", sg, ""), 0) + folder = ReplaceString("/", sg, "") + folder = ReplaceString(" ", folder, "") + folder = CleanupName(folder, 0) setdatafolder fileDF newdatafolder /s /o $folder psh5_load_scan_complete(fileID, sg, load_data=load_data, load_attr=load_attr) @@ -219,14 +221,26 @@ end /// @param load_attr 1 (default): load attributes; 0: do not load attributes /// note: for correct scaling of the image, the attributes need to be loaded /// +/// @param pref_scans semicolon-separated list of preferred scans. +/// the items of the list are match strings for the Igor StringMatch function. +/// the first matching scan (i.e. top-level HDF5 group with a matching name) is loaded from the file. +/// if no match is found, the first scan is loaded. +/// +/// @param pref_datasets semicolon-separated list of preferred datasets. +/// the items of the list are match strings for the Igor StringMatch function. +/// the first matching dataset is loaded from the file. +/// if no match is found, the first dataset listed in the file is loaded. +/// /// @return name of loaded preview wave. /// -function /s psh5_load_preview(ANickName, APathName, AFileName, [load_data, load_attr]) +function /s psh5_load_preview(ANickName, APathName, AFileName, [load_data, load_attr, pref_scans, pref_datasets]) string ANickName string APathName string AFileName variable load_data variable load_attr + string pref_scans + string pref_datasets if (ParamIsDefault(load_data)) load_data = 1 @@ -234,7 +248,13 @@ function /s psh5_load_preview(ANickName, APathName, AFileName, [load_data, load_ if (ParamIsDefault(load_attr)) load_attr = 1 endif - + if (ParamIsDefault(pref_scans)) + pref_scans = "*scan1*;" + endif + if (ParamIsDefault(pref_datasets)) + pref_datasets = "" + endif + dfref saveDF = GetDataFolderDFR() setdatafolder root: newdatafolder /o/s pearl_area @@ -253,12 +273,35 @@ function /s psh5_load_preview(ANickName, APathName, AFileName, [load_data, load_ if (v_flag == 0) AFileName = s_path + s_filename dfref fileDF = GetDataFolderDFR() + scanpaths = psh5_list_scans(fileID) + variable ng = ItemsInList(scanpaths) variable ig string sg - ig = 0 - sg = StringFromList(ig, scanpaths, ";") - dataname = psh5_load_scan_preview(fileID, sg, set_scale=load_attr) + variable np = ItemsInList(pref_scans) + variable ip + string sp + variable found = 0 + if (ng > 0) + for (ip = 0; ip < np; ip += 1) + for (ig = 0; ig < ng; ig += 1) + sg = StringFromList(ig, scanpaths) + sp = StringFromList(ip, pref_scans) + if (StringMatch(sg, sp)) + found = 1 + break + endif + endfor + if (found) + break + endif + endfor + if (!found) + ig = 0 + endif + sg = StringFromList(ig, scanpaths) + dataname = psh5_load_scan_preview(fileID, sg, set_scale=load_attr, pref_datasets=pref_datasets) + endif wave /z data = $dataname string destpath = GetDataFolder(1, saveDF) + ANickName @@ -396,6 +439,9 @@ end /// /// data is loaded into the current data folder. /// +/// this function does not scale the datasets. +/// call ps_scale_datasets() separately. +/// /// @param fileID ID of open HDF5 file from psh5_open_file(). /// /// @param scanpath path to the scan group in the HDF5 file, e.g. "/scan 1". @@ -517,28 +563,29 @@ function /s psh5_load_scan_meta(fileID, scanpath) HDF5LoadData /O /Q /Z /A="Dimensions" /N=ScanDimensions /TYPE=1 fileID, scanpath if (!v_flag) wavenames = AddListItem(s_wavenames, wavenames, ";", inf) - HDF5LoadData /O /Q /Z /A="Writables" /N=ScanWritables /TYPE=1 fileID, scanpath - if (!v_flag) - wavenames = AddListItem(s_wavenames, wavenames, ";", inf) - endif - HDF5LoadData /O /Q /Z /A="Readables" /N=ScanReadables /TYPE=1 fileID, scanpath - if (!v_flag) - wavenames = AddListItem(s_wavenames, wavenames, ";", inf) - endif - HDF5LoadData /O /Q /Z /A="Steps" /N=ScanSteps /TYPE=1 fileID, scanpath - if (!v_flag) - wavenames = AddListItem(s_wavenames, wavenames, ";", inf) - endif else make /n=1 /o ScanDimensions ScanDimensions = 0 wavenames = AddListItem("ScanDimensions", wavenames, ";", inf) + endif + HDF5LoadData /O /Q /Z /A="Readables" /N=ScanReadables /TYPE=1 fileID, scanpath + if (!v_flag) + wavenames = AddListItem(s_wavenames, wavenames, ";", inf) + else make /n=1 /o /t ScanReadables ScanReadables[0] = "ScientaSpectrum" wavenames = AddListItem("ScanReadables", wavenames, ";", inf) endif + HDF5LoadData /O /Q /Z /A="Writables" /N=ScanWritables /TYPE=1 fileID, scanpath + if (!v_flag) + wavenames = AddListItem(s_wavenames, wavenames, ";", inf) + endif + HDF5LoadData /O /Q /Z /A="Steps" /N=ScanSteps /TYPE=1 fileID, scanpath + if (!v_flag) + wavenames = AddListItem(s_wavenames, wavenames, ";", inf) + endif wavenames = ReplaceString(";;", wavenames, ";") - + return wavenames end @@ -573,6 +620,10 @@ function /s psh5_load_dataset(fileID, scanpath, datasetname, [set_scale]) string datasetname variable set_scale + if (ParamIsDefault(set_scale)) + set_scale = 1 + endif + string datasetpath datasetpath = scanpath + "/" + datasetname datasetpath = ReplaceString("//", datasetpath, "/") @@ -586,7 +637,7 @@ function /s psh5_load_dataset(fileID, scanpath, datasetname, [set_scale]) endif string dataname - if (di.ndims < 3) + if (di.ndims < 2) HDF5LoadData /O /Q /Z fileID, datasetpath dataname = StringFromList(0, S_waveNames) else @@ -626,42 +677,68 @@ end /// @arg 1 (default) set the wave scaling. /// @arg 0 do not set the wave scaling. /// +/// @param pref_datasets semicolon-separated list of preferred datasets. +/// the items of the list are match strings for the Igor StringMatch function. +/// the first matching dataset is loaded from the file. +/// if no match is found, the first dataset listed in the file is loaded. +/// if empty, a hard-coded default preference list is used. +/// /// @return name of loaded wave if successful. empty string otherwise. /// -function /s psh5_load_scan_preview(fileID, scanpath, [set_scale]) +function /s psh5_load_scan_preview(fileID, scanpath, [set_scale, pref_datasets]) variable fileID string scanpath variable set_scale + string pref_datasets + + if (ParamIsDefault(set_scale)) + set_scale = 1 + endif + if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0)) + pref_datasets = "ScientaImage;ScientaSpectrum;ImageAngleDistribution;ImageEnergyDistribution;Counts;SampleCurrent" + endif dfref saveDF = GetDataFolderDFR() dfref dataDF = saveDF string datasets = psh5_list_scan_datasets(fileID, scanpath) - string datasetname = "" variable index - // todo: this should be generalized - if (strsearch(datasets, "ScientaImage", 0) >= 0) - datasetname = "ScientaImage" - elseif (strsearch(datasets, "ScientaSpectrum", 0) >= 0) - datasetname = "ScientaSpectrum" - elseif (strsearch(datasets, "ScientaEnergyDistribution", 0) >= 0) - datasetname = "ScientaEnergyDistribution" - elseif (strsearch(datasets, "ImageEnergyDistribution", 0) >= 0) - datasetname = "ImageEnergyDistribution" - elseif (strsearch(datasets, "Counts", 0) >= 0) - datasetname = "Counts" - elseif (strsearch(datasets, "SampleCurrent", 0) >= 0) - datasetname = "SampleCurrent" + + variable nds = ItemsInList(datasets) + variable ids + string sds + variable np = ItemsInList(pref_datasets) + variable ip + string sp + variable found = 0 + if (nds > 0) + for (ip = 0; ip < np; ip += 1) + for (ids = 0; ids < nds; ids += 1) + sds = StringFromList(ids, datasets) + index = ItemsInList(sds, "/") - 1 + sds = StringFromList(index, sds, "/") + sp = StringFromList(ip, pref_datasets) + if (StringMatch(sds, sp)) + found = 1 + break + endif + endfor + if (found) + break + endif + endfor + if (!found) + ids = 0 + sds = StringFromList(ids, datasets) + index = ItemsInList(sds, "/") - 1 + sds = StringFromList(index, sds, "/") + endif else - datasetname = StringFromList(0, datasets) - index = ItemsInList(datasetname, "/") - 1 - datasetname = StringFromList(index, datasetname, "/") - endif - if (strlen(datasetname) == 0) return "" endif - + string datasetpath + string datasetname = sds datasetpath = scanpath + "/" + datasetname datasetpath = ReplaceString("//", datasetpath, "/") STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf. @@ -673,7 +750,7 @@ function /s psh5_load_scan_preview(fileID, scanpath, [set_scale]) endif string dataname - if (di.ndims < 3) + if (di.ndims < 2) HDF5LoadData /O /Q /Z fileID, datasetpath dataname = StringFromList(0, S_waveNames) wave /z data = $dataname @@ -803,6 +880,9 @@ end /// /// @return name of loaded wave if successful. empty string otherwise. /// +/// @todo images are transposed in the first two dimensions. +/// this is useful for Scienta images but may not be appropriate for other sources. +/// function /s psh5_load_dataset_slabs(fileID, datapath, datasetname, [progress]) variable fileID string datapath @@ -927,6 +1007,9 @@ end /// /// @return name of loaded wave if successful. empty string otherwise. /// +/// @todo images are transposed in the first two dimensions. +/// this is useful for Scienta images but may not be appropriate for other data sources. +/// function /s psh5_load_dataset_slab(fileID, datapath, datasetname, dim2start, dim2count, dim3start, dim3count) variable fileID string datapath @@ -1010,42 +1093,63 @@ end /// /// dimension labels are required by scaling functions. /// +/// @param data data wave as loaded from PShell file +/// +/// @return @arg 0 all labels set successfully. +/// @arg 1 unidentified data source. +/// @arg 2 wave does not contain data. +/// function ps_set_dimlabels(data) wave data string name = NameOfWave(data) - - // intrinsic dimensions - strswitch(name) - case "ScientaImage": - setdimlabel 0, -1, $kEnergyDimLabel, data - setdimlabel 1, -1, $kAngleDimLabel, data - if (WaveDims(data) >= 3) - setdimlabel 2, -1, $kScanDimLabel, data - endif - break - case "ImageAngleDistribution": - case "ScientaAngleDistribution": - if (WaveDims(data) >= 2) - setdimlabel 0, -1, $kScanDimLabel, data - setdimlabel 1, -1, $kAngleDimLabel, data - else - setdimlabel 0, -1, $kAngleDimLabel, data - endif - break - case "ScientaSpectrum": - case "ImageEnergyDistribution": - case "ScientaEnergyDistribution": - if (WaveDims(data) >= 2) - setdimlabel 0, -1, $kScanDimLabel, data - setdimlabel 1, -1, $kEnergyDimLabel, data - else + variable dummy + + try + // intrinsic dimensions + strswitch(name) + case "ScientaImage": setdimlabel 0, -1, $kEnergyDimLabel, data - endif - break - default: - setdimlabel 0, -1, $kScanDimLabel, data - endswitch + setdimlabel 1, -1, $kAngleDimLabel, data + if (WaveDims(data) >= 3) + setdimlabel 2, -1, $kScanDimLabel, data + endif + AbortOnRTE + break + case "ImageAngleDistribution": + case "ScientaAngleDistribution": + if (WaveDims(data) >= 2) + setdimlabel 0, -1, $kScanDimLabel, data + setdimlabel 1, -1, $kAngleDimLabel, data + else + setdimlabel 0, -1, $kAngleDimLabel, data + endif + AbortOnRTE + break + case "ScientaSpectrum": + case "ImageEnergyDistribution": + case "ScientaEnergyDistribution": + if (WaveDims(data) >= 2) + setdimlabel 0, -1, $kScanDimLabel, data + setdimlabel 1, -1, $kEnergyDimLabel, data + else + setdimlabel 0, -1, $kEnergyDimLabel, data + endif + AbortOnRTE + break + default: + if (WaveDims(data) == 1) + setdimlabel 0, -1, $kScanDimLabel, data + AbortOnRTE + else + return 1 + endif + endswitch + catch + dummy = GetRTError(1) + return 2 + endtry + return 0 end /// set the dimension scales of loaded PShell Scienta datasets according to attributes. @@ -1219,7 +1323,7 @@ function ps_detect_scale(ax, lo, hi, un) if (!WaveExists(scanner)) wave /z /SDFR=attrDF scanner = $ScanWritables[0] endif - if (WaveExists(scanner)) + if (WaveExists(scanner) && (numpnts(scanner) >= 1)) lo[%$kScanDimLabel] = scanner[0] hi[%$kScanDimLabel] = scanner[numpnts(scanner)-1] ax[%$kScanDimLabel] = NameOfWave(scanner) @@ -1362,7 +1466,9 @@ function /s psh5_load_reduced(ANickName, APathName, AFileName, reduction_func, r string folder sg = StringFromList(ig, s_scanpaths) - folder = CleanupName(ReplaceString("/", sg, ""), 0) + folder = ReplaceString("/", sg, "") + folder = ReplaceString(" ", folder, "") + folder = CleanupName(folder, 0) setdatafolder fileDF newdatafolder /s /o $folder dfref dataDF = GetDataFolderDFR()