new features: data reduction, angle scan panel
- new data reduction interface for more efficient multi-peak fitting. the new interface breaks compatibility with pre-2.0 data reduction functions. user-defined functions must be adapted to the new interface. - new angle scan processing panel for interactive data analysis.
This commit is contained in:
@ -1,12 +1,11 @@
|
||||
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
|
||||
#pragma IgorVersion = 6.36
|
||||
#pragma ModuleName = PearlPShellImport
|
||||
#pragma version = 1.03
|
||||
#include <HDF5 Browser>
|
||||
#include "pearl-gui-tools"
|
||||
#include "pearl-area-import"
|
||||
|
||||
// copyright (c) 2013-16 Paul Scherrer Institut
|
||||
// copyright (c) 2013-18 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.
|
||||
@ -47,6 +46,14 @@
|
||||
/// - psh5_list_scan_datasets()
|
||||
/// - psh5_load_scan_meta()
|
||||
/// - psh5_load_scan_attrs()
|
||||
///
|
||||
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
|
||||
///
|
||||
/// @copyright 2013-18 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
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
/// @namespace PearlPShellImport
|
||||
/// @brief import data from PShell
|
||||
@ -1728,6 +1735,12 @@ end
|
||||
/// @arg `lo[%%scan]` scan dimension.
|
||||
/// @arg `lo[%%data]` data dimension.
|
||||
///
|
||||
/// if the data dimension labels and units are at their defaults ("value" and "arb.", respectively),
|
||||
/// the function tries to read them from the existing wave note ("AxisLabelD" and "AxisUnitD"),
|
||||
/// or based on the wave name if the name is one of the known measurement variables:
|
||||
/// "ScientaImage", "ImageAngleDistribution", "ScientaAngleDistribution", "ScientaSpectrum", "ImageEnergyDistribution", "ScientaEnergyDistribution",
|
||||
/// "SampleCurrent", "RefCurrent", "AuxCurrent", "MachineCurrent".
|
||||
///
|
||||
/// @param data data wave to be scaled.
|
||||
/// dimension labels (index -1) must be set to match the limit waves.
|
||||
///
|
||||
@ -1754,28 +1767,45 @@ function ps_scale_dataset_2(data, ax, lo, hi, un)
|
||||
wave hi
|
||||
wave /t un
|
||||
|
||||
string snote = note(data)
|
||||
string sdim
|
||||
sdim = GetDimLabel(data, 0, -1)
|
||||
if (strlen(sdim))
|
||||
setscale /i x lo[%$sdim], hi[%$sdim], un[%$sdim], data
|
||||
Note data, "AxisLabelX=" + ax[%$sdim]
|
||||
snote = ReplaceStringByKey("AxisLabelX", snote, ax[%$sdim], "=", "\r")
|
||||
endif
|
||||
|
||||
sdim = GetDimLabel(data, 1, -1)
|
||||
if (strlen(sdim))
|
||||
setscale /i y lo[%$sdim], hi[%$sdim], un[%$sdim], data
|
||||
Note data, "AxisLabelY=" + ax[%$sdim]
|
||||
snote = ReplaceStringByKey("AxisLabelY", snote, ax[%$sdim], "=", "\r")
|
||||
endif
|
||||
|
||||
sdim = GetDimLabel(data, 2, -1)
|
||||
if (strlen(sdim))
|
||||
setscale /i z lo[%$sdim], hi[%$sdim], un[%$sdim], data
|
||||
Note data, "AxisLabelZ=" + ax[%$sdim]
|
||||
snote = ReplaceStringByKey("AxisLabelZ", snote, ax[%$sdim], "=", "\r")
|
||||
endif
|
||||
|
||||
|
||||
string data_unit = un[%$kDataDimLabel]
|
||||
string data_label = ax[%$kDataDimLabel]
|
||||
if (cmpstr(data_unit, "arb.") == 0)
|
||||
string s
|
||||
variable def = (cmpstr(data_unit, "arb.") == 0) && (cmpstr(data_label, "value") == 0)
|
||||
|
||||
if (def)
|
||||
s = StringByKey("AxisLabelD", snote, "=", "\r")
|
||||
if (strlen(s) > 0)
|
||||
data_label = s
|
||||
def = 0
|
||||
endif
|
||||
s = StringByKey("AxisUnitD", snote, "=", "\r")
|
||||
if (strlen(s) > 0)
|
||||
data_unit = s
|
||||
def = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
if (def)
|
||||
strswitch(NameOfWave(data))
|
||||
case "ScientaImage":
|
||||
case "ImageAngleDistribution":
|
||||
@ -1786,28 +1816,35 @@ function ps_scale_dataset_2(data, ax, lo, hi, un)
|
||||
data *= kDetectorSensitivity
|
||||
data_unit = "counts"
|
||||
data_label = "intensity"
|
||||
def = 0
|
||||
break
|
||||
case "SampleCurrent":
|
||||
case "RefCurrent":
|
||||
case "AuxCurrent":
|
||||
data_unit = "A"
|
||||
data_label = "current"
|
||||
def = 0
|
||||
break
|
||||
case "MachineCurrent":
|
||||
data_unit = "mA"
|
||||
data_label = "current"
|
||||
def = 0
|
||||
break
|
||||
endswitch
|
||||
endif
|
||||
|
||||
setscale d 0, 0, data_unit, data
|
||||
Note data, "AxisLabelD=" + data_label
|
||||
Note data, "Dataset=" + NameOfWave(data)
|
||||
snote = ReplaceStringByKey("AxisLabelD", snote, data_label, "=", "\r")
|
||||
snote = ReplaceStringByKey("AxisUnitD", snote, data_unit, "=", "\r")
|
||||
snote = ReplaceStringByKey("Dataset", snote, NameOfWave(data), "=", "\r")
|
||||
note /k data, snote
|
||||
end
|
||||
|
||||
/// load and reduce the ScientaImage dataset of the first scan of a PShell data file.
|
||||
///
|
||||
/// the resulting dataset is reduced in one image dimension by a user-defined reduction function,
|
||||
/// e.g. by region-of-interest integration, curve fitting, etc.
|
||||
/// cf. @ref adh5_default_reduction for further details.
|
||||
///
|
||||
/// the function loads the dataset image by image using the hyperslab option
|
||||
/// and applies a custom reduction function to each image.
|
||||
@ -1817,14 +1854,21 @@ end
|
||||
/// if the data is from the electron analyser driver and some special attributes are included,
|
||||
/// the function will set the scales of the image dimensions.
|
||||
///
|
||||
/// by default, the reduction function is called in separate threads to reduce the total loading time.
|
||||
/// (see the global variable psh5_perf_secs which reports the total run time of the function.)
|
||||
/// the effect varies depending on the balance between file loading (image size)
|
||||
/// and data processing (complexity of the reduction function).
|
||||
/// for debugging the reduction function, multi-threading can be disabled.
|
||||
///
|
||||
/// @param ANickName destination folder name (top level under root).
|
||||
///
|
||||
/// @param APathName igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed.
|
||||
///
|
||||
/// @param AFileName if empty a dialog box shows up.
|
||||
///
|
||||
/// @param reduction_func custom reduction function
|
||||
/// (any user-defined function which has the same parameters as adh5_default_reduction())
|
||||
/// @param reduction_func custom data reduction function.
|
||||
/// this can be any user-defined function which has the same parameters as @ref adh5_default_reduction.
|
||||
/// some reduction functions are predefined in the @ref PearlScientaPreprocess module.
|
||||
///
|
||||
/// @param reduction_param parameter string for the reduction function.
|
||||
///
|
||||
@ -1832,8 +1876,13 @@ end
|
||||
/// @arg 1 (default) show progress window
|
||||
/// @arg 0 do not show progress window
|
||||
///
|
||||
/// @return semicolon-separated list of the loaded waves,
|
||||
/// `ReducedData1` and `ReducedData2` if successful.
|
||||
/// @param nthreads
|
||||
/// @arg -1 (default) use as many threads as there are processor cores (in addition to main thread).
|
||||
/// @arg 0 use main thread only (for debugging and profiling).
|
||||
/// @arg >= 1 use a fixed number of (additional) threads.
|
||||
///
|
||||
/// @return semicolon-separated list of the loaded dataset `ReducedData1`, `ReducedData2`, etc. if successful.
|
||||
/// auxiliary waves, scan positions, attributes are loaded but not listed in the string.
|
||||
/// empty string if an error occurred.
|
||||
/// error messages are printed to the history.
|
||||
///
|
||||
@ -1841,20 +1890,22 @@ end
|
||||
///
|
||||
/// @return global string s_scanpaths in new data folder contains a list of scan groups inside the file.
|
||||
///
|
||||
/// @todo load scan positions.
|
||||
///
|
||||
function /s psh5_load_reduced(ANickName, APathName, AFileName, reduction_func, reduction_param, [progress])
|
||||
function /s psh5_load_reduced(ANickName, APathName, AFileName, reduction_func, reduction_param, [progress, nthreads])
|
||||
string ANickName
|
||||
string APathName
|
||||
string AFileName
|
||||
funcref adh5_default_reduction reduction_func
|
||||
string reduction_param
|
||||
variable progress
|
||||
variable nthreads
|
||||
|
||||
if (ParamIsDefault(progress))
|
||||
progress = 1
|
||||
endif
|
||||
|
||||
if (ParamIsDefault(nthreads))
|
||||
nthreads = -1
|
||||
endif
|
||||
|
||||
dfref saveDF = GetDataFolderDFR()
|
||||
|
||||
// performance monitoring
|
||||
@ -1904,7 +1955,7 @@ function /s psh5_load_reduced(ANickName, APathName, AFileName, reduction_func, r
|
||||
setdatafolder dataDF
|
||||
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)
|
||||
wavenames = psh5_load_dataset_reduced(fileID, scanpath, dataset, reduction_func, reduction_param, progress=progress, nthreads=nthreads)
|
||||
|
||||
psh5_close_file(fileID)
|
||||
endif
|
||||
@ -1922,7 +1973,7 @@ end
|
||||
///
|
||||
/// the function loads the dataset image by image using the hyperslab option
|
||||
/// and applies a custom reduction function to each image.
|
||||
/// the results from the reduction function are written to the `ReducedData1` and `ReducedData2` waves.
|
||||
/// the results from the reduction function are written to the `ReducedData1`, `ReducedData2`, etc. waves.
|
||||
/// the raw data are discarded.
|
||||
///
|
||||
/// by default, the reduction function is called in separate threads to reduce the total loading time.
|
||||
@ -1946,8 +1997,9 @@ end
|
||||
/// the name can include the region name as a relative path, e.g. "region1/ScientaImage".
|
||||
/// 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()).
|
||||
/// @param reduction_func custom data reduction function.
|
||||
/// this can be any user-defined function which has the same parameters as @ref adh5_default_reduction.
|
||||
/// some reduction functions are predefined in the @ref PearlScientaPreprocess module.
|
||||
///
|
||||
/// @param reduction_param parameter string for the reduction function.
|
||||
///
|
||||
@ -1957,11 +2009,11 @@ end
|
||||
///
|
||||
/// @param nthreads
|
||||
/// @arg -1 (default) use as many threads as there are processor cores (in addition to main thread).
|
||||
/// @arg 0 use main thread only (e.g. for debugging the reduction function).
|
||||
/// @arg 0 use main thread only (for debugging and profiling).
|
||||
/// @arg >= 1 use a fixed number of (additional) threads.
|
||||
///
|
||||
/// @return semicolon-separated list of the loaded waves,
|
||||
/// `ReducedData1` and `ReducedData2` if successful.
|
||||
/// @return semicolon-separated list of the loaded dataset `ReducedData1`, `ReducedData2`, etc. if successful.
|
||||
/// auxiliary waves, scan positions, attributes are loaded but not listed in the string.
|
||||
/// empty string if an error occurred.
|
||||
/// error messages are printed to the history.
|
||||
///
|
||||
@ -2079,6 +2131,10 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f
|
||||
|
||||
variable iz, it, izt
|
||||
string dfname
|
||||
variable iw, nw
|
||||
string sw
|
||||
make /n=0 /free /wave result_waves
|
||||
|
||||
izt = 0
|
||||
for (iz = 0; iz < nz; iz += 1)
|
||||
for (it = 0; it < nt; it += 1)
|
||||
@ -2102,9 +2158,10 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f
|
||||
processing_folders[izt] = GetDataFolderDFR()
|
||||
make /n=1/d profile1, profile2
|
||||
wave slabdata
|
||||
variable /g func_result
|
||||
func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
|
||||
WaveClear slabdata, image, profile1, profile2
|
||||
wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
|
||||
variable /g func_result = numpnts(reduced_waves)
|
||||
adh5_get_result_waves(reduced_waves, "redw_", 0)
|
||||
WaveClear slabdata, image, reduced_waves
|
||||
setdatafolder ::
|
||||
endif
|
||||
|
||||
@ -2159,31 +2216,36 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f
|
||||
nvar rr = dfr:r_index
|
||||
nvar ss = dfr:s_index
|
||||
nvar func_result = dfr:func_result
|
||||
wave profile1 = dfr:profile1
|
||||
wave profile2 = dfr:profile2
|
||||
|
||||
if (func_result == 0)
|
||||
if (izt == 0)
|
||||
make /n=(dimsize(profile1, 0), nz, nt) /d /o ReducedData1
|
||||
make /n=(dimsize(profile2, 0), nz, nt) /d /o ReducedData2
|
||||
setdimlabel 0, -1, $getdimlabel(profile1, 0, -1), ReducedData1
|
||||
setdimlabel 0, -1, $getdimlabel(profile2, 0, -1), ReducedData2
|
||||
setdimlabel 1, -1, $kScanDimLabel, ReducedData1
|
||||
setdimlabel 1, -1, $kScanDimLabel, ReducedData2
|
||||
ps_scale_dataset(ReducedData1)
|
||||
ps_scale_dataset(ReducedData2)
|
||||
setscale /p x dimoffset(profile1, 0), dimdelta(profile1, 0), waveunits(profile1, 0), ReducedData1
|
||||
setscale /p x dimoffset(profile2, 0), dimdelta(profile2, 0), waveunits(profile2, 0), ReducedData2
|
||||
setscale d 0, 0, waveunits(profile1, -1), ReducedData1
|
||||
setscale d 0, 0, waveunits(profile2, -1), ReducedData2
|
||||
endif
|
||||
ReducedData1[][rr][ss] = profile1[p]
|
||||
ReducedData2[][rr][ss] = profile2[p]
|
||||
else
|
||||
if (func_result < 1)
|
||||
print "error during data reduction."
|
||||
result = -3
|
||||
break
|
||||
endif
|
||||
|
||||
if (numpnts(result_waves) == 0)
|
||||
redimension /n=(func_result) result_waves
|
||||
for (iw = 0; iw < func_result; iw += 1)
|
||||
sw = "redw_" + num2str(iw)
|
||||
wave profile = dfr:$sw
|
||||
sw = "ReducedData" + num2str(iw+1)
|
||||
make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
|
||||
wave data = $sw
|
||||
setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
|
||||
setdimlabel 1, -1, $kScanDimLabel, data
|
||||
note data, note(profile)
|
||||
ps_scale_dataset(data)
|
||||
setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
|
||||
setscale d 0, 0, waveunits(profile, -1), data
|
||||
result_waves[iw] = data
|
||||
endfor
|
||||
endif
|
||||
for (iw = 0; iw < func_result; iw += 1)
|
||||
sw = "redw_" + num2str(iw)
|
||||
wave profile = dfr:$sw
|
||||
wave data = result_waves[iw]
|
||||
data[][rr][ss] = profile[p]
|
||||
endfor
|
||||
endfor
|
||||
|
||||
if (nthreads > 0)
|
||||
@ -2199,14 +2261,17 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f
|
||||
endif
|
||||
|
||||
if (result == 0)
|
||||
if (nz == 1)
|
||||
redimension /n=(-1, 0, 0) ReducedData1
|
||||
redimension /n=(-1, 0, 0) ReducedData2
|
||||
elseif (nt == 1)
|
||||
redimension /n=(-1, nz, 0) ReducedData1
|
||||
redimension /n=(-1, nz, 0) ReducedData2
|
||||
endif
|
||||
wavenames = "ReducedData1;ReducedData2;"
|
||||
nw = numpnts(result_waves)
|
||||
wavenames = ""
|
||||
for (iw = 0; iw < nw; iw += 1)
|
||||
wave data = result_waves[iw]
|
||||
if (nz == 1)
|
||||
redimension /n=(-1, 0, 0) data
|
||||
elseif (nt == 1)
|
||||
redimension /n=(-1, nz, 0) data
|
||||
endif
|
||||
wavenames += nameofwave(data) + ";"
|
||||
endfor
|
||||
endif
|
||||
if (progress)
|
||||
kill_progress_panel()
|
||||
@ -2240,14 +2305,14 @@ threadsafe static function reduce_slab_worker(reduction_func)
|
||||
|
||||
// do the work
|
||||
newdatafolder /s outDF
|
||||
make /n=1/d profile1, profile2
|
||||
variable /g r_index = rr
|
||||
variable /g s_index = ss
|
||||
variable /g func_result
|
||||
func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
|
||||
wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
|
||||
variable /g func_result = numpnts(reduced_waves)
|
||||
|
||||
// send output to queue and clean up
|
||||
WaveClear slabdata, image, profile1, profile2
|
||||
adh5_get_result_waves(reduced_waves, "redw_", 0)
|
||||
WaveClear slabdata, image, reduced_waves
|
||||
ThreadGroupPutDF 0, :
|
||||
KillDataFolder dfr
|
||||
while (1)
|
||||
@ -2255,18 +2320,16 @@ threadsafe static function reduce_slab_worker(reduction_func)
|
||||
return 0
|
||||
end
|
||||
|
||||
threadsafe static function reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, reduction_param)
|
||||
threadsafe static function /wave reduce_slab_image(slabdata, image, reduction_func, reduction_param)
|
||||
wave slabdata
|
||||
wave image
|
||||
wave profile1
|
||||
wave profile2
|
||||
funcref adh5_default_reduction reduction_func
|
||||
string reduction_param
|
||||
|
||||
// the multiplication by detector sensitivity assumes that we are loading a ScientaImage.
|
||||
image = slabdata[q][p][0][0] * kDetectorSensitivity
|
||||
|
||||
return reduction_func(image, profile1, profile2, reduction_param)
|
||||
return reduction_func(image, reduction_param)
|
||||
end
|
||||
|
||||
/// load descriptive info from a PShell data file.
|
||||
|
Reference in New Issue
Block a user