From 80a01f2bdb6147a6e7fae76d0a6387e1bf4cda5f Mon Sep 17 00:00:00 2001 From: matthias muntwiler Date: Tue, 4 Jul 2017 11:06:49 +0200 Subject: [PATCH] updates: pshell import, angle-scans, elog - pshell import: fix units and data scaling. - pshell import: support new multi-region scans. - angle scans: add trim function. - angle scans: update import_tpi_scan function. - angle scans: fix scales of check waves in normalization. - area display: new cursor mode for background selection. - elog: bugfixes (attachment list, check existing logbook). --- pearl/pearl-anglescan-process.ipf | 75 ++++- pearl/pearl-anglescan-tracker.ipf | 4 +- pearl/pearl-area-display.ipf | 88 ++++- pearl/pearl-area-import.ipf | 4 +- pearl/pearl-data-explorer.ipf | 2 + pearl/pearl-elog.ipf | 20 +- pearl/pearl-pshell-import.ipf | 327 +++++++++++++++---- pearl/preferences/pearl_elog/preferences.pxp | Bin 2553 -> 12204 bytes 8 files changed, 426 insertions(+), 94 deletions(-) diff --git a/pearl/pearl-anglescan-process.ipf b/pearl/pearl-anglescan-process.ipf index cc779ac..a8c2324 100644 --- a/pearl/pearl-anglescan-process.ipf +++ b/pearl/pearl-anglescan-process.ipf @@ -300,6 +300,7 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot duplicate /free dist, dist_smoo duplicate /free theta, theta_int theta_int = theta - theta_offset + setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo variable nx = dimsize(strip, 0) variable ix @@ -336,6 +337,7 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot if (check) duplicate /o dist, check_dist duplicate /o dist_smoo, check_smoo + setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo endif end @@ -1861,7 +1863,7 @@ function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_p make /n=1 /d /free d_polar, d_azi variable n_alpha = round(alpha_hi - alpha_lo) + 1 make /n=(n_alpha) /d /free analyser - setscale /i x alpha_lo, alpha_hi, "deg", analyser + setscale /i x alpha_lo, alpha_hi, "°", analyser analyser = x convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi) @@ -2586,8 +2588,35 @@ end /// import a hemispherical scan from theta-phi-intensity waves and display it /// -/// @warning EXPERIMENTAL -/// the interface and behaviour of this function may change +/// in the tpi format, the hemi scan data is represented +/// by a triple of flat one-dimensional waves +/// corresponding to the polar angle (theta), azimuthal angle (phi) and intensity. +/// no specific sort order is required. +/// +/// @param nickname nick name for output data +/// @arg in default mode, this will become the name of a child folder containing the output. +/// @arg in XPDplot mode, this will become a prefix of the generated data in the root folder. +/// +/// @param theta theta angles, 0 = normal emission. +/// +/// @param phi phi angles, 0 = azimuthal origin. size = dimsize(data, 1) +/// +/// @param intensity intensity wave, see requirements above. +/// +/// @param npolar number of polar angles, determines polar and azimuthal step size. +/// default = 91 (1 degree steps) +/// +/// @param folding rotational averaging. +/// example: 3 = average to 3-fold symmetry. +/// default = 1. +/// +/// @param nograph display a new graph window? +/// @arg 0 (default) display a new polar graph +/// @arg 1 don't display a new graph +/// +/// @param xpdplot XPDplot compatibility +/// @arg 0 (default) create waves in child folder $nickname +/// @arg 1 create waves in root folder (compatible with XPDplot) /// function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nograph, xpdplot]) string nickname @@ -2622,7 +2651,43 @@ function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nogr fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding endfor - display_hemi_scan(nickname) + if (nograph==0) + display_hemi_scan(nickname) + endif +end + +/// trim a hemispherical scan at grazing angle +/// +/// the function recalaculates the values wave from totals and weights +/// but sets elements above a given polar angle to nan. +/// +/// @param nickname name of the scan dataset. +/// can be empty if no prefix is used. +/// the dataset must be in the current datafolder. +/// +/// @param theta_max highest polar angle to keep (0...90 degrees). +/// +function trim_hemi_scan(nickname, theta_max) + string nickname + variable theta_max + + if (strlen(nickname)) + string s_prefix = nickname + "_" + string s_int = s_prefix + "i" + else + s_prefix = "" + s_int = "values" + endif + string s_totals = s_prefix + "tot" + string s_weights = s_prefix + "wt" + string s_polar = s_prefix + "pol" + + wave w_polar = $s_polar + wave w_values = $s_int + wave w_totals = $s_totals + wave w_weights = $s_weights + + w_values = w_polar <= theta_max ? w_totals / w_weights : nan end /// extract a polar cut from a hemispherical scan. @@ -2772,7 +2837,7 @@ function /wave hemi_azi_cut(nickname, pol) make /n=(nsel) /o $s_cut wave w_cut = $s_cut w_cut = w_values[sel] - setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "deg", w_cut + setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "°", w_cut return w_cut else return $"" diff --git a/pearl/pearl-anglescan-tracker.ipf b/pearl/pearl-anglescan-tracker.ipf index 8efa077..ecc3df1 100644 --- a/pearl/pearl-anglescan-tracker.ipf +++ b/pearl/pearl-anglescan-tracker.ipf @@ -436,7 +436,7 @@ static function setup_detector() setdatafolder $(package_path) make /n=31 /o detector_angle, detector_pol, detector_az, detector_rad - setscale /i x -30, 30, "deg", detector_angle, detector_pol, detector_az, detector_rad + setscale /i x -30, 30, "°", detector_angle, detector_pol, detector_az, detector_rad detector_angle = x setdatafolder saveDF @@ -573,7 +573,7 @@ static function update_detector(theta, tilt, phi, range) //m_phi *= -1 // checked 140702 wave detector_angle, detector_pol, detector_az, detector_rad - setscale /i x -range/2, +range/2, "deg", detector_angle + setscale /i x -range/2, +range/2, "°", detector_angle detector_angle = x convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, detector_angle, detector_pol, detector_az) diff --git a/pearl/pearl-area-display.ipf b/pearl/pearl-area-display.ipf index 8be128e..0d05cf1 100644 --- a/pearl/pearl-area-display.ipf +++ b/pearl/pearl-area-display.ipf @@ -196,6 +196,7 @@ function /s ad_display_profiles(image, [filter]) view_filter_options = "" variable /g view_filter_smoothing_x = 1 variable /g view_filter_smoothing_y = 1 + variable /g view_cursor_mode = 0 string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string graphtitle = dfname + NameOfWave(image) + " Profiles" string /g prof_graphname = graphname_from_dfref(imagedf, "prof_") @@ -348,15 +349,88 @@ function ad_update_profiles(image) return 0 end +/// switch cursors on a profiles graph +/// +/// the standard cursors allow to select the profiles to display in the profiles panes. +/// additional cursors are shown in the profiles panes. +/// +/// in the background selection mode, additional cursors allow the user to select +/// the limits of the background and peak integration regions. +/// the meaning of the cursors depends on the particular processing function. +/// +/// @param mode cursor mode. +/// @arg 0 (default) standard profile selection. cursors C-F on profile panes. +/// @arg 1 background selection. cursors A-F on image. +/// +/// @param image image displayed in the graph. +/// this is the original image, not the one in the view data folder. +/// +function ad_profiles_cursor_mode(image, mode) + wave image + variable mode + + dfref savedf = GetDataFolderDFR() + wave view_image = get_view_image(image) + dfref viewdf = GetWavesDataFolderDFR(view_image) + svar /sdfr=viewdf graphname = prof_graphname + nvar /sdfr=viewdf cursor_mode = view_cursor_mode + wave /sdfr=viewdf xprofiles, yprofiles + + variable dx = DimSize(view_image, 0) + variable dy = DimSize(view_image, 1) + switch(mode) + case 1: // background selection + Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 A view_image 0, 0 + Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1 + Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 C view_image round(0.2 * dx) -1, 0 + Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 D view_image round(0.8 * dx) -1, 0 + Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 E view_image round(0.4 * dx) -1, 0 + Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 F view_image round(0.6 * dx) -1, 0 + + ShowInfo /w=$graphname /CP=0 + cursor_mode = mode + break + default: + Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A view_image 0,0 + Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1 + variable pcurs + pcurs = floor(DimSize(xprofiles, 0) / 3) + Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs + pcurs = floor(DimSize(xprofiles, 0) * 2 / 3) + Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs + pcurs = floor(DimSize(yprofiles, 0) / 3) + Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs + pcurs = floor(DimSize(yprofiles, 0) * 2 / 3) + Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs + ShowInfo /w=$graphname /CP=0 + cursor_mode = 0 + endswitch + + setdatafolder savedf + return 0 +end + /// move a cursor to the specified position in a profiles graph. +/// +/// this function can only set cursors in the image part of the profiles graph. +/// +/// @param image image displayed in the graph. +/// this is the original image, not the one in the view data folder. +/// @param cursorname name of the cursor, e.g. "A" or "B". +/// other cursors are allowed but need to be activated separately. +/// @param xa x-coordinate to move the cursor to. +/// the position is coerced to the image scale. +/-inf is allowed. +/// @param ya y-coordinate to move the cursor to. +/// the position is coerced to the image scale. +/-inf is allowed. +/// @param pscale scaling of the position argument +/// @arg 0 (default) wave scaling +/// @arg 1 point scaling +/// function ad_profiles_set_cursor(image, cursorname, xa, ya, [pscale]) - wave image // image displayed in the graph. this is the original image, not the one in the view data folder. - string cursorname // name of the cursor. must be "A" or "B". - variable xa, ya // position to move the cursor to. - // the position is coerced to the image scale. +/-inf is allowed. - variable pscale // scaling of the position argument - // 0 (default) = wave scaling - // 1 = point scaling + wave image + string cursorname + variable xa, ya + variable pscale if (ParamIsDefault(pscale)) pscale = 0 diff --git a/pearl/pearl-area-import.ipf b/pearl/pearl-area-import.ipf index 18dae4c..a5eb16e 100644 --- a/pearl/pearl-area-import.ipf +++ b/pearl/pearl-area-import.ipf @@ -1667,12 +1667,12 @@ function adh5_scale_scienta(data) case 1: // Angular45 ALow = -45/2 AHigh = +45/2 - AUnit = "deg" + AUnit = "°" break case 2: // Angular60 ALow = -60/2 AHigh = +60/2 - AUnit = "deg" + AUnit = "°" break endswitch endif diff --git a/pearl/pearl-data-explorer.ipf b/pearl/pearl-data-explorer.ipf index 755d863..4c943b9 100644 --- a/pearl/pearl-data-explorer.ipf +++ b/pearl/pearl-data-explorer.ipf @@ -1090,6 +1090,7 @@ static function /df load_pshell_file(filename, [options]) string reduction_params = pref_params if (prompt_func_params(reduction_func, reduction_params) == 0) pref_params = reduction_params + print reduction_func, reduction_params psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params) svar s_filepath loaded_filename = s_filepath @@ -1141,6 +1142,7 @@ static function /df load_hdf_file(filename, [options]) string reduction_params = pref_params if (prompt_func_params(reduction_func, reduction_params) == 0) pref_params = reduction_params + print reduction_func, reduction_params loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params) endif break diff --git a/pearl/pearl-elog.ipf b/pearl/pearl-elog.ipf index 37c1373..e44890e 100644 --- a/pearl/pearl-elog.ipf +++ b/pearl/pearl-elog.ipf @@ -426,6 +426,13 @@ function elog_create_logbook(name, [template]) dfref df_volatile_root = get_elog_df("", kdfVolatile) dfref df_volatile_parent = df_volatile_root:logbooks + setdatafolder df_persistent_parent + if (CheckName(name, 11) != 0) + setdatafolder savedf + Abort "invalid logbook name" + return -1 + endif + if (strlen(template) > 0) dfref df_template = get_elog_df(template, kdfTemplates) dfref df_existing = get_elog_df(name, kdfPersistent) @@ -1380,13 +1387,14 @@ static function update_attach_items(logbook) FindValue /text=s /txop=4 /z attach_list if (v_value < 0) k = DimSize(attach_list, 0) - InsertPoints /M=0 k, 1, attach_list, attach_sel - attach_list[i][kAttachColSel] = "" - attach_list[i][kAttachColTitle] = "" + Redimension /n=(k+1,3) attach_list, attach_sel + //InsertPoints /M=0 k, 1, attach_list, attach_sel + attach_list[k][kAttachColSel] = "" + attach_list[k][kAttachColTitle] = "" attach_list[k][kAttachColName] = s - attach_sel[i][kAttachColSel] = 32 - attach_sel[i][kAttachColTitle] = 0 - attach_sel[i][kAttachColName] = 0 + attach_sel[k][kAttachColSel] = 32 + attach_sel[k][kAttachColTitle] = 0 + attach_sel[k][kAttachColName] = 0 endif endfor diff --git a/pearl/pearl-pshell-import.ipf b/pearl/pearl-pshell-import.ipf index 585f5cc..3797303 100644 --- a/pearl/pearl-pshell-import.ipf +++ b/pearl/pearl-pshell-import.ipf @@ -1,7 +1,7 @@ #pragma rtGlobals=3 // Use modern global access method and strict wave access. #pragma IgorVersion = 6.36 #pragma ModuleName = PearlPShellImport -#pragma version = 1.02 +#pragma version = 1.03 #include #include "pearl-gui-tools" #include "pearl-area-import" @@ -309,6 +309,15 @@ function /s psh5_load_preview(ANickName, APathName, AFileName, [load_data, load_ ig = 0 endif sg = StringFromList(ig, scanpaths) + + if (load_attr) + setdatafolder fileDF + newdatafolder /o/s attr + killwaves /a/z + psh5_load_scan_attrs(fileID, sg) + endif + + setdatafolder fileDF dataname = psh5_load_scan_preview(fileID, sg, set_scale=load_attr, pref_datasets=pref_datasets) wave /z data = $dataname @@ -320,13 +329,6 @@ function /s psh5_load_preview(ANickName, APathName, AFileName, [load_data, load_ print "no data found in file " + AFileName endif - if (load_attr) - setdatafolder saveDF - newdatafolder /o/s attr - killwaves /a/z - psh5_load_scan_attrs(fileID, sg) - setdatafolder :: - endif else print "no scans found in file " + AFileName endif @@ -346,6 +348,7 @@ end /// /// data is loaded into the current data folder. /// attribute datasets are loaded into sub-folder `attr`. +/// region datasets are loaded into region sub-folders. /// existing data, if present, is overwritten. /// /// @param fileID ID of open HDF5 file from psh5_open_file(). @@ -382,13 +385,14 @@ function /s psh5_load_scan_complete(fileID, scanpath, [load_data, load_attr]) string wavenames string attrnames psh5_load_scan_meta(fileID, scanpath) - if (load_data) - wavenames = psh5_load_scan_data(fileID, scanpath) - endif if (load_attr) newdatafolder /s /o attr attrnames = psh5_load_scan_attrs(fileID, scanpath) endif + if (load_data) + setdatafolder dataDF + wavenames = psh5_load_scan_data(fileID, scanpath) + endif if (load_data && load_attr) setdatafolder dataDF ps_scale_datasets() @@ -439,18 +443,72 @@ end /// /// @return semicolon-separated list of dataset paths. /// -function /s psh5_list_scan_datasets(fileID, scanpath) +/// @version since version 1.03 this function returns paths relative to scanpath. +/// +function /s psh5_list_scan_datasets(fileID, scanpath, [include_regions]) + variable fileID + string scanpath + variable include_regions + + if (ParamIsDefault(include_regions)) + include_regions = 0 + endif + string result + + HDF5ListGroup /TYPE=2 /Z fileID, scanpath + result = S_HDF5ListGroup + + if (include_regions) + HDF5ListGroup /R /TYPE=2 /Z fileID, scanpath + variable n = ItemsInList(S_HDF5ListGroup) + variable i + string ds + string region_datasets + for (i = 0; i < n; i += 1) + ds = StringFromList(i, S_HDF5ListGroup) + if (StringMatch(ds, "region*/*")) + //region_datasets = psh5_list_scan_datasets(fileID, ReplaceString("//", scanpath + "/" + region, "/"), include_regions=0) + result = AddListItem(ds, result, ";", inf) + endif + endfor + endif + + return result +end + +/// list regions of a PShell scan group. +/// +/// the function returns a list of all region groups of the selected scan. +/// +/// @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". +/// +/// @return semicolon-separated list of datagroup paths. +/// +function /s psh5_list_scan_regions(fileID, scanpath) variable fileID string scanpath - HDF5ListGroup /F /TYPE=2 /Z fileID, scanpath + HDF5ListGroup /TYPE=1 /Z fileID, scanpath + variable n = ItemsInList(S_HDF5ListGroup) + variable i + string result = "" + string s + for (i = 0; i < n; i += 1) + s = StringFromList(i, S_HDF5ListGroup) + if (StringMatch(s, "region*")) + result = AddListItem(s, result, ";", inf) + endif + endfor - return S_HDF5ListGroup + return result end /// load all datasets of a PShell scan group. /// /// data is loaded into the current data folder. +/// region datasets are loaded into the respective region sub-folders. /// /// this function does not scale the datasets. /// call ps_scale_datasets() separately. @@ -464,22 +522,18 @@ end function /s psh5_load_scan_data(fileID, scanpath) variable fileID string scanpath + + string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1) + variable nds = ItemsInList(datasets) + variable ids + string sds + string sw string wavenames = "" - - HDF5ListGroup /F /TYPE=2 /Z fileID, scanpath - - if (!v_flag) - variable ids - variable nds = ItemsInList(S_HDF5ListGroup, ";") - string sds - string sw - - for (ids = 0; ids < nds; ids += 1) - sds = StringFromList(ids, S_HDF5ListGroup, ";") - sw = psh5_load_dataset(fileID, "", sds, set_scale=0) - wavenames = AddListItem(sw, wavenames, ";", inf) - endfor - endif + for (ids = 0; ids < nds; ids += 1) + sds = StringFromList(ids, datasets) + sw = psh5_load_dataset(fileID, scanpath, sds, set_scale=0) + wavenames = AddListItem(sw, wavenames, ";", inf) + endfor return wavenames end @@ -617,12 +671,18 @@ end /// - wave scaling is set if the necessary scan attributes have been loaded and the `set_scale` option is selected (default). /// the attributes must be loaded by psh5_load_scan_meta() and psh5_load_scan_attrs() (attr_sets=2). /// +/// the dataset is loaded into the current data folder unless datasetname contains a region specifier. +/// in the latter case, the dataset is loaded into sub-folder with the name of the region. +/// the function returns from the original data folder. +/// /// @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". /// -/// @param dataset name of the dataset. +/// @param datasetname name of the dataset. /// the name of the loaded wave is a cleaned up version of the dataset name. +/// the name can include the region name as a relative path, e.g. "region1/ScientaSpectrum". +/// in this case, the dataset is loaded into a sub-folder named "region1". /// /// @param set_scale by default, the function tries to set the wave scaling if the attributes have been loaded. /// if multiple datasets are loaded from a file, @@ -632,6 +692,8 @@ end /// /// @return name of loaded wave if successful. empty string otherwise. /// +/// @version this function supports regions as of version 1.03. +/// function /s psh5_load_dataset(fileID, scanpath, datasetname, [set_scale]) variable fileID string scanpath @@ -642,10 +704,24 @@ function /s psh5_load_dataset(fileID, scanpath, datasetname, [set_scale]) set_scale = 1 endif + dfref base_df = GetDataFolderDFR() + string datasetpath datasetpath = scanpath + "/" + datasetname datasetpath = ReplaceString("//", datasetpath, "/") + string regionname + string regionpath + if (ItemsInList(datasetname, "/") >= 2) + regionname = StringFromList(0, datasetname, "/") + regionpath = ReplaceString("//", scanpath + "/" + regionname, "/") + datasetname = RemoveListItem(0, datasetname, "/") + NewDataFolder /o/s $regionname + else + regionname = "" + regionpath = scanpath + endif + STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf. InitHDF5DataInfo(di) variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di) @@ -659,12 +735,12 @@ function /s psh5_load_dataset(fileID, scanpath, datasetname, [set_scale]) HDF5LoadData /O /Q /Z fileID, datasetpath dataname = StringFromList(0, S_waveNames) else - dataname = psh5_load_dataset_slabs(fileID, scanpath, datasetname) + dataname = psh5_load_dataset_slabs(fileID, regionpath, datasetname) endif wave /z data = $dataname if (waveexists(data)) - psh5_load_dataset_meta(fileID, scanpath, datasetname, data) + psh5_load_dataset_meta(fileID, regionpath, datasetname, data) ps_set_dimlabels(data) if (set_scale) ps_scale_dataset(data) @@ -673,19 +749,22 @@ function /s psh5_load_dataset(fileID, scanpath, datasetname, [set_scale]) dataname = "" endif + setdatafolder base_df return dataname end /// select the preferred dataset from a list of available datasets. /// /// @param file_datasets semicolon-separated list of datasets that are available in the file. +/// the items may include a path separated by slashes "/". +/// only the last component of the path is checked. /// /// @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 file dataset is selected. /// -/// @return name of selected dataset. +/// @return selected dataset. /// static function /s select_dataset(file_datasets, pref_datasets) string file_datasets @@ -695,6 +774,7 @@ static function /s select_dataset(file_datasets, pref_datasets) variable nds = ItemsInList(file_datasets) variable ids string sds = "" + string mds = "" variable np = ItemsInList(pref_datasets) variable ip string sp @@ -704,9 +784,9 @@ static function /s select_dataset(file_datasets, pref_datasets) for (ids = 0; ids < nds; ids += 1) sds = StringFromList(ids, file_datasets) index = ItemsInList(sds, "/") - 1 - sds = StringFromList(index, sds, "/") + mds = StringFromList(index, sds, "/") sp = StringFromList(ip, pref_datasets) - if (StringMatch(sds, sp)) + if (StringMatch(mds, sp)) found = 1 break endif @@ -718,8 +798,6 @@ static function /s select_dataset(file_datasets, pref_datasets) if (!found) ids = 0 sds = StringFromList(ids, file_datasets) - index = ItemsInList(sds, "/") - 1 - sds = StringFromList(index, sds, "/") endif endif @@ -766,7 +844,7 @@ function /s psh5_load_scan_preview(fileID, scanpath, [set_scale, pref_datasets]) dfref saveDF = GetDataFolderDFR() dfref dataDF = saveDF - string datasets = psh5_list_scan_datasets(fileID, scanpath) + string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1) string datasetname = select_dataset(datasets, pref_datasets) string datasetpath datasetpath = scanpath + "/" + datasetname @@ -995,7 +1073,8 @@ end /// @param datapath path to the containing group in the HDF5 file. /// path separator is the slash "/". /// -/// @param dataset name of the dataset. +/// @param datasetname name of the dataset. +/// may include relative path. /// /// @param datawave metadata is added to the wave note of this wave. /// @@ -1364,42 +1443,92 @@ function ps_set_dimlabels2(data, name) return 0 end +/// find the scan folder +/// +/// the scan folder is the one that contains the :attr folder +/// the data and scan folders may refer to the same folder. +/// +static function /df find_scan_folder(dataDF) + dfref dataDF + + dfref attrDF = dataDF:attr + if (!DataFolderRefStatus(attrDF)) + string df = GetDataFolder(1, dataDF) + ":" + dfref scanDF = $df + else + dfref scanDF = dataDF + endif + return scanDF +end + +/// find the attributes data folder +/// +/// this is the :attr folder. +/// +static function /df find_attr_folder(dataDF) + dfref dataDF + + dfref attrDF = dataDF:attr + if (!DataFolderRefStatus(attrDF)) + string df = GetDataFolder(1, dataDF) + ":" + dfref scanDF = $df + dfref attrDF = scanDF:attr + endif + return attrDF +end + /// set the dimension scales of loaded PShell Scienta datasets according to attributes. /// -/// the datasets must be in the current data folder. -/// all datasets listed in the ScanReadables waves are scaled -/// according to the attribute waves in the :attr folder. +/// datasets listed in the ScanReadables waves are scaled +/// according to the attribute waves in the data, scan, and attributes folders, +/// whichever is found first. /// -/// the dimension labels of the dataset waves must be set correctly, e.g. by ps_set_dimlabels(). +/// the current datafolder must contain the ScanReadables wave and the :attr folder. +/// the ScanReadables text wave contains names of the waves to scale. +/// wave names can include a relative path to a sub-folder. the path separator is "/". +/// +/// the dimension labels of the dataset waves must have been set correctly, e.g. by ps_set_dimlabels(). /// this is implicitly done by the high-level load functions. /// +/// @version this function supports regions from version 1.03. +/// check that you're in the correct data folder! +/// function ps_scale_datasets() - dfref dataDF = GetDataFolderDFR() - dfref attrDF = :attr + dfref scanDF = GetDataFolderDFR() + dfref attrDF = find_attr_folder(scanDF) make /n=3 /free lo, hi make /n=3 /t /free ax, un - ps_detect_scale(ax, lo, hi, un) - - wave /t /z /SDFR=dataDF ScanReadables + wave /t /z /SDFR=scanDF ScanReadables if (WaveExists(ScanReadables)) variable isr variable nsr = numpnts(ScanReadables) string ssr + string sdf for (isr = 0; isr < nsr; isr += 1) - wave /z /SDFR=dataDF wsr = $ScanReadables[isr] + setdatafolder scanDF + ssr = ScanReadables[isr] + if (ItemsInList(ssr, "/") >= 2) + sdf = StringFromList(0, ssr, "/") + ssr = RemoveListItem(0, ssr, "/") + setdatafolder $sdf + endif + wave /z wsr=$ssr if (WaveExists(wsr)) + ps_detect_scale(ax, lo, hi, un) ps_scale_dataset_2(wsr, ax, lo, hi, un) endif endfor endif + setdatafolder scanDF end /// set the dimension scales of a loaded PShell Scienta dataset according to attributes. /// -/// the attributes must be in the child folder `:attr` next to the dataset. +/// the current datafolder must contain the :attr folder. +/// the data wave can be in the current folder or a sub-folder. /// -/// the dimension labels of the dataset waves must be set correctly, cf. ps_set_dimlabels(). +/// the dimension labels of the dataset waves must have been set correctly, e.g. by ps_set_dimlabels(). /// this is implicitly done by the high-level load functions. /// /// the function is useful if a single dataset is loaded and scaled. @@ -1408,27 +1537,48 @@ end /// @param data data wave to be scaled. /// dimension labels (index -1) must be set correctly, cf. ps_set_dimlabels(). /// +/// @version this function supports regions from version 1.03. +/// function ps_scale_dataset(data) wave data dfref saveDF = GetDataFolderDFR() dfref dataDF = GetWavesDataFolderDFR(data) - setdatafolder dataDF + setdatafolder dataDF make /n=3 /free lo, hi make /n=3 /t /free ax, un ps_detect_scale(ax, lo, hi, un) ps_scale_dataset_2(data, ax, lo, hi, un) - setdatafolder saveDF end +static function /wave find_scale_wave(name, dataDF, scanDF, attrDF) + string name + dfref dataDF + dfref scanDF + dfref attrDF + + wave /SDFR=dataDF /Z w = $name + if (!WaveExists(w)) + wave /SDFR=scanDF /Z w = $name + if (!WaveExists(w)) + wave /SDFR=attrDF /Z w = $name + endif + endif + return w +end + /// detect the dimension scales from attributes. /// -/// the function checks the current data folder and the sub-folder `:attr` for scan parameters. +/// the function checks the data , scan and attributes folders for scan parameters. /// the results are written to the provided waves. /// the function is normally called by ps_scale_datasets() but can also be used independently. /// +/// the current datafolder must be the data or the scan folder. +/// the data folder contains the waves that are to be scaled. +/// the scan folder contains the scan positions and the :attr folder. +/// /// the provided waves are redimensioned by the function, and dimension labels are set. /// the scale parameters can then be extracted by keyword, e.g., /// @arg `lo[%%energy]` analyser energy dimension. @@ -1436,13 +1586,14 @@ end /// @arg `lo[%%scan]` scan dimension. /// @arg `lo[%%data]` data dimension. /// -/// the function tries to read the following waves, -/// and may fall back to more or less reasonable default values if they are not found. -/// @arg `:attr:LensMode` -/// @arg `:attr:ScientaChannelBegin` -/// @arg `:attr:ScientaChannelEnd` -/// @arg `:attr:ScientaSliceBegin` -/// @arg `:attr:ScientaSliceEnd` +/// the function tries to read the following waves, in the data, scan, and attributes folders, +/// where the first folder in the list takes precedence. +/// it may fall back to more or less reasonable default values if no data is not found. +/// @arg `LensMode` +/// @arg `ScientaChannelBegin` +/// @arg `ScientaChannelEnd` +/// @arg `ScientaSliceBegin` +/// @arg `ScientaSliceEnd` /// @arg `ScanWritables` /// @arg wave referenced by `ScanWritables[0]` /// @@ -1456,6 +1607,9 @@ end /// /// @return the function results are written to the lo, hi, un, and ax waves. /// +/// @version this function supports regions from version 1.03. +/// check that you're in the correct data folder! +/// function ps_detect_scale(ax, lo, hi, un) wave /t ax wave lo @@ -1463,7 +1617,8 @@ function ps_detect_scale(ax, lo, hi, un) wave /t un dfref dataDF = GetDataFolderDFR() - dfref attrDF = :attr + dfref scanDF = find_scan_folder(dataDF) + dfref attrDF = find_attr_folder(dataDF) redimension /n=4 lo, hi, un, ax setdimlabel 0, 0, $kEnergyDimLabel, lo, hi, un, ax @@ -1493,10 +1648,10 @@ function ps_detect_scale(ax, lo, hi, un) ax[%$kDataDimLabel] = "value" wave /SDFR=attrDF /T /Z LensMode - wave /SDFR=attrDF /Z ChannelBegin = ScientaChannelBegin - wave /SDFR=attrDF /Z ChannelEnd = ScientaChannelEnd - wave /SDFR=attrDF /Z SliceBegin = ScientaSliceBegin - wave /SDFR=attrDF /Z SliceEnd = ScientaSliceEnd + wave /Z ChannelBegin = find_scale_wave("ScientaChannelBegin", dataDF, scanDF, attrDF) + wave /Z ChannelEnd = find_scale_wave("ScientaChannelEnd", dataDF, scanDF, attrDF) + wave /Z SliceBegin = find_scale_wave("ScientaSliceBegin", dataDF, scanDF, attrDF) + wave /Z SliceEnd = find_scale_wave("ScientaSliceEnd", dataDF, scanDF, attrDF) // lens mode can give more detail if (waveexists(LensMode) && (numpnts(LensMode) >= 1)) @@ -1504,13 +1659,13 @@ function ps_detect_scale(ax, lo, hi, un) case "Angular45": lo[%$kAngleDimLabel] = -45/2 hi[%$kAngleDimLabel] = +45/2 - un[%$kAngleDimLabel] = "deg" + un[%$kAngleDimLabel] = "°" ax[%$kAngleDimLabel] = "angle" break case "Angular60": lo[%$kAngleDimLabel] = -60/2 hi[%$kAngleDimLabel] = +60/2 - un[%$kAngleDimLabel] = "deg" + un[%$kAngleDimLabel] = "°" ax[%$kAngleDimLabel] = "angle" break case "Transmission": @@ -1529,9 +1684,10 @@ function ps_detect_scale(ax, lo, hi, un) lo[%$kAngleDimLabel] = SliceBegin[0] hi[%$kAngleDimLabel] = SliceEnd[0] endif - wave /z /t /SDFR=dataDF ScanWritables + + wave /z /t /SDFR=scanDF ScanWritables if (WaveExists(ScanWritables)) - wave /z /SDFR=dataDF scanner = $ScanWritables[0] + wave /z /SDFR=scanDF scanner = $ScanWritables[0] if (!WaveExists(scanner)) wave /z /SDFR=attrDF scanner = $ScanWritables[0] endif @@ -1553,6 +1709,7 @@ function ps_detect_scale(ax, lo, hi, un) case "RefocusZTrans": case "ExitSlitY": un[%$kScanDimLabel] = "mm" + break case "ExitSlit": un[%$kScanDimLabel] = "µm" break @@ -1560,6 +1717,7 @@ function ps_detect_scale(ax, lo, hi, un) case "ManipulatorTilt": case "ManipulatorPhi": un[%$kScanDimLabel] = "°" + break case "FocusXRot": case "FocusYRot": case "FocusZRot": @@ -1567,6 +1725,7 @@ function ps_detect_scale(ax, lo, hi, un) case "RefocusYRot": case "RefocusZRot": un[%$kScanDimLabel] = "mrad" + break endswitch endif endif @@ -1603,6 +1762,8 @@ end /// @param un unit labels. /// the unit labels are applied using the SetScale operation. /// +/// @version this function supports regions from version 1.03. +/// function ps_scale_dataset_2(data, ax, lo, hi, un) wave data wave /t ax @@ -1746,8 +1907,11 @@ function /s psh5_load_reduced(ANickName, APathName, AFileName, reduction_func, r HDF5LoadData /O /Q /Z fileID, positionerpath endif endif + setdatafolder dataDF - wavenames = psh5_load_dataset_reduced(fileID, scanpath, "ScientaImage", reduction_func, reduction_param, progress=progress) + string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1) + string dataset = select_dataset(datasets, "ScientaImage") + wavenames = psh5_load_dataset_reduced(fileID, scanpath, dataset, reduction_func, reduction_param, progress=progress) psh5_close_file(fileID) endif @@ -1783,7 +1947,10 @@ end /// /// @param scanpath path to scan group in the HDF5 file. /// -/// @param dataset name of the dataset. +/// @param datasetname name of the dataset. +/// the name of the loaded wave is a cleaned up version of the dataset name. +/// the name can include the region name as a relative path, e.g. "region1/ScientaSpectrum". +/// in this case, the dataset is loaded into a sub-folder named "region1". /// /// @param reduction_func custom reduction function /// (any user-defined function which has the same parameters as adh5_default_reduction()). @@ -1804,6 +1971,8 @@ end /// empty string if an error occurred. /// error messages are printed to the history. /// +/// @version this function supports regions as of version 1.03. +/// function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_func, reduction_param, [progress, nthreads]) variable fileID string scanpath @@ -1820,6 +1989,7 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f nthreads = -1 endif + dfref base_df = GetDataFolderDFR() variable result = 0 string datasetpath string datawavename @@ -1829,6 +1999,18 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f datasetpath = ReplaceString("//", datasetpath, "/") datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/") + string regionname + string regionpath + if (ItemsInList(datasetname, "/") >= 2) + regionname = StringFromList(0, datasetname, "/") + regionpath = ReplaceString("//", scanpath + "/" + regionname, "/") + datasetname = RemoveListItem(0, datasetname, "/") + NewDataFolder /o/s $regionname + else + regionname = "" + regionpath = scanpath + endif + STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf. InitHDF5DataInfo(di) variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di) @@ -2035,6 +2217,7 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f kill_progress_panel() endif + setdatafolder base_df return wavenames end diff --git a/pearl/preferences/pearl_elog/preferences.pxp b/pearl/preferences/pearl_elog/preferences.pxp index 8909c97853ed4066bc19a5f806ac6021a3464347..9d82a6db90f0675dd5e9d21e6b10ed44eaea143f 100644 GIT binary patch literal 12204 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