updates: scaling of pshell data, matrix preview, elog panel

- elog panel supports multiple attachments
- matrix (omicron STM) data file preview in data explorer
- various improvements for the scaling of pshell data
This commit is contained in:
muntwiler_m 2017-02-02 15:31:13 +01:00
parent c8a69460bc
commit 9a65d26984
5 changed files with 1680 additions and 171 deletions

View File

@ -1,11 +1,14 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlDataExplorer
#pragma version = 1.43
#pragma version = 1.50
#include "pearl-area-import"
#include "pearl-area-profiles"
#include "pearl-area-display"
#include "pearl-pshell-import"
#if exists("MFR_OpenResultFile")
#include "pearl-matrix-import"
#endif
// copyright (c) 2013-16 Paul Scherrer Institut
//
@ -20,7 +23,10 @@
///
///
/// preview and import panel for PEARL data:
/// scienta analyser, prosilica cameras, s-scans, otf-scans
/// @arg area detector (HDF5) files from scienta analyser and prosilica cameras (if HDF5.xop is installed).
/// @arg igor text files from s-scans and otf-scans.
/// @arg pshell (HDF5) data files (if HDF5.xop is installed).
/// @arg matrix STM files (if MatrixFileReader.xop is installed).
/// @namespace PearlDataExplorer
/// @brief preview and import panel for PEARL data
@ -33,6 +39,7 @@ static strconstant package_path = "root:packages:pearl_explorer:"
static strconstant ks_filematch_adh5 = "*.h5"
static strconstant ks_filematch_pshell = "psh*.h5"
static strconstant ks_filematch_itx = "*.itx"
static strconstant ks_filematch_mtrx = "*_mtrx"
function pearl_data_explorer()
init_package()
@ -140,31 +147,64 @@ static function load_prefs()
return result
end
/// check whether a file can be imported by this module.
///
/// the file type is determined by the extension of the file name.
///
/// @return file type
/// @arg 0 not a recognized file type
/// @arg 1 PShell file (HDF5, name starts with psh_)
/// @arg 2 area detector HDF5 file
/// @arg 3 Igor text (itx) file
/// @arg 4 Matrix STM file (*_mtrx)
///
static function pearl_file_type(filename)
string filename
if (StringMatch(filename, ks_filematch_pshell))
return 1
elseif (StringMatch(filename, ks_filematch_adh5))
return 2
elseif (StringMatch(filename, ks_filematch_itx))
return 3
#if exists("MFR_OpenResultFile")
elseif (StringMatch(filename, ks_filematch_mtrx))
return 4
#endif
else
return 0
endif
end
/// read a list of PEARL files from the file system
///
/// wtFiles and wSelectedFiles in the package data folder are updated.
/// only files for which pearl_file_type() returns non-zero are listed.
///
static function update_filelist()
dfref saveDF = GetDataFolderDFR()
string hdf_files, itx_files, all_files
string all_files
wave /t wtFiles = $(package_path + "wtFiles")
wave wSelectedFiles = $(package_path + "wSelectedFiles")
variable nn
PathInfo pearl_explorer_filepath
if (v_flag == 1)
hdf_files = IndexedFile(pearl_explorer_filepath, -1, ".h5")
itx_files = IndexedFile(pearl_explorer_filepath, -1, ".itx")
all_files = hdf_files + itx_files
all_files = SortList(hdf_files + itx_files, ";", 4)
all_files = IndexedFile(pearl_explorer_filepath, -1, "????")
nn = ItemsInList(all_files)
else
all_files = ""
nn = 0
endif
redimension /n=(nn) wtFiles, wSelectedFiles
if (nn > 0)
wtFiles = StringFromList(p, all_files)
wSelectedFiles = 0
endif
make /n=(nn) /t /free wtAllFiles
wtAllFiles = StringFromList(p, all_files)
Extract /o /t wtAllFiles, wtFiles, pearl_file_type(wtAllFiles[p])
Sort /A /R wtFiles, wtFiles
redimension /n=(numpnts(wtFiles)) wSelectedFiles
wSelectedFiles = 0
setdatafolder saveDF
end
@ -216,14 +256,24 @@ static function preview_file(filename)
string filename
dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, ks_filematch_pshell))
wave /z image = preview_pshell_file(filename)
elseif (StringMatch(filename, ks_filematch_adh5))
wave /z image = preview_hdf_file(filename)
elseif (StringMatch(filename, ks_filematch_itx))
wave /z image = preview_itx_file(filename)
endif
variable ft = pearl_file_type(filename)
switch(ft)
case 1:
wave /z image = preview_pshell_file(filename)
break
case 2:
wave /z image = preview_hdf_file(filename)
break
case 3:
wave /z image = preview_itx_file(filename)
break
case 4:
wave /z image = preview_mtrx_file(filename)
break
default:
wave /z image = $""
endswitch
if (WaveExists(image))
string graphname = show_preview_graph(image)
@ -240,9 +290,10 @@ static function preview_file(filename)
endif
setdatafolder saveDF
return 0
end
/// load the preview of a PShell HDF5 file (not implemented).
/// load the preview of a PShell HDF5 file.
///
/// the preview is an arbitrary detector image extracted from the file, see adh5_load_preview().
/// the preview is loaded to the preview_image wave in the pear_explorer data folder.
@ -354,6 +405,63 @@ static function /wave preview_itx_file(filename)
return preview_image
end
/// load the preview of a Matrix STM file.
///
/// the preview is loaded to the preview_image wave in the pearl_explorer data folder.
///
/// the s_file_info string is updated with information about the scan dimensions.
///
/// this function requires the MatrixFileReader.xop and pearl-matrix-import.ipf to be loaded.
/// otherwise it will return an empty wave reference.
///
/// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object.
///
/// @return wave reference of the preview image.
/// empty wave reference if the function failed.
///
static function /wave preview_mtrx_file(filename)
string filename
#if exists("MFR_OpenResultFile")
dfref saveDF = GetDataFolderDFR()
setdatafolder $package_path
variable /g V_MatrixFileReaderOverwrite = 1
variable /g V_MatrixFileReaderFolder = 0
variable /g V_MatrixFileReaderDouble = 0
svar s_preview_file
svar s_preview_source
string datanames
string dataname
datanames = mtrx_load_preview("preview", "pearl_explorer_filepath", filename)
if (strlen(datanames) > 0)
s_preview_file = filename
dataname = StringFromList(0, datanames)
wave data = $dataname
duplicate /o $dataname, preview_image
s_preview_source = StringByKey("Dataset", note(data), "=", "\r")
svar /z s_file_info
if (svar_exists(s_file_info))
s_file_info = ""
endif
variable i
variable n = ItemsInList(datanames)
string s
for (i = 0; i < n; i += 1)
s = StringFromList(i, datanames)
killwaves /z $s
endfor
endif
wave /z preview_image
setdatafolder saveDF
#else
wave /z preview_image = $""
#endif
return preview_image
end
static function extract_preview_image(data, preview)
// extracts a preview image from a wave of arbitrary dimension
wave data
@ -862,22 +970,32 @@ static function load_file(filename, [options])
dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, ks_filematch_pshell))
if (ParamIsDefault(options))
load_pshell_file(filename)
else
load_pshell_file(filename, options=options)
endif
elseif (StringMatch(filename, ks_filematch_adh5))
if (ParamIsDefault(options))
load_hdf_file(filename)
else
load_hdf_file(filename, options=options)
endif
elseif (StringMatch(filename, ks_filematch_itx))
load_itx_file(filename)
endif
variable ft = pearl_file_type(filename)
switch(ft)
case 1:
if (ParamIsDefault(options))
load_pshell_file(filename)
else
load_pshell_file(filename, options=options)
endif
break
case 2:
if (ParamIsDefault(options))
load_hdf_file(filename)
else
load_hdf_file(filename, options=options)
endif
break
case 3:
load_itx_file(filename)
break
case 4:
load_mtrx_file(filename)
break
default:
break
endswitch
setdatafolder saveDF
end
@ -1080,6 +1198,32 @@ static function /df load_itx_file(filename, [options])
return actDF
end
/// load a matrix (STM) data file
///
///
static function /df load_mtrx_file(filename, [options])
string filename
string options
dfref saveDF = GetDataFolderDFR()
dfref dataDF = $""
#if exists("MFR_OpenResultFile")
setdatafolder root:
string datasets = ""
datasets = mtrx_load_file("pearl_explorer_filepath", filename)
if (strlen(datasets) > 0)
string /g pearl_explorer_import = "load_mtrx_file"
string s1 = StringFromList(0, datasets)
wave w1 = $s1
dataDF = GetWavesDataFolderDFR(w1)
endif
#endif
setdatafolder saveDF
return dataDF
end
function /s itx_suggest_foldername(filename, [ignoredate,sourcename,unique])
// suggests the name of a data folder based on a file name
// if the file name follows the naming convention source-date-index.extension,

View File

@ -1,5 +1,5 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma version = 1.31
#pragma version = 1.40
#pragma IgorVersion = 6.2
#pragma ModuleName = PearlElog
@ -16,13 +16,38 @@
/// @ingroup ArpesPackage
///
///
/// the functions in this module support the following work flows:
/// 1. send a preview of a selected measurement to ELOG.
/// 2. send any Igor graph to ELOG. (CLI and GUI)
/// 3. direct access to all ELOG parameters. (CLI only)
/// the functions in this module support the following ELOG features:
/// - submit new entries and replies to existing entries.
/// - text field, list box, and check box attributes.
/// - attach any Igor graph to ELOG.
/// - configurable logbook templates for logbooks that share the same configuration.
/// - common server configurations available on the ELOG command line
/// (hostname, port, SSL, username, password, sub-directory).
/// - not specific to the configuration at PEARL.
/// PEARL code is concentrated in the elog_init_pearl_templates() function.
/// - the configuration of the ELOG server and logbooks
/// as well as the most recently used attributes are persisted in the preference file.
///
/// the configuration of the ELOG server and logbooks (except user name and password)
/// as well as the most recently used attributes are persisted in the preference file.
/// usage:
/// 1. the administrator of the ELOG server creates logbook templates
/// according to the configuration of the logbooks.
/// the templates are written in Igor code.
/// 2. the user opens logbooks via the _Open ELOG panel_ menu item.
/// before first use, select a template and enter a name for the logbook.
/// the new logbook is written to the preference file,
/// and can afterwards be opened directly.
/// 3. if the server requires a user name and password,
/// click the login button.
/// 4. edit the message, attributes and attachments as necessary, and submit to ELOG.
/// 5. log out before saving the experiment to clear the password.
///
/// @attention the user name and password are stored in the global data tree of an experiment.
/// it is not possible to handle passwords safely in Igor.
/// they can be read by anyone having access to an open Igor experiment or a saved experiment file
/// (unless the password is reset before saving).
/// therefore:
/// - use a password for the ELOG server which is different from your other passwords.
/// - clear the password (logout button in the panel) before saving an experiment.
///
/// elog command line
///@verbatim
@ -43,12 +68,6 @@
/// -m <textfile>] | <text>
///@endverbatim
///
/// user name and password are used if configured in the package data folder.
/// there is currently no separate user interface.
///
/// @attention some functions in this module refer specifically to the ELOG configuration at PEARL.
///
/// @todo ask for logbook, username and password before opening the panel.
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
@ -82,7 +101,7 @@ function pearl_elog(logbook)
load_prefs()
string templates = list_logbooks(templates=1)
if (ItemsInList(templates) < 1)
init_pearl_templates()
elog_init_pearl_templates()
endif
endif
@ -95,7 +114,11 @@ function pearl_elog(logbook)
if (strlen(WinList(win_name, ";", "")) > 0)
DoWindow /F $win_name
else
PearlElogPanel(logbook)
win_name = PearlElogPanel(logbook)
STRUCT WMWinHookStruct s
s.eventCode = 0
s.winName = win_name
elog_panel_hook(s)
endif
endif
end
@ -104,6 +127,7 @@ end
static function IgorBeforeNewHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
cleanup_temp_files()
return 0
end
@ -111,6 +135,7 @@ end
static function IgorQuitHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
cleanup_temp_files()
return 0
end
@ -234,7 +259,7 @@ end
///
/// @remark this function is specific to the setup at PEARL.
///
static function init_pearl_templates()
function elog_init_pearl_templates()
dfref savedf = getdatafolderdfr()
dfref df_root = get_elog_df("", kdfRoot)
@ -247,10 +272,10 @@ static function init_pearl_templates()
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;source;task;technique;valid;file"
string /g attributes = "author;project;sample;source;task;technique;file;valid;"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;sv_project;sv_sample;pm_source;pm_task;pm_technique;cb_valid;sv_file"
string /g controls = "sv_author;sv_project;sv_sample;pm_source;pm_task;pm_technique;sv_file;cb_valid;"
// attributes with fixed options, value item declares the options string
string /g options = "source=sources;task=tasks;technique=techniques"
// attributes which must be defined
@ -258,8 +283,8 @@ static function init_pearl_templates()
// option lists
string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
string /g tasks = "Measurement;Sample Preparation;Sample Storage;Optimization;Analysis;Development;Maintenance;Test;Comment;Other"
string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;LEED;AES;STM;STS;QMS;MBE;Test;Other"
string /g tasks = "Measurement;Optimization;Analysis;Sample Preparation;Sample Storage;Comment;Development;Maintenance;Test;Other"
string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;STM;STS;LEED;AES;QMS;MBE;Sputter/Anneal;Test;Other"
// Calculations template
setdatafolder df_templates
@ -267,18 +292,38 @@ static function init_pearl_templates()
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;program;revision;machine;job;source path;result path;valid"
string /g attributes = "author;project;sample;program;revision;machine;job;experiment;source path;result path;valid"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;sv_project;sv_sample;pm_program;sv_revision;pm_machine;sv_job;sv_sourcepath;sv_resultpath;cb_valid"
string /g controls = "sv_author;sv_project;sv_sample;pm_program;sv_revision;pm_machine;sv_job;sv_experiment;sv_sourcepath;sv_resultpath;cb_valid"
// attributes with fixed options, value item declares the options string
string /g options = "program=programs;machine=machines"
// attributes which must be defined
string /g required_attributes = "author;project;sample"
// option lists
string /g programs = "DMSUP;EDAC;MSC;MUFPOT;SSC"
string /g machines = "llcx;Merlin;PC"
string /g programs = "PMSCO;EDAC;MSC;SSC;MUFPOT;DMSUP;Other"
string /g machines = "PC;VM;Ra;Merlin;llcx;Other"
// System template
setdatafolder df_templates
newdatafolder /o/s System
// attributes (persistent)
// available attributes
string /g attributes = "author;type;system;source;file"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;pm_type;pm_system;pm_source;sv_file"
// attributes with fixed options, value item declares the options string
string /g options = "type=types;system=systems;source=sources"
// attributes which must be defined
string /g required_attributes = "author;type;system"
// option lists
string /g types = "Installation;Repair;Maintenance;Test;Commissioning;Bakeout;Incident;Cool-down;Warm-up;Storage;Other"
string /g systems = "Vacuum;Control System;BL;XA;XP;SA;SP;T;LL;Monochromator;Carving;Scienta;STM;PC-Scienta;PC-Matrix;PC-Console;PC-Console-Win;PC-XP;EPS;LAC;Desiccator"
string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
setdatafolder savedf
return 0
@ -303,6 +348,11 @@ static function init_volatile_vars()
variable nlb = ItemsInList(logbooks)
variable ilb
SetDataFolder df_volatile_root
if (exists("temp_graph_files") != 2)
string /g temp_graph_files = ""
endif
for (ilb = 0; ilb < nlb; ilb += 1)
logbook = StringFromList(ilb, logbooks)
@ -322,6 +372,13 @@ static function init_volatile_vars()
if (exists("msg_id") != 2)
variable /g msg_id = 0
endif
if (exists("att_list") != 1)
make /n=(0,3) /t /o attach_list
make /n=(0,3) /i /o attach_sel
endif
if (exists("url") != 2)
string /g url = ""
endif
endfor
SetDataFolder savedf
@ -347,6 +404,9 @@ end
/// create a new empty logbook or duplicate from a template.
///
/// @param name name of the new logbook.
/// if the logbook exists, the existing logbook folder is killed
/// and replaced by a new one.
/// this may fail if a window is still open.
///
/// @param template name of the template.
/// if empty string, a new empty logbook is created.
@ -368,6 +428,10 @@ function elog_create_logbook(name, [template])
if (strlen(template) > 0)
dfref df_template = get_elog_df(template, kdfTemplates)
dfref df_existing = get_elog_df(name, kdfPersistent)
if (DataFolderRefStatus(df_existing))
KillDataFolder /Z df_existing
endif
DuplicateDataFolder df_template, df_persistent_parent:$name
else
NewDataFolder /o/s df_persistent_parent:$name
@ -695,7 +759,6 @@ function elog_create_entry(logbook, attributes, message, [encoding, graphs, repl
endif
result = -4
endif
cleanup_temp_files()
else
if (loglevel >= 2)
print "ELOG: failed to create temporary message file."
@ -759,7 +822,6 @@ function elog_add_attachment(logbook, id, graphs)
endif
result = -4 // error: elog returned error
endif
cleanup_temp_files()
endif
setdatafolder savedf
@ -817,6 +879,39 @@ static function /s prepare_command_line(logbook)
return cmd
end
/// format the URL for display to the user
///
///
/// @param logbook name of the target logbook
///
static function /s format_url(logbook)
string logbook
dfref df_general = get_elog_df("", kdfPersistent)
svar /sdfr=df_general hostname
nvar /sdfr=df_general port
nvar /sdfr=df_general ssl
svar /sdfr=df_general subdir
string cmd = ""
if ((nvar_exists(ssl)) && (ssl != 0))
cmd += "https://"
else
cmd += "http://"
endif
cmd += hostname
if ((nvar_exists(port)) && (port > 0))
cmd += ":" + num2str(port)
endif
if ((svar_exists(subdir)) && (strlen(subdir) > 0))
cmd += "/" + subdir
endif
cmd += "/" + logbook
return cmd
end
/// prepare screenshots of graph windows for attachments
///
/// prepares the attachment files from Igor graph windows
@ -875,13 +970,18 @@ static function /s create_graph_file(graphname, fileindex)
string graphname
variable fileindex
dfref df_volatile_root = get_elog_df("", kdfVolatile)
svar /sdfr=df_volatile_root temp_graph_files
string path = SpecialDirPath("Temporary", 0, 1, 0)
string ts = get_timestamp("_")
variable len = strlen(path)
if (numtype(len) == 0)
path += "elog_" + ts + "_" + num2str(fileindex) + ".png"
SavePICT /B=72 /E=-5 /M /O /W=(0,0,8,6) /WIN=$graphname /Z as path
if (v_flag != 0)
if (v_flag == 0)
temp_graph_files = AddListItem(path, temp_graph_files, ";", inf)
else
path = ""
endif
else
@ -921,12 +1021,30 @@ static function /s get_log_path()
return path
end
static function /s cleanup_temp_files()
string path = SpecialDirPath("Temporary", 0, 1, 0)
string cmd
sprintf cmd, "del \"%s\elog*.*\"", path
//ExecuteScriptText cmd
return path
/// delete temporary files created by the ELOG module.
///
/// this deletes all temporary graph files that are referenced by the volatile temp_graph_files list.
/// temp_graph_files is a semicolon-delimited string.
/// items are added by create_graph_file().
///
/// this function should be called before a new experiment is loaded or igor quits.
///
static function cleanup_temp_files()
dfref df_volatile_root = get_elog_df("", kdfVolatile)
if (DataFolderRefStatus(df_volatile_root))
svar /sdfr=df_volatile_root /z temp_graph_files
if (SVAR_Exists(temp_graph_files))
variable nfi = ItemsInList(temp_graph_files)
variable ifi
string sfi
for (ifi = 0; ifi < nfi; ifi += 1)
sfi = StringFromList(ifi, temp_graph_files)
DeleteFile /Z sfi
endfor
temp_graph_files = ""
endif
endif
return 0
end
static strconstant elog_success_msg = "Message successfully transmitted"
@ -1048,14 +1166,17 @@ function /s PearlElogPanel(logbook)
string win_name = logbook + "ElogPanel"
string win_title = "ELOG " + logbook
NewPanel /K=1 /N=$win_name /W=(600,200,926,494) as win_title
NewPanel /K=1 /N=$win_name /W=(600,200,1200,700) as win_title
win_name = s_name
ModifyPanel /w=$win_name cbRGB=(52224,52224,65280)
svar /sdfr=df_persistent attributes
svar /sdfr=df_persistent controls
svar /sdfr=df_persistent options
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
svar /sdfr=df_volatile url
variable iattr
variable nattr = ItemsInList(attributes, ";")
string s_attr
@ -1066,35 +1187,28 @@ function /s PearlElogPanel(logbook)
string options_path
string variable_path
variable ypos = 2
variable height = 0
Button b_login,win=$win_name, pos={264,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
Button b_login,win=$win_name, help={"Enter user name and password."}
Button b_login,win=$win_name, fcolor=(56576,60928,47872)
Button b_logout,win=$win_name, pos={264,ypos},size={46,20},proc=PearlElog#bp_logout,title="Logout"
Button b_logout,win=$win_name, help={"Clear user name and password."}
Button b_logout,win=$win_name, fcolor=(56576,60928,47872), disable=3
for (iattr = 0; iattr < nattr; iattr += 1)
s_attr = StringFromList(iattr, attributes, ";")
s_control = StringFromList(iattr, controls, ";")
strswitch(s_control[0,1])
case "sv":
SetVariable $s_control, win=$win_name, pos={0,ypos}, size={260,16}, bodyWidth=200
SetVariable $s_control, win=$win_name, pos={0,ypos}, size={300,16}, bodyWidth=230
SetVariable $s_control, win=$win_name, title=s_attr, value= _STR:""
SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 18
break
case "pm":
options_path = persistent_path + StringByKey(s_attr, options, "=", ";")
PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={260,21}, bodyWidth=200
PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={300,21}, bodyWidth=230
PopupMenu $s_control, win=$win_name, title=s_attr
PopupMenu $s_control, win=$win_name, mode=1, popvalue="Test", value= #options_path
PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 23
break
case "cb":
CheckBox $s_control, win=$win_name, pos={60,ypos}, size={260,14}
CheckBox $s_control, win=$win_name, pos={70,ypos}, size={300,14}
CheckBox $s_control, win=$win_name, title=s_attr, value= 1
CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 17
@ -1102,48 +1216,81 @@ function /s PearlElogPanel(logbook)
endswitch
endfor
PopupMenu pm_attach,win=$win_name, pos={0,ypos},size={260,21},bodyWidth=200,title="Attachment"
PopupMenu pm_attach,win=$win_name, mode=1,popvalue="(none)",value=PearlElog#pm_list_attach_items()
PopupMenu pm_attach,win=$win_name, help={"Choose any visible Igor graph for attachment."}
Button b_select_attach_top,win=$win_name, pos={264,ypos},size={60,20},proc=PearlElog#bp_select_attach_top,title="Top Graph"
Button b_select_attach_top,win=$win_name, help={"Select top graph window."}
Button b_select_attach_top,win=$win_name, fcolor=(56576,60928,47872)
TitleBox t_attach, win=$win_name, pos={308,5}, size={70,14}, title="Attachments", frame=0
height = ypos - 21 - 4
ListBox lb_attach, win=$win_name, pos={308,21}, size={264,height}
ListBox lb_attach, win=$win_name, listWave=attach_list
ListBox lb_attach, win=$win_name, mode=1, selWave=attach_sel, selRow=-1
ListBox lb_attach, win=$win_name, widths={20,160,80}
ListBox lb_attach, win=$win_name, help={"Choose graphs to attach to the message."}
Button b_attach_top, win=$win_name, pos={420,2}, size={40,18}, title="top"
Button b_attach_top, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_top, win=$win_name, proc=PearlElog#bp_attach_top
Button b_attach_top, win=$win_name, help={"Select top graph for attachment."}
Button b_attach_all, win=$win_name, pos={460,2}, size={40,18}, title="all"
Button b_attach_all, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_all, win=$win_name, proc=PearlElog#bp_attach_allnone
Button b_attach_all, win=$win_name, help={"Select all graphs for attachment."}
Button b_attach_none, win=$win_name, pos={500,2}, size={40,18}, title="none"
Button b_attach_none, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_none, win=$win_name, proc=PearlElog#bp_attach_allnone
Button b_attach_none, win=$win_name, help={"Deselect all attachments."}
Button b_save_graphs, win=$win_name, pos={540,2}, size={40,18}, title="save"
Button b_save_graphs, win=$win_name, fcolor=(56576,60928,47872)
Button b_save_graphs, win=$win_name, proc=PearlElog#bp_save_graphs
Button b_save_graphs, win=$win_name, help={"Save selected graphs as PNG bitmap files."}
Button b_attach_up, win=$win_name, pos={576,20}, size={20,20}, title="\\W517"
Button b_attach_up, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_up, win=$win_name, proc=PearlElog#bp_attach_updown
Button b_attach_up, win=$win_name, help={"Move selected graph up."}
Button b_attach_dw, win=$win_name, pos={576,40}, size={20,20}, title="\\W523"
Button b_attach_dw, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_dw, win=$win_name, proc=PearlElog#bp_attach_updown
Button b_attach_dw, win=$win_name, help={"Move selected graph down."}
ypos += 246-160
Button b_submit,win=$win_name, pos={60,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
Button b_submit,win=$win_name, pos={70,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
Button b_submit,win=$win_name, help={"Submit form data to ELOG (new entry)."}
Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
Button b_clear,win=$win_name, pos={110,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
Button b_clear,win=$win_name, pos={120,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
Button b_clear,win=$win_name, help={"Clear the form fields"}
Button b_clear,win=$win_name, fcolor=(56576,60928,47872)
ypos += 272-246
variable_path = volatile_path + "msg_id"
SetVariable sv_id,win=$win_name, pos={46,ypos},size={109,16},bodyWidth=94
SetVariable sv_id,win=$win_name, pos={51,ypos},size={119,16},bodyWidth=77
SetVariable sv_id,win=$win_name, title="ID",value=$variable_path
SetVariable sv_id,win=$win_name, help={"ID of last submitted message, or message to attach or reply to."}
TitleBox t_host, win=$win_name, pos={170,ypos+4}, size={112.00,14.00}, frame=0
TitleBox t_host, win=$win_name, variable=url
ypos += 270-272
Button b_attach,win=$win_name, pos={160,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
Button b_attach,win=$win_name, pos={170,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
Button b_attach,win=$win_name, help={"Attach the selected graph to an existing ELOG entry (correct ID required)."}
Button b_attach,win=$win_name, fcolor=(56576,60928,47872)
Button b_reply,win=$win_name, pos={210,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
Button b_reply,win=$win_name, pos={220,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
Button b_reply,win=$win_name, help={"Submit form data to ELOG as a reply to an existing message (correct ID required)."}
Button b_reply,win=$win_name, fcolor=(56576,60928,47872)
ypos += 184-270
TitleBox t_message,win=$win_name, pos={0,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
Button b_login,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
Button b_login,win=$win_name, help={"Enter user name and password."}
Button b_login,win=$win_name, fcolor=(56576,60928,47872)
Button b_logout,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_logout,title="Logout"
Button b_logout,win=$win_name, help={"Clear user name and password."}
Button b_logout,win=$win_name, fcolor=(56576,60928,47872), disable=3
SetWindow $win_name, hook(elogPanelHook)=PearlElog#elog_panel_hook
SetWindow $win_name, userdata(logbook)=logbook
DefineGuide UGH0={FT,ypos},UGV0={FL,60},UGH1={FB,-52},UGV1={FR,-2}
ypos += 160-270
TitleBox t_message,win=$win_name, pos={10,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
DefineGuide UGH0={FT,ypos},UGV0={FL,70},UGH1={FB,-52},UGV1={FR,-2}
NewNotebook /F=0 /N=Message /OPTS=3 /W=(115,404,345,341)/FG=(UGV0,UGH0,UGV1,UGH1) /HOST=#
Notebook kwTopWin, defaultTab=20, statusWidth=0, autoSave=0
Notebook kwTopWin font="Arial", fSize=10, fStyle=0, textRGB=(0,0,0)
Notebook kwTopWin fSize=10, fStyle=0, textRGB=(0,0,0)
RenameWindow #,Message
string nb_name = win_name + "#Message"
SetActiveSubwindow ##
// restore recently used attributes and message
@ -1155,6 +1302,7 @@ function /s PearlElogPanel(logbook)
if (svar_exists(recent_message) && (strlen(recent_message) > 0))
set_panel_message(win_name, recent_message)
endif
Notebook $nb_name selection={startOfFile,startOfFile}, findText={"",1}
setdatafolder savedf
return win_name
@ -1166,49 +1314,152 @@ static function elog_panel_hook(s)
Variable hookResult = 0
switch(s.eventCode)
case 0: // activate
string logbook = GetUserData(s.winName, "", "logbook")
if (strlen(logbook) > 0)
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
svar /sdfr=df_volatile url
url = format_url(logbook)
update_attach_items(logbook)
endif
break
case 6: // resize
// move bottom-aligned controls when the window is resized
variable b_top = s.winRect.bottom + 4
Button b_submit,pos={60,b_top}
Button b_clear,pos={110,b_top}
Button b_submit,pos={70,b_top}
Button b_clear,pos={120,b_top}
TitleBox t_host, pos={170,b_top+4}
b_top += 24
Button b_attach,pos={160,b_top}
Button b_reply,pos={210,b_top}
Button b_attach,pos={170,b_top}
Button b_reply,pos={220,b_top}
Button b_login, pos={550,b_top}
Button b_logout, pos={550,b_top}
b_top += 2
SetVariable sv_id,pos={46,b_top}
SetVariable sv_id,pos={51,b_top}
break
endswitch
return hookResult // 0 if nothing done, else 1
end
/// get a list of graph windows for a popup menu.
static function /s pm_list_attach_items()
static constant kAttachColSel = 0
static constant kAttachColTitle = 1
static constant kAttachColName = 2
// get graph names
/// update the list of attachments
static function update_attach_items(logbook)
string logbook
dfref savedf = getdatafolderdfr()
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
if (!waveexists(attach_list))
return -1
endif
string names = WinList("*", ";", "WIN:1;VISIBLE:1")
names = SortList(names, ";", 16)
// get corresponding graph titles
variable nnames = ItemsInList(names, ";")
variable iname
string name
string item
string items = ""
// format each entry like "name: title"
for (iname = 0; iname < nnames; iname += 1)
name = StringFromList(iname, names, ";")
getwindow /z $name, wtitle
if (v_flag == 0)
item = ReplaceString(";", s_value, ", ") // title
item = item + " (" + name + ")"
items = AddListItem(item, items, ";", inf)
// remove closed graphs
variable i
variable k
variable n = DimSize(attach_list, 0)
string s
for (i = n-1; i >= 0; i -= 1)
s = attach_list[i][kAttachColName]
if (WhichListItem(s, names) < 0)
DeletePoints /M=0 i, 1, attach_list, attach_sel
endif
endfor
items = AddListItem("(none)", items, ";")
return items
// add new graphs
n = ItemsInList(names)
for (i = 0; i < n; i += 1)
s = StringFromList(i, names)
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] = ""
attach_list[k][kAttachColName] = s
attach_sel[i][kAttachColSel] = 32
attach_sel[i][kAttachColTitle] = 0
attach_sel[i][kAttachColName] = 0
endif
endfor
// update titles
n = DimSize(attach_list, 0)
for (i = n-1; i >= 0; i -= 1)
s = attach_list[i][kAttachColName]
getwindow /z $s, wtitle
if (v_flag == 0)
attach_list[i][kAttachColTitle] = s_value
else
attach_list[i][kAttachColTitle] = s
endif
endfor
setdatafolder savedf
return 0
end
/// move an attachment item in the list of attachments
static function move_attach_item(logbook, item, distance)
string logbook
variable item
variable distance
dfref savedf = getdatafolderdfr()
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
variable n = DimSize(attach_list, 0)
variable dest = item + distance
if ((item >= 0) && (item < n) && (dest >= 0) && (dest < n))
string name = attach_list[item][kAttachColName]
variable sel = attach_sel[item][kAttachColSel]
DeletePoints /M=0 item, 1, attach_list, attach_sel
InsertPoints /M=0 dest, 1, attach_list, attach_sel
attach_list[dest][kAttachColName] = name
update_attach_items(logbook)
attach_sel[dest][kAttachColSel] = sel
endif
end
/// button procedure for the attachment up and down buttons
static function bp_attach_updown(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
ControlInfo /w=$ba.win lb_attach
variable row = v_value
dfref df = $s_datafolder
wave /t /sdfr=df attach_list = $s_value
if (cmpstr(ba.ctrlName, "b_attach_up") == 0)
// up button
if (row >= 1)
move_attach_item(logbook, row, -1)
ListBox lb_attach, win=$ba.win, selRow=(row-1)
endif
else
// down button
if (row < DimSize(attach_list, 0) - 1)
move_attach_item(logbook, row, +1)
ListBox lb_attach, win=$ba.win, selRow=(row+1)
endif
endif
break
case -1: // control being killed
break
endswitch
return 0
end
/// button procedure for the Submit and Reply buttons
@ -1259,7 +1510,7 @@ static function bp_submit(ba) : ButtonControl
end
/// select top graph window for attachment
static function bp_select_attach_top(ba) : ButtonControl
static function bp_attach_top(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
@ -1274,6 +1525,28 @@ static function bp_select_attach_top(ba) : ButtonControl
return 0
end
/// select/deselect all graph windows for attachment
static function bp_attach_allnone(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /sdfr=df_volatile attach_sel
if (cmpstr(ba.ctrlName, "b_attach_all") == 0)
attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] | 16
else
attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] & ~16
endif
break
case -1: // control being killed
break
endswitch
return 0
end
static function bp_attach(ba) : ButtonControl
STRUCT WMButtonAction &ba
@ -1307,6 +1580,34 @@ static function bp_attach(ba) : ButtonControl
return 0
end
static function bp_save_graphs(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
string graphs = get_panel_graphs(ba.win)
variable ngraphs = ItemsInList(graphs, ";")
variable igraph
string sgraph
string graph_path
for (igraph = 0; igraph < ngraphs; igraph += 1)
sgraph = StringFromList(igraph, graphs, ";")
graph_path = create_graph_file(sgraph, igraph)
if (strlen(graph_path) > 0)
print graph_path
endif
endfor
break
case -1: // control being killed
break
endswitch
return 0
end
static function bp_clear(ba) : ButtonControl
STRUCT WMButtonAction &ba
@ -1522,15 +1823,14 @@ end
/// get the names of the graphs selected for attachment
///
/// @param windowname panel window name
/// @returns a semicolon-separated list,
/// or the empty string if the selection is not valid.
///
/// in the current version, the function returns at most one graph.
/// in future versions, the function may return more than one graph.
///
static function /s get_panel_graphs(windowname)
string windowname // panel window name
dfref savedf = getdatafolderdfr()
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
@ -1538,24 +1838,38 @@ static function /s get_panel_graphs(windowname)
return ""
endif
ControlInfo /W=$windowname pm_attach
// menu item has the form: "title (name)"
string graphname = ReplaceString(")", StringFromList(ItemsInList(s_value, "(") - 1, s_value, "("), "")
string logbook = GetUserData(windowname, "", "logbook")
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
string graphs = ""
string windows = WinList(graphname, ";", "WIN:1")
if (ItemsInList(windows) == 1)
graphs = graphname
else
graphs = ""
endif
string windows = ""
string graphname
variable n = DimSize(attach_sel, 0)
variable i
for (i = 0; i < n; i += 1)
if (attach_sel[i][kAttachColSel] & 16)
graphname = attach_list[i][kAttachColName]
windows = WinList(graphname, ";", "WIN:1")
if (ItemsInList(windows) == 1)
graphs = AddListItem(graphname, graphs, ";", inf)
endif
endif
endfor
return graphs
end
/// update selection of graphs for attachment
///
/// @param windowname panel window name. looks for default panel if empty.
///
/// @param graphs semicolon-separated list of names of graph windows to select for attachment.
///
static function /s set_panel_graphs(windowname, graphs)
string windowname // panel window name. looks for default panel if empty.
string graphs // name of graph window to select for attachment.
string windowname
string graphs
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
@ -1564,23 +1878,21 @@ static function /s set_panel_graphs(windowname, graphs)
return ""
endif
// the panel supports only one graph
string graph = StringFromList(0, graphs, ";")
string items = pm_list_attach_items()
string item
string itemname
variable nitems = ItemsInList(items, ";")
variable iitem
for (iitem = 0; iitem < nitems; iitem += 1)
item = StringFromList(iitem, items, ";")
itemname = ReplaceString(")", StringFromList(ItemsInList(item, "(") - 1, item, "("), "")
if (cmpstr(graph, itemname) == 0)
iitem += 1
PopupMenu pm_attach mode=iitem, win=$windowname
break
string logbook = GetUserData(windowname, "", "logbook")
update_attach_items(logbook)
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
variable n = DimSize(attach_sel, 0)
variable i
string graphname
for (i = 0; i < n; i += 1)
graphname = attach_list[i][kAttachColName]
if (WhichListItem(graphname, graphs)>= 0)
attach_sel[i][kAttachColSel] = 48
else
attach_sel[i][kAttachColSel] = 32
endif
endfor
return graph
end

View File

@ -0,0 +1,900 @@
#pragma rtGlobals=3
#pragma version = 1.00
#pragma IgorVersion = 6.36
#pragma ModuleName = PearlMatrixImport
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2016 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
/// @file
/// @brief data file import for omicron matrix (STM) files
///
/// the matrix file import requires the matrix file reader XOP by thomas braun
/// (http://www.igorexchange.com/project/matrixFileReader)
/// which in turn requires an installation of vernissage by omicron nanotechnology.
///
/// @warning EXPERIMENTAL
/// the matrix import module and its interface may change radically in future revisions!
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2016 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 PearlMatrixImport
/// @brief data file import for omicron matrix (STM) files
///
/// PearlMatrixImport is declared in @ref pearl-matrix-import.ipf.
static strconstant package_name = "pearl_matrix_import"
static strconstant package_path = "root:packages:pearl_matrix_import:"
static strconstant ks_filematch_mtrx = "*_mtrx"
/// initialize the package data folder.
///
///
static function init_package()
dfref savedf = getdatafolderdfr()
setdatafolder root:
newdatafolder /o/s packages
newdatafolder /o/s $package_name
variable /g loglevel = 3
string /g dataFilePath = ""
string /g resultFilePath = ""
variable /g runCycle = 0
variable /g scanCycle = 0
string /g channelName = ""
variable /g brickletID = 0
variable /g V_MatrixFileReaderOverwrite = 1
variable /g V_MatrixFileReaderFolder = 0
variable /g V_MatrixFileReaderDouble = 0
setdatafolder savedf
return 0
end
/// check that the package data folder exists
///
/// initialize the package if the folder does not exist.
///
static function check_package_folder()
dfref df_pack = $(package_path)
if (DataFolderRefStatus(df_pack))
svar /sdfr=df_pack /z resultFilePath
if (!svar_exists(resultFilePath))
init_package()
endif
else
init_package()
endif
end
/// initialize the package and reload preferences after an experiment is loaded.
static function AfterFileOpenHook(refNum,file,pathName,type,creator,kind)
Variable refNum,kind
String file,pathName,type,creator
if( (kind >= 1) && (kind <= 2))
init_package()
//load_prefs()
endif
return 0
end
/// open a matrix file that was dropped into Igor.
///
/// preliminary implementation.
/// this should rather load the entire file and display a preview.
/// graph windows should be reused by subsequent loads.
/// also decide on a data saving location.
///
static function BeforeFileOpenHook(refNum,fileName,path,type,creator,kind)
Variable refNum,kind
String fileName,path,type,creator
Variable handledOpen = 0
if (StringMatch(fileName, ks_filematch_mtrx))
setdatafolder root:
newdatafolder /o /s matrix
mtrx_load_preview("matrix", path, fileName)
handledOpen = 1
endif
return handledOpen
End
/// generate elog message from bricklet metadata
///
/// @param metadata two-column text wave
///
function /s matrix_format_elog_message(metadata)
wave /t metadata
string key
string value
variable nkeys = dimsize(metadata, 0)
variable ikey
string message_keys
message_keys = "resultFileName;sampleName;channelName;"
message_keys += "XYScanner.Points.value;XYScanner.Raster_Time.value;XYScanner.Raster_Time.unit;XYScanner.Width.value;XYScanner.Width.unit;XYScanner.Height.value;XYScanner.Height.unit;"
message_keys += "GapVoltageControl.Voltage.value;GapVoltageControl.Voltage.unit;"
message_keys += "Regulator.Loop_Gain_1_I.value;Regulator.Loop_Gain_1_I.unit;Regulator.Setpoint_1.value;Regulator.Setpoint_1.unit;"
message_keys += "Spectroscopy.Device_1_Start.value;Spectroscopy.Device_1_Start.unit;Spectroscopy.Spectroscopy_Mode.value;"
string message
message_keys = ""
for (ikey = 0; ikey < nkeys; ikey += 1)
key = metadata[ikey][0]
value = metadata[ikey][1]
if (WhichListItem(key, message_keys) >= 0)
message += key + " = " + value + "\r"
endif
endfor
end
function matrix_preview_2d(data, metadata)
wave data
wave /t metadata
Display
AppendImage data
ModifyImage data ctab= {*,*,Mud,0}
ModifyGraph margin(left)=30,margin(bottom)=30,margin(top)=5,margin(right)=5,height={Plan,1,left,bottom}
ModifyGraph mirror=2
ModifyGraph nticks=3
ModifyGraph axThick=0.5
ModifyGraph btLen=4
end
/// load the preview of a Matrix data file
///
/// the preview is loaded to the preview_image wave in the pearl_explorer data folder.
///
/// the s_file_info string is updated with information about the scan dimensions.
///
/// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object.
///
/// @return wave reference of the preview image
///
static function /wave preview_matrix_file(filename)
string filename
dfref saveDF = GetDataFolderDFR()
setdatafolder $package_path
svar s_preview_file
svar s_preview_source
mtrx_load_preview("preview_image", "pearl_explorer_filepath", filename)
s_preview_file = filename
s_preview_source = ""
wave /z preview_image
svar /z s_file_info
if (! svar_exists(s_file_info))
string /g s_file_info
endif
if (strlen(s_preview_file) > 0)
s_file_info = mtrx_load_info("pearl_explorer_filepath", filename)
else
s_file_info = ""
endif
setdatafolder saveDF
return preview_image
end
/// from matrixfilereader help
Structure errorCode
int32 SUCCESS
int32 UNKNOWN_ERROR
int32 ALREADY_FILE_OPEN
int32 EMPTY_RESULTFILE
int32 FILE_NOT_READABLE
int32 NO_NEW_BRICKLETS
int32 WRONG_PARAMETER
int32 INTERNAL_ERROR_CONVERTING_DATA
int32 NO_FILE_OPEN
int32 INVALID_RANGE
int32 WAVE_EXIST
EndStructure
/// from matrixfilereader help
static Function initStruct(errorCode)
Struct errorCode &errorCode
errorCode.SUCCESS =0
errorCode.UNKNOWN_ERROR=10001
errorCode.ALREADY_FILE_OPEN=10002
errorCode.EMPTY_RESULTFILE=10004
errorCode.FILE_NOT_READABLE=10008
errorCode.NO_NEW_BRICKLETS=10016
errorCode.WRONG_PARAMETER=10032
errorCode.INTERNAL_ERROR_CONVERTING_DATA=10064
errorCode.NO_FILE_OPEN=10128
errorCode.INVALID_RANGE=10256
errorCode.WAVE_EXIST=10512
end
/// load all data from a Matrix data file.
///
function mtrx_load_all()
struct errorCode errorCode
initStruct(errorCode)
#if exists("MFR_OpenResultFile")
MFR_OpenResultFile
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
return -1
endif
MFR_GetBrickletData
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
return -1
endif
MFR_GetBrickletMetaData
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
return -1
endif
return 0
#else
return -1
#endif
end
/// parse matrix file names
///
/// parse matrix file names for result name, run cycle, scan cycle, and channel.
///
/// @param fileName matrix result or data file name (without path).
///
/// @param resultFile (out) base name of the result file.
/// append "_%04u.mtrx" to get the actual result file.
/// we do not know the chain link number at this stage.
///
/// @param runCycle (out) run cycle number. necessary to look up the bricklet ID.
///
/// @param scanCycle (out) scan cycle number. necessary to look up the bricklet ID.
///
/// @param channel (out) channel name.
///
/// @return file type
/// @arg 0 result file (logbook)
/// @arg 1 result data file (bricklet)
///
/// result file names look like:
/// default_2015Apr20-124353_STM-STM_AtomManipulation_0001.mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation_0002.mtrx, etc.
/// the function returns the first part up to the experiment name ("AtomManipulation" in the examples).
/// all other return values set to defaults and must not be regarded.
///
/// result data files look like:
/// default_2015Apr20-124353_STM-STM_AtomManipulation--136_1.Aux1(V)_mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation--136_1.I(V)_mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation--14_1.I_mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation--14_1.Z_mtrx, etc.
/// the function returns all results as described in the parameter list.
///
function mtrx_parse_filename(fileName, resultFile, runCycle, scanCycle, channel)
string fileName
string &resultFile
variable &runCycle
variable &scanCycle
string &channel
variable fileType = 0
resultFile = ""
channel = ""
runCycle = 0
scanCycle = 0
string regexp = ""
string index1 = ""
string index2 = ""
string extension = ""
if (StringMatch(fileName, "*.mtrx"))
regexp = "(.+)_([[:digit:]]+)\.(.+)"
SplitString /E=regexp fileName, resultFile, index1, extension
fileType = 0
else
regexp = "(.+)--([[:digit:]]+)_([[:digit:]]+)\.((.+)_mtrx)"
SplitString /E=regexp fileName, resultFile, index1, index2, extension, channel
fileType = 1
runCycle = str2num(index1)
scanCycle = str2num(index2)
endif
return fileType
end
/// split a matrix filename and return the first three parts
///
/// we assume that the second (third) part contains the date (time).
/// the parts are separated by dash or underscore.
///
function /s mtrx_split_filename(fileName, prefix, datepart, timepart)
string fileName
string &prefix
string &datepart
string &timepart
string regexp
regexp = "([[:alpha:][:digit:]]+)[-_]([[:alpha:][:digit:]]+)[-_]([[:alpha:][:digit:]]+)[-_].+"
SplitString /E=regexp fileName, prefix, datepart, timepart
return datepart
end
/// create or look up a data folder based on a matrix file name.
///
/// the name of the folder is mtrx_date_time, where date and time are parsed from the file name.
/// for this to work, the file name must consist of at least three parts that are separated by dash or underscore.
/// the second (third) part contains the date (time).
/// date and time are copied as strings.
///
/// if the data folder exists, a reference to the existing folder is returned.
///
/// @param fileName name of the result or data file.
///
/// @param df_base (optional) base data folder.
/// default: current folder.
///
/// @return reference of the newly created or existing data folder.
///
function /df mtrx_create_folder(fileName, [df_base])
string fileName
dfref df_base
if (ParamIsDefault(df_base))
df_base = GetDataFolderDFR()
endif
string prefix
string datepart
string timepart
string folderName
mtrx_split_filename(fileName, prefix, datepart, timepart)
folderName = "mtrx_" + datepart + "_" + timepart
folderName = CleanupName(folderName, 0)
dfref df_save = GetDataFolderDFR()
setdatafolder root:
newdatafolder /o /s $foldername
dfref df = GetDataFolderDFR()
setdatafolder df_save
return df
end
/// create a data folder for bricklet data.
///
/// the name of the folder is, for example "r23s2" where the first (second) number is the run (scan) cycle.
/// run cycle and scan cycle numbers are taken from the open matrix file unless overridden by optional arguments.
///
/// if the data folder exists, a reference to the existing folder is returned.
/// if one of the run or scan cycle numbers is lower than 1, the base folder is returned.
///
/// @param df_base (optional) base data folder.
/// default: current folder.
///
/// @param runCycle (optional) run cycle number. must be >= 1.
/// default: from last mtrx_open_file call.
///
/// @param scanCycle (optional) scan cycle number. must be >= 1.
/// default: from last mtrx_open_file call.
///
/// @return reference of the newly created or existing data folder.
///
function /df mtrx_get_cycle_folder([df_base, runCycle, scanCycle])
dfref df_base
variable runCycle
variable scanCycle
dfref df_save = GetDataFolderDFR()
dfref df_pack = $(package_path)
if (ParamIsDefault(df_base))
df_base = GetDataFolderDFR()
endif
if (ParamIsDefault(runCycle))
nvar /sdfr=df_pack defRunCycle = runCycle
runCycle = defRunCycle
endif
if (ParamIsDefault(scanCycle))
nvar /sdfr=df_pack defScanCycle = scanCycle
scanCycle = defScanCycle
endif
string dfname
if ((runCycle >= 1) && (scanCycle >= 1))
sprintf dfname, "r%us%u", runCycle, scanCycle
setdatafolder df_base
dfref df = $dfname
if (DataFolderRefStatus(df) == 0)
newdatafolder $dfname
dfref df = $dfname
endif
else
dfref df = df_base
endif
setdatafolder df_save
return df
end
/// find out bricklet ID of a file
///
/// @warning EXPERIMENTAL
/// the code of this function is inefficient.
/// the function may be removed in a later version.
///
/// @param resultFile base name of result file without chain link number and extension.
/// as returned by mtrx_parse_filename.
///
/// @param runCycle requested run cycle.
/// 0 = first available.
///
/// @param scanCycle requested scan cycle.
/// 0 = first available.
///
/// @param channel channel name. for example: "I", "Z", "Aux(V)", etc.
/// empty string: first available.
///
/// @return bricklet ID, or -1 if an error occurred.
///
function mtrx_file_brickletID(resultFile, runCycle, scanCycle, channel)
string resultFile
variable runCycle
variable scanCycle
string channel
dfref df_overview = NewFreeDataFolder()
variable link = 1
variable id = -1
variable idx = 0
string resultFileName
#if exists("MFR_OpenResultFile")
struct errorCode errorCode
initStruct(errorCode)
do
sprintf resultFileName, "%s_%04u.mtrx", resultFile, link
MFR_OpenResultFile /K resultFileName
if(V_flag != errorCode.SUCCESS)
return -1
endif
MFR_CreateOverviewTable /DEST=df_overview
// dimension labels are: brickletID, scanCycleCount, runCycleCount, sequenceID, dimension, channelName
wave /t /sdfr=df_overview overviewTable
make /n=(dimsize(overviewTable, 0)) /i /u /free runcycles, scancycles, ids, match
make /n=(dimsize(overviewTable, 0)) /t /free channels
ids = str2num(overviewtable[p][%brickletID])
if (runcycle > 0)
runcycles = str2num(overviewtable[p][%runCycleCount])
else
runcycles = runcycle
endif
if (scancycle > 0)
scancycles = str2num(overviewtable[p][%scanCycleCount])
else
scancycles = scancycle
endif
if (strlen(channel) > 0)
channels = overviewTable[p][%channelName]
else
channels = channel
endif
Extract /FREE ids, match_ids, (scancycles == scanCycle) && (runcycles == runCycle) && (cmpstr(channels, channel) == 0)
if (numpnts(match_ids) > 0)
id = match_ids[0]
else
link += 1
endif
while (id < 0)
#endif
return id
end
/// open a matrix result or data file
///
/// this function opens a matrix result file (.mtrx) or data file (.*_mtrx).
///
/// if a data file is selected, the function locates the corresponding result file, opens it,
/// and looks up the bricklet ID of the data file.
/// if a result file is selected, the function opens it but does not look up bricklet IDs.
///
/// the result file remains open and can be accessed using the mtrx_ functions or MFR_ operations.
/// once a result file is open, you can easily access any bricklets linked to it,
/// i.e., any run cycle, scan cycle, and channel.
///
/// the function stores information about the opened file in a global package data folder.
/// if the same result file is opened again later, the information is reused and the file not read again.
/// this may cause problems if the file has been modified in the meantime,
/// or if the cached data become corrupt for some reason.
/// the function detects if a data file is not linked in the open result file, and updates the cache.
/// in other situations it may be necessary to force a reload.
///
/// @todo fix possible cache issues, add an option to override the cache.
///
/// @param pathName igor path name or empty string.
///
/// @param fileName file name, with or without path, or empty string.
///
/// @return file type
/// @arg 0 result file (logbook)
/// @arg 1 result data file (bricklet)
/// @arg -1 error, no data loaded
/// @arg -2 matrixfilereader.xop not installed
///
function mtrx_open_file(pathName, fileNameOrPath)
string pathName
string fileNameOrPath
check_package_folder()
dfref df_save = GetDataFolderDFR()
dfref df_pack = $(package_path)
svar /sdfr=df_pack dataFilePath
svar /sdfr=df_pack resultFilePath
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
string loc_resultFileName
string loc_resultFilePath
variable loc_runCycle
variable loc_scanCycle
string loc_channelName
// make sure we have a valid and complete file path
GetFileFolderInfo /P=$pathName /Q /Z=2 fileNameOrPath
string filePath
if ((v_flag == 0) && (v_isFile))
filePath = s_path
else
return -1
endif
// get base file name
string fileName
string fileDir
string baseFileName
variable fileType
fileName = ParseFilePath(0, filePath, ":", 1, 0)
fileDir = ParseFilePath(1, filePath, ":", 1, 0)
fileType = mtrx_parse_filename(fileName, baseFileName, loc_runCycle, loc_scanCycle, loc_channelName)
variable link = 1
variable id = -1
variable result = -1
variable using_cache = 0
struct errorCode errorCode
initStruct(errorCode)
do
sprintf loc_resultFileName, "%s_%04u.mtrx", baseFileName, link
loc_resultFilePath = fileDir + loc_resultFileName
#if exists("MFR_OpenResultFile")
if ((strlen(resultFilePath) == 0) || (cmpstr(loc_resultFilePath, resultFilePath) != 0))
MFR_OpenResultFile /K loc_resultFilePath
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
result = -1
break
endif
resultFilePath = loc_resultFilePath
if (fileType == 1)
dataFilePath = filePath
else
dataFilePath = ""
endif
runCycle = 0
scanCycle = 0
channelName = ""
brickletID = 0
MFR_CreateOverviewTable /DEST=df_pack
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
result = -1
break
endif
using_cache = 0
else
using_cache = 1
endif
#else
print "matrixfilereader.xop not installed"
result = -2
break
#endif
// dimension labels are: brickletID, scanCycleCount, runCycleCount, sequenceID, dimension, channelName
wave /t /sdfr=df_pack overviewTable
make /n=(dimsize(overviewTable, 0)) /i /u /o df_pack:runCycles, df_pack:scanCycles, df_pack:ids
make /n=(dimsize(overviewTable, 0)) /t /o df_pack:channels
wave /sdfr=df_pack ids, runCycles, scanCycles
wave /t /sdfr=df_pack channels
ids = str2num(overviewtable[p][%brickletID])
runCycles = str2num(overviewtable[p][%runCycleCount])
scanCycles = str2num(overviewtable[p][%scanCycleCount])
channels = overviewTable[p][%channelName]
result = fileType
// if a data file is opened, make sure we found the right result file
if ((loc_runCycle > 0) && (loc_scanCycle > 0))
Extract /FREE ids, match_ids, (runCycles == loc_runCycle) && (scanCycles == loc_scanCycle) && (cmpstr(channels, loc_channelName) == 0)
if (numpnts(match_ids) > 0)
id = match_ids[0]
runCycle = loc_runCycle
scanCycle = loc_scanCycle
channelName = loc_channelName
brickletID = id
break
elseif (using_cache)
resultFilePath = ""
else
link += 1
endif
else
break
endif
while (id < 0)
return result
end
/// load a preview image from a Matrix data file.
///
/// the data wave is loaded into the current data folder.
///
/// @param destName destination wave name. the wave is created in the current data folder.
///
/// @param pathName igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed
///
/// @param fileName if empty a dialog box shows up
/// the file name must adhere to the format
/// "{prefix}-{date}-{time}-{anything}--{run_cycle}_{scan_cycle}.{extension}".
/// the first three seperators can alternatively be underscores.
/// it may be necessary to change the configuration of the Matrix application.
///
/// @param traces (currently not used) semicolon-separated list of preferred traces.
/// the items of the list are match strings for the Igor StringMatch function.
/// only the first matching trace is loaded from the file.
/// default: "*Up;*Down;*ReUp;*ReDown;"
///
/// @return semicolon-separated list of loaded waves including partial path from current data folder.
///
function /s mtrx_load_preview(destName, pathName, fileName, [traces])
string destName
string pathName
string fileName
string traces
if (ParamIsDefault(traces))
traces = "*Up;*Down;*ReUp;*ReDown;"
endif
dfref df_save = GetDataFolderDFR()
string datanames = ""
string datapaths = ""
variable filestatus = mtrx_open_file(pathName, fileName)
if (filestatus != 1)
return ""
endif
dfref df_pack = $(package_path)
svar /sdfr=df_pack dataFilePath
svar /sdfr=df_pack resultFilePath
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
#if exists("MFR_OpenResultFile")
dfref df_data = df_save
variable /g df_data:V_MatrixFileReaderOverwrite = 1
variable /g df_data:V_MatrixFileReaderFolder = 0
variable /g df_data:V_MatrixFileReaderDouble = 0
struct errorCode errorCode
initStruct(errorCode)
MFR_GetBrickletData /N=destName /R=(brickletID) /S=2 /DEST=df_data
if(V_flag == errorCode.SUCCESS)
datanames = S_waveNames
variable i
variable n = ItemsInList(datanames)
string s
s = StringFromList(0, datanames)
wave data = $s
mtrx_scale_dataset(data)
if (WaveDims(data) == 2)
subtract_line_bg(data)
endif
datapaths = AddListItem(GetWavesDataFolder(data, 4), datapaths, ";", inf)
for (i = 1; i < n; i += 1)
s = StringFromList(i, datanames)
killwaves /z $s
endfor
else
MFR_GetXOPErrorMessage
endif
//MFR_GetBrickletMetaData /N=ANickName /R=(brickletID) // /DEST=dfref
#else
print "matrixfilereader.xop not installed"
#endif
setdatafolder df_save
return datapaths
end
/// load all data from a Matrix data file.
///
/// the data wave is loaded into a sub-subfolder the current data folder.
/// the relative path has the format ":mtrx_{date}_{time}:r{run_cycle}s{scan_cycle}",
/// where the parameters {date}, {time}, {run_cycle} and {scan_cycle} are copied from the file name.
/// the file name must be formatted according to the specifications set out below.
///
/// @param pathName igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed
///
/// @param fileName if empty a dialog box shows up
/// the file name must adhere to the format
/// "{prefix}-{date}-{time}-{anything}--{run_cycle}_{scan_cycle}.{extension}".
/// the first three seperators can alternatively be underscores.
/// it may be necessary to change the configuration of the Matrix application.
///
/// @param traces (currently not used) semicolon-separated list of preferred traces.
/// the items of the list are match strings for the Igor StringMatch function.
/// only matching traces are loaded from the file.
/// default: "*Up;*Down;*ReUp;*ReDown;"
///
/// @return semicolon-separated list of loaded waves including partial path from current data folder.
///
function /s mtrx_load_file(pathName, fileName, [traces])
string pathName
string fileName
string traces
if (ParamIsDefault(traces))
traces = "*Up;*Down;*ReUp;*ReDown;"
endif
dfref df_save = GetDataFolderDFR()
string datanames = ""
string datapaths = ""
variable filestatus = mtrx_open_file(pathName, fileName)
if (filestatus != 1)
return ""
endif
dfref df_pack = $(package_path)
svar /sdfr=df_pack dataFilePath
svar /sdfr=df_pack resultFilePath
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
#if exists("MFR_OpenResultFile")
string resultFileName = ParseFilePath(0, resultFilePath, ":", 1, 0)
dfref df_result = mtrx_create_folder(resultFileName, df_base=df_save)
dfref df_data = mtrx_get_cycle_folder(df_base = df_result)
variable /g df_data:V_MatrixFileReaderOverwrite = 1
variable /g df_data:V_MatrixFileReaderFolder = 0
variable /g df_data:V_MatrixFileReaderDouble = 0
struct errorCode errorCode
initStruct(errorCode)
string name
name = CleanupName(channelName, 0)
MFR_GetBrickletData /N=name /R=(brickletID) /DEST=df_data
if(V_flag == errorCode.SUCCESS)
datanames = S_waveNames
variable i
variable n = ItemsInList(datanames)
string s
for (i = 0; i < n; i += 1)
s = StringFromList(i, datanames)
wave /sdfr=df_data data = $s
mtrx_scale_dataset(data)
datapaths = AddListItem(GetWavesDataFolder(data, 4), datapaths, ";", inf)
endfor
else
MFR_GetXOPErrorMessage
endif
//MFR_GetBrickletMetaData /N=ANickName /R=(brickletID) // /DEST=dfref
#else
print "matrixfilereader.xop not installed"
#endif
setdatafolder df_save
return datapaths
end
function mtrx_scale_dataset(data)
wave data
dfref df_pack = $(package_path)
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
string scanDir = StringFromList(2, NameOfWave(data), "_")
if (WaveDims(data) == 2)
Note data, "AxisLabelX=X"
Note data, "AxisLabelY=Y"
endif
Note data, "AxisLabelD=" + channelName
string title
sprintf title, "%u-%u %s %s", runCycle, scanCycle, channelName, scanDir
Note data, "Dataset=" + title
end
/// load descriptive info from a Matrix data file.
///
/// the info string lists the following information for each scan contained in the file:
/// - path of the scan group inside the file.
/// - number of scan positions.
/// - dataset names of scan positioners.
/// - dataset names of detectors.
///
/// @param APathName igor symbolic path name. can be empty if the path is specified in AFileName or a dialog box should be displayed
///
/// @param AFileName if empty a dialog box shows up
///
/// @return newline terminated string.
///
function /s mtrx_load_info(APathName, AFileName)
string APathName
string AFileName
dfref saveDF = GetDataFolderDFR()
dfref fileDF = NewFreeDataFolder()
setdatafolder fileDF
variable fileID
string filepath
string scanpaths
variable nscans
variable iscan
string scanpath
string info = ""
setdatafolder saveDF
return info
end
/// remove linear background line-by-line
///
function subtract_line_bg(img)
wave img
variable nx = dimsize(img, 0)
variable ny = dimsize(img, 1)
variable iy
make /n=(nx) /free line, fit
for (iy = 0; iy < ny; iy += 1)
line = img[p][iy]
if (numtype(sum(line)) == 0)
CurveFit /N /Q /NTHR=0 line line /D=fit
img[][iy] = line[p] - fit[p]
endif
endfor
end

View File

@ -1539,6 +1539,35 @@ function ps_detect_scale(ax, lo, hi, un)
lo[%$kScanDimLabel] = scanner[0]
hi[%$kScanDimLabel] = scanner[numpnts(scanner)-1]
ax[%$kScanDimLabel] = NameOfWave(scanner)
strswitch(NameOfWave(scanner))
case "Eph":
ax[%$kScanDimLabel] = "photon energy"
un[%$kScanDimLabel] = "eV"
break
case "ManipulatorX":
case "ManipulatorY":
case "ManipulatorZ":
case "FocusYTrans":
case "FocusZTrans":
case "RefocusYTrans":
case "RefocusZTrans":
case "ExitSlitY":
un[%$kScanDimLabel] = "mm"
case "ExitSlit":
un[%$kScanDimLabel] = "µm"
break
case "ManipulatorTheta":
case "ManipulatorTilt":
case "ManipulatorPhi":
un[%$kScanDimLabel] = "°"
case "FocusXRot":
case "FocusYRot":
case "FocusZRot":
case "RefocusXRot":
case "RefocusYRot":
case "RefocusZRot":
un[%$kScanDimLabel] = "mrad"
endswitch
endif
endif
end
@ -1600,8 +1629,24 @@ function ps_scale_dataset_2(data, ax, lo, hi, un)
Note data, "AxisLabelZ=" + ax[%$sdim]
endif
setscale d 0, 0, un[%$kDataDimLabel], data
Note data, "AxisLabelD=" + ax[%$kDataDimLabel]
string data_unit = un[%$kDataDimLabel]
string data_label = ax[%$kDataDimLabel]
if (cmpstr(data_unit, "arb.") == 0)
strswitch(NameOfWave(data))
case "SampleCurrent":
case "RefCurrent":
case "AuxCurrent":
data_unit = "A"
data_label = "current"
break
case "MachineCurrent":
data_unit = "mA"
data_label = "current"
break
endswitch
endif
setscale d 0, 0, data_unit, data
Note data, "AxisLabelD=" + data_label
Note data, "Dataset=" + NameOfWave(data)
end
@ -1674,21 +1719,35 @@ function /s psh5_load_reduced(ANickName, APathName, AFileName, reduction_func, r
variable ig = 0
variable ng = ItemsInList(s_scanpaths)
string sg
string scanpath
string folder
string positioners
string positioner
string positionerpath
sg = StringFromList(ig, s_scanpaths)
folder = ReplaceString("/", sg, "")
scanpath = StringFromList(ig, s_scanpaths)
folder = ReplaceString("/", scanpath, "")
folder = ReplaceString(" ", folder, "")
folder = CleanupName(folder, 0)
setdatafolder fileDF
newdatafolder /s /o $folder
dfref dataDF = GetDataFolderDFR()
psh5_load_scan_meta(fileID, sg)
positioners = psh5_load_scan_meta(fileID, scanpath)
newdatafolder /s /o attr
psh5_load_scan_attrs(fileID, sg)
killwaves /a/z
psh5_load_scan_attrs(fileID, scanpath)
setdatafolder dataDF
wavenames = psh5_load_dataset_reduced(fileID, sg, "ScientaImage", reduction_func, reduction_param, progress=progress)
wave /t /z ScanWritables
if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
positioner = ScanWritables[0]
if (strlen(positioner) > 0)
positionerpath = scanpath + "/" + positioner
positionerpath = ReplaceString("//", positionerpath, "/")
HDF5LoadData /O /Q /Z fileID, positionerpath
endif
endif
setdatafolder dataDF
wavenames = psh5_load_dataset_reduced(fileID, scanpath, "ScientaImage", reduction_func, reduction_param, progress=progress)
psh5_close_file(fileID)
endif
@ -1803,9 +1862,7 @@ function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_f
ny = di.dims[idy]
nz = di.dims[idz]
nt = di.dims[idt]
make /n=(nx,ny,nz,nt) /o $datawavename /wave=data
// adjust nz and nt *after* making the data wave
// adjust singleton dimensions
nz = max(nz, 1)
nt = max(nt, 1)
nzt = nz * nt

View File

@ -703,3 +703,99 @@ function scienta_poly_bg(w, e, a): fitfunc
return bg * (base + pk1 + pk2 + pk3)
end
/// parameter dialog for the redim_linbg_reduction() function
///
/// @param param parameter string in a key1=value1;key2=value2;... list.
/// the parameter string is passed by reference.
/// see redim_linbg_reduction() for a description of parameters.
///
/// @return zero if the user clicked OK, non-zero if the user clicked Cancel.
///
function prompt_redim_linbg_reduction(param)
string &param
variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
variable Lsize = NumberByKey("Lsize", param, "=", ";")
variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
variable Hsize = NumberByKey("Hsize", param, "=", ";")
variable Cpos = NumberByKey("Cpos", param, "=", ";")
variable Csize = NumberByKey("Csize", param, "=", ";")
prompt Lcrop, "Lower cropping region"
prompt Hcrop, "Upper cropping region"
prompt Lsize, "Lower background region"
prompt Hsize, "Upper background region"
prompt Cpos, "Center position"
prompt Csize, "Center integration region"
doprompt "redim_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
if (v_flag == 0)
param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
endif
return v_flag
end
/// linear background reduction function for incorrectly dimensioned scienta image
///
/// if the energy step size does not divide the energy range to an integer number,
/// the scienta image is exported with the wrong array size.
/// this can be fixed by redimensioning the array.
///
/// the current implementation works in the case where dimension 0 needs to be incremented.
/// the function may be generalized to dimension 1 and/or decrementing by additional parameters.
/// it is not known yet whether a generalization is needed or whether it can cover all cases.
///
/// background subtraction and peak integration is the same as by the int_linbg_reduction() function.
///
/// @param source source wave
/// Scienta detector image, energy axis along X, angle axis along Y
///
/// @param dest1 destination wave 1
///
/// @param dest2 destination wave 2
/// each wave is a one-dimensional intensity distribution
/// the function may redimension these waves to one of the image dimensions
/// (it must be clear to the user which dimension this is).
/// the meaning of dest1 and dest2 is up to the particular function,
/// e.g. dest1 could hold the mean value and dest2 the one-sigma error,
/// or dest1 could hold the X-profile, and dest2 the Y-profile.
///
/// @param param parameter string in a key1=value1;key2=value2;... list.
/// the parameter string is passed by reference.
///
/// all region parameters are relative to the image size (0...1).
/// @arg Lcrop size of the lower cropping region
/// @arg Hcrop size of the upper cropping region
/// @arg Lsize size of the lower background integration region
/// @arg Hsize size of the upper background integration region
/// @arg Cpos center position of the of the peak integration region
/// @arg Csize size of the peak integration region
///
/// typical values (peak centered on detector, FWHM ~ 20 % of image)
/// Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2
///
/// @return zero if successful, non-zero if an error occurs.
///
threadsafe function redim_linbg_reduction(source, dest1, dest2, param)
wave source
wave dest1, dest2
string &param
variable nx = dimsize(source, 0)
variable ny = dimsize(source, 1)
duplicate /free source, source_redim
redimension /n=(nx * ny) source_redim
nx += 1
redimension /n=(nx, ny) source_redim
return int_linbg_reduction(source_redim, dest1, dest2, param)
end