11 Commits

Author SHA1 Message Date
9a65d26984 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
2017-02-02 15:31:13 +01:00
c8a69460bc updates: igor 7, map projections, hemi cuts, longitudinal section
- pearl procedures compile under igor 7.
  some features may not work, e.g. 3D graphics with gizmo.
- add orthographic map projection to angle scans.
- add functions for azimuthal and polar cuts through hemispherical scan.
- add function to load longitudinal section from pshell data file.
2016-10-14 16:56:20 +02:00
600061f684 bugfixes in pshell import and preview
changes:
- fix null string exception in preview
- fix transposition of two-dimensional datasets
2016-09-23 19:11:07 +02:00
0dc6ca820b bugfix release: pshell import and preview
changes:
- catch runtime errors due to empty datasets
- improve window titles and graph names
- fix scaling of scienta image from XPSSpectrum script
- remove unnecessary spaces and underscores from folder names
2016-09-22 14:15:09 +02:00
a87975d1e6 update data explorer: axis scale and labels in preview 2016-08-17 12:12:52 +02:00
86cf328961 README.md: fix heading levels 2016-06-06 16:07:19 +02:00
2479582c08 README.md: add release notes 2016-06-06 16:04:56 +02:00
02709fd4df maintenance release: pshell import, elog, documentation
* bugfixes in pshell import
* updates to elog interface: templates, login, separate persistent and volatile data
* new header and revision information in documentation
2016-06-03 12:06:04 +02:00
724c73ef19 remove unnecessary files and dependencies
* remove unit tests (require third-party testing framework)
* remove sample preparation (require EPICS.XOP)
* remove scans and live view (require EPICS.XOP)

these files are useful for hard-core developers or on-site only.
for all off-site use, broken dependencies cause unnecessary problems.
contact the PEARL staff if you need to use one of the omitted files.
2016-04-22 13:53:26 +02:00
fcd6a56e4e new feature: preview and import of pshell data files 2016-04-09 13:07:37 +02:00
29d4b6881f new angle-scan processing features, update documentation, bugfixes
new functions:
- voigt_fwhm_lor
- rotate_hemi_scan
- import_tpi_scan
- draw_diffraction_cone

updated functions:
- interpolate_hemi_scan
- display_hemi_scan
- duplicate_hemi_scan

updated documentation:
- installation instructions
- readme
2016-03-30 12:02:57 +02:00
28 changed files with 6001 additions and 3405 deletions

20
.gitattributes vendored Normal file
View File

@ -0,0 +1,20 @@
.git* export-ignore
#*.ipf diff=igorpro
# git diff --check should output something useful
*.ipf whitespace=indent-with-non-tab,tabwidth=4
# mark files as binary
# you can also add -delta if you regularly
# commit large files of these types
*.ibw binary
*.xop binary
*.pxp binary
*.pxt binary
*.uxp binary
*.uxt binary
*.ihf binary
*.ifn binary
*.ift binary
# automatic end of line normalization
*.ipf eol=lf

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
*.ipfT* *.ipfT*
doc/html/* doc/html/*
doc/latex/* doc/latex/*

47
README.md Normal file
View File

@ -0,0 +1,47 @@
Introduction
============
PEARL Procedures is a suite of Igor Pro procedures developed for data acquisition and data processing at the PEARL beamline at the Swiss Light Source.
Installation
============
PEARL Procedures should be installed according to the regular Igor Pro guidelines. Please read the Igor help `About Igor Pro User Files` for details.
- Make a `pearl-procs` directory in your private or shared `User Procedures` folder, and copy the PEARL Procedures distribution there.
- Create shortcuts of the `pearl-arpes.ipf` and `pearl-menu.ipf` files, and move them to the `Igor Procedures` folder next to your `User Procedures` folder.
- Find the `HDF5.XOP` (`HDF5-64.xop` for Igor 7 64-bit) extension in the `Igor Pro Folder` under `More Extensions/File Loaders` (`More Extensions (64-bit)/File Loaders`), create a shortcut, and move the shortcut to the `Igor Extensions` folder next to your `User Procedures` folder.
- Find the `HDF5 Help.ihf` next to `HDF5.XOP`, create a shortcut, and move the shortcut to the `Igor Help Files` folder next to your `User Procedures` folder.
PEARL Procedures has been tested under Igor Pro version 6.37 (32-bit). Older versions prior to 6.36 are not be compatible. Please update to the latest Igor Pro 6 version before reporting any problems.
PEARL Procedures compiles under Igor 7.00. Some features, in particular 3D graphics, may not work properly.
License
=======
The source code of PEARL Procedures is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) at <https://git.psi.ch/pearl-public/igor-procs>.
Please read and respect the respective license agreements.
Please share your extensions of the code with the original author.
Author
------
Matthias Muntwiler, <mailto:matthias.muntwiler@psi.ch>
Copyright
---------
Copyright 2009-2016 by [Paul Scherrer Institut](http://www.psi.ch)
Release Notes
=============
## rev-distro-1.1.1
- If you have upgraded PEARL Procedures from pre-1.1.1 and Igor breaks in pearl-elog.ipf while opening an experiment, please delete the ELOG preferences file `pearl-elog/preferences.pxp`. (Check the Igor Help to find the package preferences folder on your system.)

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "PEARL Procedures"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = PROJECT_NUMBER = $(REVISION)
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@ -758,7 +758,8 @@ WARN_LOGFILE =
# spaces. # spaces.
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = ../pearl INPUT = ../pearl \
src
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -778,7 +779,8 @@ INPUT_ENCODING = CP1252
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
# *.qsf, *.as and *.js. # *.qsf, *.as and *.js.
FILE_PATTERNS = *.ipf FILE_PATTERNS = *.ipf \
*.dox
# The RECURSIVE tag can be used to specify whether or not subdirectories should # The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well. # be searched for input files as well.
@ -863,7 +865,7 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added # code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly. # or removed, the anchors will not be placed correctly.
INPUT_FILTER = "gawk -f doxygen-filter-ipf.awk" INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the # basis. Doxygen will compare the file name with each pattern and apply the
@ -872,7 +874,7 @@ INPUT_FILTER = "gawk -f doxygen-filter-ipf.awk"
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the # filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied. # patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS = FILTER_PATTERNS = "*.ipf=\"gawk -f doxygen-filter-ipf.awk\""
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will also be used to filter the input files that are used for # INPUT_FILTER) will also be used to filter the input files that are used for
@ -1645,7 +1647,7 @@ EXTRA_PACKAGES =
# to HTML_HEADER. # to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER = LATEX_HEADER = src/header.tex
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last # generated LaTeX document. The footer should contain everything after the last

View File

@ -11,12 +11,15 @@ DOX=doxygen
DOXOPTS= DOXOPTS=
LATEX_DIR=latex LATEX_DIR=latex
REVISION=$(shell git describe --always --tags --dirty --long || echo "unknown, "`date +"%F %T %z"`)
export REVISION
all: docs all: docs
docs: doxygen pdf docs: doxygen pdf
doxygen: doxygen:
$(DOX) $(DOXOPTS) Doxyfile $(DOX) $(DOXOPTS) config.dox
pdf: doxygen pdf: doxygen
-$(MAKE) -C $(LATEX_DIR) -$(MAKE) -C $(LATEX_DIR)

149
doc/src/header.tex Normal file
View File

@ -0,0 +1,149 @@
% Latex header for doxygen 1.8.9.1
%
% To generate this file, call:
% doxygen -w latex header.tex footer.tex doxygen.sty
% and substitute the placeholders:
% $title, $datetime, $date, $doxygenversion, $projectname, $projectnumber, $projectbrief, $projectlogo
% (or diff and merge with previous version)
%
\documentclass[twoside]{book}
% Packages required by doxygen
\usepackage{fixltx2e}
\usepackage{calc}
\usepackage{doxygen}
\usepackage[export]{adjustbox} % also loads graphicx
\usepackage{graphicx}
\usepackage[utf8]{inputenc}
\usepackage{makeidx}
\usepackage{multicol}
\usepackage{multirow}
\PassOptionsToPackage{warn}{textcomp}
\usepackage{textcomp}
\usepackage[nointegrals]{wasysym}
\usepackage[table]{xcolor}
% Font selection
\usepackage[T1]{fontenc}
\usepackage[scaled=.90]{helvet}
\usepackage{courier}
\usepackage{amssymb}
\usepackage{sectsty}
\renewcommand{\familydefault}{\sfdefault}
\allsectionsfont{%
\fontseries{bc}\selectfont%
\color{darkgray}%
}
\renewcommand{\DoxyLabelFont}{%
\fontseries{bc}\selectfont%
\color{darkgray}%
}
\newcommand{\+}{\discretionary{\mbox{\scriptsize$\hookleftarrow$}}{}{}}
% Page & text layout
\usepackage{geometry}
\geometry{%
a4paper,%
top=2.5cm,%
bottom=2.5cm,%
left=2.5cm,%
right=2.5cm%
}
\tolerance=750
\hfuzz=15pt
\hbadness=750
\setlength{\emergencystretch}{15pt}
\setlength{\parindent}{0cm}
\setlength{\parskip}{0.2cm}
\makeatletter
\renewcommand{\paragraph}{%
\@startsection{paragraph}{4}{0ex}{-1.0ex}{1.0ex}{%
\normalfont\normalsize\bfseries\SS@parafont%
}%
}
\renewcommand{\subparagraph}{%
\@startsection{subparagraph}{5}{0ex}{-1.0ex}{1.0ex}{%
\normalfont\normalsize\bfseries\SS@subparafont%
}%
}
\makeatother
% Headers & footers
\usepackage{fancyhdr}
\pagestyle{fancyplain}
\fancyhead[LE]{\fancyplain{}{\bfseries\thepage}}
\fancyhead[CE]{\fancyplain{}{}}
\fancyhead[RE]{\fancyplain{}{\bfseries\leftmark}}
\fancyhead[LO]{\fancyplain{}{\bfseries\rightmark}}
\fancyhead[CO]{\fancyplain{}{}}
\fancyhead[RO]{\fancyplain{}{\bfseries\thepage}}
\fancyfoot[LE]{\fancyplain{}{}}
\fancyfoot[CE]{\fancyplain{}{}}
\fancyfoot[RE]{\fancyplain{}{\bfseries\scriptsize $projectnumber}}
\fancyfoot[LO]{\fancyplain{}{\bfseries\scriptsize $projectnumber}}
\fancyfoot[CO]{\fancyplain{}{}}
\fancyfoot[RO]{\fancyplain{}{}}
\renewcommand{\footrulewidth}{0.4pt}
\renewcommand{\chaptermark}[1]{%
\markboth{#1}{}%
}
\renewcommand{\sectionmark}[1]{%
\markright{\thesection\ #1}%
}
% Indices & bibliography
\usepackage{natbib}
\usepackage[titles]{tocloft}
\setcounter{tocdepth}{3}
\setcounter{secnumdepth}{5}
\makeindex
% Hyperlinks (required, but should be loaded last)
\usepackage{ifpdf}
\ifpdf
\usepackage[pdftex,pagebackref=true]{hyperref}
\else
\usepackage[ps2pdf,pagebackref=true]{hyperref}
\fi
\hypersetup{%
colorlinks=true,%
linkcolor=blue,%
citecolor=blue,%
unicode%
}
% Custom commands
\newcommand{\clearemptydoublepage}{%
\newpage{\pagestyle{empty}\cleardoublepage}%
}
%===== C O N T E N T S =====
\begin{document}
% Titlepage & ToC
\hypersetup{pageanchor=false,
bookmarks=true,
bookmarksnumbered=true,
pdfencoding=unicode
}
\pagenumbering{roman}
\begin{titlepage}
\vspace*{7cm}
\begin{center}%
{\Large $projectname}\\
\vspace*{1cm}
{\large $projectbrief }\\
\vspace*{0.5cm}
{\small Version $projectnumber}\\
\vspace*{0.5cm}
{\small $datetime}\\
\end{center}
\end{titlepage}
\clearemptydoublepage
\tableofcontents
\clearemptydoublepage
\pagenumbering{arabic}
\hypersetup{pageanchor=true}
%--- Begin generated contents ---

27
doc/src/mainpage.dox Normal file
View File

@ -0,0 +1,27 @@
/*! @mainpage Introduction
\section sec_intro Introduction
PEARL Procedures is a suite of Igor Pro procedures developed for data acquisition and data processing at the PEARL beamline at the Swiss Light Source.
\section sec_install Installation
PEARL Procedures should be installed according to the regular Igor Pro guidelines. Please read the Igor help `About Igor Pro User Files` for details.
- Make a `pearl-procs` directory in your private or shared `User Procedures` folder, and copy the PEARL Procedures distribution there.
- Create shortcuts of the `pearl-arpes.ipf` and `pearl-menu.ipf` files, and move them to the `Igor Procedures` folder next to your `User Procedures` folder.
- Find the `HDF5.XOP` extension in the `Igor Pro Folder` under `More Extensions/File Loaders`, create a shortcut, and move the shortcut to the `Igor Extensions` folder next to your `User Procedures` folder.
- Find the `HDF5 Help.ihf` next to `HDF5.XOP`, create a shortcut, and move the shortcut to the `Igor Help Files` folder next to your `User Procedures` folder.
\section sec_license License Information
An open distribution of PEARL Procedures is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) at <https://git.psi.ch/pearl-public/igor-procs>.
Users of PEARL Procedures are requested to coordinate and share the development of the code with the original author.
Please read and respect the respective license agreements.
\author Matthias Muntwiler, <mailto:matthias.muntwiler@psi.ch>
\version This documentation is compiled from version $(REVISION).
\copyright 2009-2016 by [Paul Scherrer Institut](http://www.psi.ch)
\copyright Licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
*/

97
mm/mm-physconst.ipf Normal file
View File

@ -0,0 +1,97 @@
#pragma rtGlobals=1 // Use modern global access method.
#pragma version = 1.05
// physical constants
// original version: 03-05-23 by mm
// $Id$
// source: CODATA 2002 [Rev. Mod. Phys. 77, 1 (2005)]
// universal constants
constant kSpeedOfLight = 2.99792458e8 // m/s
constant kMagnField = 1.25663706144e-6 // V s / A / m
constant kElField = 8.854187817620e-12 // A s / V / m
constant kGravitation = 6.6742e-11 // m^3 / kg / s^2
constant kHBar = 6.58211915e-16 // eV s
constant kPlanckBar = 6.58211915e-16 // eV s
constant kPlanck = 4.13566743e-15 // eV s
constant kHBarC = 197.326968 // MeV fm
constant kHC = 1239.84190605 // eV nm
constant kHCicm = 1239.84190605e-7 // eV cm^-1
constant kPlanckBarSI = 1.05457168e-34 // J s
constant kPlanckSI = 6.6260693e-34 // J s
// electromagnetic constants
constant kElCharge = 1.60217653e-19 // A s
constant kMagnFlux = 2.06783372e-15 // Wb
constant kConductance = 7.748091733e-5 // S
constant kBohrMagneton = 5.788381804e-5 // eV T^-1
constant kBohrMagnetonSI = 9.27400949e-24 // J T^-1 = A m^2
constant kNuclearMagneton = 3.152451259e-8 // eV T^-1
constant kNuclearMagnetonSI = 5.05078343e-27 // J T^-1
// atomic and nuclear constants
constant kFineStruct = 7.297352568e-3
constant kInvFineStruct = 137.03599911
constant kRydberg = 10973731.568525 // m^-1
constant kRydbergEnergy = 13.6056923 // eV
constant kBohrRadius = 0.5291772108e-10 // m
constant kHartreeEnergy = 27.2113845 // eV
constant kHartreeEnergySI = 4.35974417 // J
constant kElectronMass = 510.998918e3 // eV c^-2
constant kMuonMass = 105.6583692e6 // eV c^-2
constant kProtonMass = 938.272029e6 // eV c^-2
constant kNeutronMass = 939.565360e6 // eV c^-2
constant kElectronMassSI = 9.1093826e-31 // kg
constant kProtonMassSI = 1.67262171e-27 // kg
constant kComptonWavelength = 2.426310238e-12 // m
constant kElectronRadius = 2.817940325e-15 // m
constant kThomsonCrossSection = 0.665245873e-28 // m^2
constant kElectronGFactor = -2.0023193043718
// physico-chemical constants
constant kAvogadro = 6.0221415e23 // 1 / mol
constant kAtomicMassUnit = 931.494043e6 // eV / c^2
constant kAtomicMassUnitSI = 1.66053886e-27 // kg
constant kMolarGasSI = 8.314472 // J / K / mol
constant kBoltzmann = 8.617343e-5 // eV / K
constant kBoltzmannSI = 1.3806505e-23 // J /K
constant kWien = 2.8977685e-3 // m K
constant kStefanBoltzmann = 5.670400e-8 // W m^-2 K^-4
constant kJoulesPerEV = 1.60217653e-19 // J / eV
constant kEVPerHartree = 27.2113845 // eV / Eh
// custom constants
constant kFreeElectronDispersion = 3.79736 // eV Angstrom^2
// = h_bar^2 * c^2 / (2 * m_e)
// for E = kFreeElectronDispersion * k^2
threadsafe function FreeElectronWavelength(ekin, [v0, meff])
// Wavelength of a quasi-free electron in meters
variable ekin // kinetic energy of the electron in eV
variable v0 // inner potential (where applicable), default = 0
variable meff // effective mass relative to free electron, default = 1
if (ParamIsDefault(v0))
v0 = 0
endif
if (ParamIsDefault(meff))
meff = 1
endif
return khc * 1e-9 / sqrt(2 * kElectronMass * meff * (ekin + v0))
end

View File

@ -1,80 +0,0 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlAnglescanProcessTest
#pragma version = 1.0
#include "pearl-anglescan-process"
#include "unit-testing"
// test suite for pearl-anglescan-process.ipf
// unit testing framework: http://www.igorexchange.com/project/unitTesting
// run all test cases with RunTest("pearl-anglescan-process.ipf")
// if wave equalities fail, EnableDebugOutput() and read Igor help on equalWaves().
// created: matthias.muntwiler@psi.ch, 2013-11-18
// Copyright (c) 2013 Paul Scherrer Institut
// $Id$
static function test_convert_angles_ttpa()
// function parameters
variable ntests = 3
make /n=(ntests)/d/free i_theta, i_tilt, i_phi
make /n=3/d/free i_ana
make /n=1/d/free o_polar, o_azi
i_theta = {0, 90, 90}
i_tilt = {0, 0, 0}
i_phi = {0, 0, 10}
i_ana = {-30, 0, +30}
make /n=(3,ntests)/d/free e_polar, e_azi
e_polar[][0] = {30, 0, 30}
e_azi[][0] = {-90, 0, 90} // 180, 90, 0
e_polar[][1] = {90, 90, 90}
e_azi[][1] = {-30, 0, +30}
e_polar[][2] = {90, 90, 90}
e_azi[][2] = {-20, 10, +40}
variable phi0 = 0
e_azi += phi0
convert_angles_ttpa2polar(i_theta, i_tilt, i_phi, i_ana, o_polar, o_azi)
CHECK_EQUAL_WAVES(o_polar, e_polar, tol=0.001)
CHECK_EQUAL_WAVES(o_azi, e_azi, tol=0.001)
nvar /z errors = root:packages:unittesting:error_count
if ((nvar_exists(errors)) && (errors > 0))
print o_azi
print e_azi
endif
end
static function test_hist_hemi_aziscan()
CHECK_EMPTY_FOLDER()
make /n=360/d/free value, azi
azi = p
value = 1
variable polar = 45 // dphi = 2
make_hemi_grid(91, "")
wave w_index = index
wave w_nphis = nphis
wave w_dphi = dphi
wave w_values = values
wave w_azim = azim
wave w_polar = polar
duplicate /free w_values, e_values
variable p1 = w_index[44]
variable p2 = w_index[45]
e_values = (p >= p1) && (p < p2) ? 1 : 0
hemi_add_aziscan("", value, polar, azi)
CHECK_EQUAL_WAVES(w_values, e_values, tol=0.001)
end

View File

@ -6,14 +6,14 @@
#include "pearl-polar-coordinates" #include "pearl-polar-coordinates"
#include <New Polar Graphs> #include <New Polar Graphs>
// $Id$ // copyright (c) 2013-16 Paul Scherrer Institut
//
// copyright (c) 2013-15 Paul Scherrer Institut
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// http:///www.apache.org/licenses/LICENSE-2.0 // http:///www.apache.org/licenses/LICENSE-2.0
//
// Please acknowledge the use of this code.
/// @file /// @file
/// @brief processing and holographic mapping of angle scanned XPD data. /// @brief processing and holographic mapping of angle scanned XPD data.
@ -64,7 +64,7 @@
/// ///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch /// @author matthias muntwiler, matthias.muntwiler@psi.ch
/// ///
/// @copyright 2013-15 Paul Scherrer Institut @n /// @copyright 2013-16 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @n /// 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 not use this file except in compliance with the License. @n
/// You may obtain a copy of the License at /// You may obtain a copy of the License at
@ -79,15 +79,38 @@
/// ///
/// PearlAnglescanProcess is declared in @ref pearl-anglescan-process.ipf. /// PearlAnglescanProcess is declared in @ref pearl-anglescan-process.ipf.
/// @warning experimental
function strip_remove_frames(strip, yscale, ylo, yhi) /// delete a contiguous range of frames from a strip.
///
/// this can be used to remove a region of bad frames due to, e.g., measurement problems.
/// the function operates on 2D intensity data and manipulator coordinates at the same time.
///
/// @param[in,out] strip 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan.
/// the result is written to the original wave.
///
/// @param[in,out] theta 1D data, manipulator scan.
/// the result is written to the original wave.
///
/// @param[in,out] tilt 1D data, manipulator scan.
/// the result is written to the original wave.
///
/// @param[in,out] phi 1D data, manipulator scan.
/// the result is written to the original wave.
///
/// @param[in] qlo point index of first frame to delete.
///
/// @param[in] qhi point index of last frame to delete.
/// qhi must be greater or equal than qlo.
///
function strip_delete_frames(strip, qlo, qhi, theta, tilt, phi)
wave strip // 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan wave strip // 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
wave /z yscale // Y scaling, e.g. ManipulatorPhi variable qlo
// if unassigned, point scaling is assumed variable qhi
variable ylo wave theta
variable yhi wave tilt
wave phi
if (ylo > yhi) if (qlo > qhi)
return -1 return -1
endif endif
@ -95,8 +118,8 @@ function strip_remove_frames(strip, yscale, ylo, yhi)
variable snx = dimsize(strip, 0) variable snx = dimsize(strip, 0)
variable sny = dimsize(strip, 1) variable sny = dimsize(strip, 1)
variable sq1lo = 0 variable sq1lo = 0
variable sq1hi = max(round((ylo - dimoffset(strip, 1)) / dimdelta(strip, 1)), 0) variable sq1hi = max(qlo-1, 0)
variable sq2lo = min(round((ylo - dimoffset(strip, 1)) / dimdelta(strip, 1)), sny - 1) variable sq2lo = min(qhi+1, sny - 1)
variable sq2hi = dimsize(strip, 1) - 1 variable sq2hi = dimsize(strip, 1) - 1
// dest indices // dest indices
@ -111,10 +134,24 @@ function strip_remove_frames(strip, yscale, ylo, yhi)
duplicate /free strip, strip_copy duplicate /free strip, strip_copy
redimension /n=(dnx,dny) strip redimension /n=(dnx,dny) strip
strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs] strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs]
strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs] strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs]
duplicate /free theta, theta_copy
redimension /n=(dny) theta
theta[dq1lo,dq1hi] = theta_copy[p + q1ofs]
theta[dq2lo,dq2hi] = theta_copy[p + q2ofs]
duplicate /free tilt, tilt_copy
redimension /n=(dny) tilt
tilt[dq1lo,dq1hi] = tilt_copy[p + q1ofs]
tilt[dq2lo,dq2hi] = tilt_copy[p + q2ofs]
duplicate /free phi, phi_copy
redimension /n=(dny) phi
phi[dq1lo,dq1hi] = phi_copy[p + q1ofs]
phi[dq2lo,dq2hi] = phi_copy[p + q2ofs]
return 0 return 0
end end
@ -144,6 +181,7 @@ end
/// @return if check waves are enabled, the following waves are created (overwritten if existing): /// @return if check waves are enabled, the following waves are created (overwritten if existing):
/// @arg check_dist average X distribution /// @arg check_dist average X distribution
/// @arg check_smoo smoothed distribution used to normalize the strip /// @arg check_smoo smoothed distribution used to normalize the strip
///
function normalize_strip_x(strip, [smooth_method, smooth_factor, check]) function normalize_strip_x(strip, [smooth_method, smooth_factor, check])
wave strip wave strip
variable smooth_method variable smooth_method
@ -233,6 +271,7 @@ end
/// @return if check waves are enabled, the following waves are created (overwritten if existing): /// @return if check waves are enabled, the following waves are created (overwritten if existing):
/// @arg check_dist average theta distribution /// @arg check_dist average theta distribution
/// @arg check_smoo smoothed distribution used to normalize the strip /// @arg check_smoo smoothed distribution used to normalize the strip
///
function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smooth_factor, check]) function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
wave strip wave strip
wave theta wave theta
@ -300,6 +339,70 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot
endif endif
end end
/// divide the strip by a two-dimensional normalization function.
///
/// @warning experimental. this function is under development.
///
/// @param check enable output of intermediate results
/// @arg 0 (default) don't create additional waves
/// @arg 1 create check waves in the current folder
/// @arg 2 calculate check waves only, do not modify strip
///
/// @return if check waves are enabled, the following waves are created (overwritten if existing):
/// @arg check_dist average theta distribution
/// @arg check_smoo smoothed distribution used to normalize the strip
///
function normalize_strip_2d(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
wave strip
wave theta
variable theta_offset
variable smooth_method
variable smooth_factor
variable check
if (ParamIsDefault(check))
check = 0
endif
if (ParamIsDefault(theta_offset))
theta_offset = 0
endif
if (ParamIsDefault(smooth_method))
smooth_method = 4
endif
if (ParamIsDefault(smooth_factor))
smooth_factor = 0.5
endif
variable nx = dimsize(strip, 0)
variable ny = dimsize(strip, 1)
duplicate /free strip, dist, alpha_int, theta_int
theta_int = theta[q] - theta_offset
alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
redimension /n=(nx * ny) dist, alpha_int, theta_int
switch(smooth_method)
case 4:
loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={alpha_int, theta_int}
redimension /n=(nx, ny) dist_smoo
break
default:
Abort "undefined smooth method"
break
endswitch
// divide
if (check != 2)
strip /= dist_smoo
endif
// check
if (check)
//duplicate /o dist, check_dist
duplicate /o dist_smoo, check_smoo
endif
end
/// crop a strip at the sides. /// crop a strip at the sides.
/// ///
/// the strip is cropped in place, data outside the region of interest is lost. /// the strip is cropped in place, data outside the region of interest is lost.
@ -705,9 +808,9 @@ function convert_angles_ttpa2polar(theta, tilt, phi, analyser, polar, azi)
// this is simply a polar-cartesian mapping, independent of the manipulator // this is simply a polar-cartesian mapping, independent of the manipulator
// phi=0 is in the polar rotation plane // phi=0 is in the polar rotation plane
make /n=(3,na) /d /free w_orig_polar, w_orig_cart, w_rot_cart, w_rot_polar make /n=(3,na) /d /free w_orig_polar, w_orig_cart, w_rot_cart, w_rot_polar
w_orig_polar[0] = radius w_orig_polar[0][] = radius
w_orig_polar[1] = analyser[q] w_orig_polar[1][] = analyser[q]
w_orig_polar[2] = 0 w_orig_polar[2][] = 0
polar2cart_wave(w_orig_polar, w_orig_cart) polar2cart_wave(w_orig_polar, w_orig_cart)
// if the angle-dispersive axis was horizontal, we'd need to rotate the detector // if the angle-dispersive axis was horizontal, we'd need to rotate the detector
//rotate_z_wave(w_orig_cart, 90) //rotate_z_wave(w_orig_cart, 90)
@ -1204,6 +1307,7 @@ function duplicate_hemi_scan(source_nickname, dest_folder, dest_nickname, [xpdpl
string s_theta = s_prefix + "th" string s_theta = s_prefix + "th"
string s_tot = s_prefix + "tot" string s_tot = s_prefix + "tot"
string s_weight = s_prefix + "wt" string s_weight = s_prefix + "wt"
string s_matrix = s_prefix + "matrix"
wave theta1 = $s_theta wave theta1 = $s_theta
wave polar1 = $s_polar wave polar1 = $s_polar
@ -1211,6 +1315,7 @@ function duplicate_hemi_scan(source_nickname, dest_folder, dest_nickname, [xpdpl
wave tot1 = $s_tot wave tot1 = $s_tot
wave weight1 = $s_weight wave weight1 = $s_weight
wave values1 = $s_int wave values1 = $s_int
wave /z matrix1 = $s_matrix
variable npol = numpnts(theta1) variable npol = numpnts(theta1)
@ -1230,6 +1335,7 @@ function duplicate_hemi_scan(source_nickname, dest_folder, dest_nickname, [xpdpl
s_theta = s_prefix + "th" s_theta = s_prefix + "th"
s_tot = s_prefix + "tot" s_tot = s_prefix + "tot"
s_weight = s_prefix + "wt" s_weight = s_prefix + "wt"
s_matrix = s_prefix + "matrix"
wave theta2 = $s_theta wave theta2 = $s_theta
wave polar2 = $s_polar wave polar2 = $s_polar
@ -1241,6 +1347,9 @@ function duplicate_hemi_scan(source_nickname, dest_folder, dest_nickname, [xpdpl
tot2 = tot1 tot2 = tot1
weight2 = weight1 weight2 = weight1
values2 = values1 values2 = values1
if (waveexists(matrix1))
duplicate /o matrix1, $s_matrix
endif
if (!(NumberByKey("version", note(azim1), "=", "\r") >= 1.6)) if (!(NumberByKey("version", note(azim1), "=", "\r") >= 1.6))
azim2 += 180 // changed 151030 (v1.6) azim2 += 180 // changed 151030 (v1.6)
@ -1250,6 +1359,48 @@ function duplicate_hemi_scan(source_nickname, dest_folder, dest_nickname, [xpdpl
setdatafolder saveDF setdatafolder saveDF
end end
/// azimuthally rotate a hemispherical scan dataset.
///
/// this function works only for hemi scans created by make_hemi_grid() (or compatible functions).
///
/// @param nickname name prefix for waves. source data must be in current data folder.
/// @param angle azimuthal rotation angle in degrees.
///
function rotate_hemi_scan(nickname, angle)
string nickname
variable angle
dfref savedf = getdatafolderdfr()
if (strlen(nickname))
string s_prefix = nickname + "_"
string s_int = s_prefix + "i"
else
s_prefix = ""
s_int = "values"
endif
string s_polar = s_prefix + "pol"
string s_azim = s_prefix + "az"
string s_tot = s_prefix + "tot"
string s_weight = s_prefix + "wt"
wave polar = $s_polar
wave azim = $s_azim
wave tot = $s_tot
wave weight = $s_weight
wave values = $s_int
azim += angle
azim = azim < 0 ? azim + 360 : azim
azim = azim >= 360 ? azim - 360 : azim
duplicate /free polar, neg_polar
neg_polar = -polar
sort {neg_polar, azim}, polar, azim, tot, weight, values
setdatafolder saveDF
end
/// display a plot of a hemispherical angle scan. /// display a plot of a hemispherical angle scan.
/// ///
/// the scan data must exist in the current data folder. /// the scan data must exist in the current data folder.
@ -1264,10 +1415,29 @@ end
/// @arg 0 linear /// @arg 0 linear
/// @arg 1 stereographic (default) /// @arg 1 stereographic (default)
/// @arg 2 azimuthal /// @arg 2 azimuthal
/// @arg 3 gnomonic (0 <= polar < 90).
/// ///
/// @param graphtype type of graph /// @param graphtype type of graph
/// @arg 1 Igor "New Polar" (default) /// @arg 1 (pol, az) trace in Igor "New Polar" (default).
/// @arg 2 XPDplot (reserved, not implemented) /// @arg 2 XPDplot (reserved, not implemented).
/// @arg 3 matrix in Igor "New Polar".
/// the matrix wave is a 2D wave with X and Y scaling corresponding to the selected projection.
/// matrix waves can be created by interpolate_hemi_scan().
/// note: the pol and az waves are required as well.
///
/// @param do_ticks select which ticks to draw.
/// value must be the arithmetic OR of all selected items.
/// default: 3
/// @arg 0 none
/// @arg 1 major azimuthal
/// @arg 2 minor azimuthal
///S
/// @param do_grids select which grids to draw.
/// value must be the arithmetic OR of all selected items.
/// default: 3
/// @arg 0 none
/// @arg 1 radius at 0 and 90 degree azimuth
/// @arg 2 circle at 30 and 60 degree polar
/// ///
/// @param graphname name of graph window. default: nickname /// @param graphname name of graph window. default: nickname
/// if empty, a default name is assigned. /// if empty, a default name is assigned.
@ -1275,10 +1445,12 @@ end
/// ///
/// @returns the name of the graph window /// @returns the name of the graph window
/// ///
function /s display_hemi_scan(nickname, [projection, graphtype, graphname]) function /s display_hemi_scan(nickname, [projection, graphtype, do_ticks, do_grids, graphname])
string nickname string nickname
variable projection variable projection
variable graphtype variable graphtype
variable do_ticks
variable do_grids
string graphname string graphname
if (ParamIsDefault(projection)) if (ParamIsDefault(projection))
@ -1287,6 +1459,12 @@ function /s display_hemi_scan(nickname, [projection, graphtype, graphname])
if (ParamIsDefault(graphtype)) if (ParamIsDefault(graphtype))
graphtype = 1 graphtype = 1
endif endif
if (ParamIsDefault(do_ticks))
do_ticks = 3
endif
if (ParamIsDefault(do_grids))
do_grids = 3
endif
if (ParamIsDefault(graphname)) if (ParamIsDefault(graphname))
if (strlen(nickname) > 0) if (strlen(nickname) > 0)
graphname = nickname graphname = nickname
@ -1305,9 +1483,12 @@ function /s display_hemi_scan(nickname, [projection, graphtype, graphname])
endif endif
string s_polar = s_prefix + "pol" string s_polar = s_prefix + "pol"
string s_azim = s_prefix + "az" string s_azim = s_prefix + "az"
string s_matrix = s_prefix + "matrix"
wave /z values = $s_int wave /z values = $s_int
wave /z azim = $s_azim wave /z azim = $s_azim
wave /z polar = $s_polar wave /z polar = $s_polar
wave /z matrix = $s_matrix
string s_ster_rad = s_prefix + "ster_rad" string s_ster_rad = s_prefix + "ster_rad"
duplicate /o polar, $s_ster_rad /wave=ster_rad duplicate /o polar, $s_ster_rad /wave=ster_rad
@ -1325,11 +1506,12 @@ function /s display_hemi_scan(nickname, [projection, graphtype, graphname])
azim_offset = 180 // changed 151030 (v1.6) azim_offset = 180 // changed 151030 (v1.6)
endif endif
string s_trace
switch(graphtype) switch(graphtype)
case 1: case 1:
graphname = display_polar_graph(graphname, angle_offset=azim_offset) graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
string s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360) s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
ModifyGraph /W=$graphname mode($s_trace)=2, lsize($s_trace)=2 ModifyGraph /W=$graphname mode($s_trace)=2, lsize($s_trace)=2
ModifyGraph /W=$graphname zColor($s_trace)={values,*,*,BlueGreenOrange,0} ModifyGraph /W=$graphname zColor($s_trace)={values,*,*,BlueGreenOrange,0}
@ -1338,7 +1520,21 @@ function /s display_hemi_scan(nickname, [projection, graphtype, graphname])
ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50 ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
SetWindow $graphname, userdata(projection)=num2str(projection) SetWindow $graphname, userdata(projection)=num2str(projection)
draw_hemi_axes(graphname) draw_hemi_axes(graphname, do_grids=do_grids)
break
case 3:
graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
ModifyGraph /W=$graphname mode($s_trace)=0, lsize($s_trace)=0
AppendImage /L=VertCrossing /B=HorizCrossing matrix
ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 image=$s_matrix
ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
SetWindow $graphname, userdata(projection)=num2str(projection)
draw_hemi_axes(graphname, do_grids=do_grids)
break break
endswitch endswitch
@ -1373,22 +1569,33 @@ end
/// for hemi grids created with earlier versions, /// for hemi grids created with earlier versions,
/// it should be set to 180 for correct orientation. /// it should be set to 180 for correct orientation.
/// ///
/// @param do_ticks select which ticks to draw.
/// value must be the arithmetic OR of all selected items.
/// default: 3
/// @arg 0 none
/// @arg 1 major azimuthal
/// @arg 2 minor azimuthal
///
/// @returns the name of the graph window. /// @returns the name of the graph window.
/// ///
/// @version 1.7 /// @version 1.7
/// interface change: the trace drawing code is moved to display_hemi_scan, /// interface change: the trace drawing code is moved to display_hemi_scan,
/// so that this function can be reused by other graph types, e.g. display_scanlines. /// so that this function can be reused by other graph types, e.g. display_scanlines.
/// ///
static function /s display_polar_graph(graphname, [angle_offset]) static function /s display_polar_graph(graphname, [angle_offset, do_ticks])
string graphname string graphname
variable angle_offset variable angle_offset
variable do_ticks
dfref savedf = GetDataFolderDFR() dfref savedf = GetDataFolderDFR()
if (ParamIsDefault(angle_offset)) if (ParamIsDefault(angle_offset))
angle_offset = 0 angle_offset = 0
endif endif
if (ParamIsDefault(do_ticks))
do_ticks = 3
endif
if ((strlen(graphname) == 0) || (wintype(graphname) == 0)) if ((strlen(graphname) == 0) || (wintype(graphname) == 0))
Display /k=1 /W=(10,45,360,345) Display /k=1 /W=(10,45,360,345)
@ -1408,15 +1615,28 @@ static function /s display_polar_graph(graphname, [angle_offset])
WMPolarGraphSetVar(graphname, "doPolarGrids", 0) WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0) WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
WMPolarGraphSetStr(graphname, "radiusAxisWhere", " Off ") WMPolarGraphSetStr(graphname, "radiusAxesWhere", " Off") // note the leading spaces, cf. WMPolarAnglesForRadiusAxes
WMPolarGraphSetStr(graphname, "radiusTicksLocation", "Off")
WMPolarGraphSetVar(graphname, "majorTickLength", 5) WMPolarGraphSetVar(graphname, "majorTickLength", 2)
WMPolarGraphSetVar(graphname, "majorTickThick", 0.5) WMPolarGraphSetVar(graphname, "majorTickThick", 0.5)
WMPolarGraphSetVar(graphname, "minorTickLength", 3) WMPolarGraphSetVar(graphname, "minorTickLength", 1)
WMPolarGraphSetVar(graphname, "minorTickThick", 0.5) WMPolarGraphSetVar(graphname, "minorTickThick", 0.5)
WMPolarGraphSetVar(graphname, "tickLabelOpaque", 0) WMPolarGraphSetVar(graphname, "tickLabelOpaque", 0)
WMPolarGraphSetVar(graphname, "tickLabelFontSize", 7) WMPolarGraphSetVar(graphname, "tickLabelFontSize", 7)
// changes
if (do_ticks & 1)
WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
else
WMPolarGraphSetStr(graphname, "angleTicksLocation", "Off")
endif
if (do_ticks & 2)
WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 1)
else
WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 0)
endif
DoWindow /T $graphname, graphname DoWindow /T $graphname, graphname
// cursor info in angles // cursor info in angles
@ -1452,11 +1672,11 @@ static function /s display_polar_graph(graphname, [angle_offset])
return graphname return graphname
end end
/// draw polar and azimuthal axes in an existing polar graph /// draw polar and azimuthal grids in an existing polar graph.
/// ///
/// the function adds the following draw objects to a polar graph: /// the function adds the following draw objects to a polar graph:
/// * concentric circles at polar angles 0, 30, 60, and 90 degrees with labels. /// * concentric circles at polar angles 0, 30, and 60 degrees with labels.
/// * labels for azimuthal angles at 0, 30, 60, and 90 degrees. /// * radial axes at 0 and 90 degree azimuth.
/// ///
/// the objects are added to the ProgFront drawing layer and will appear in front of the data trace. /// the objects are added to the ProgFront drawing layer and will appear in front of the data trace.
/// in interactive drawing mode, you can select the active drawing layer by clicking the tree icon /// in interactive drawing mode, you can select the active drawing layer by clicking the tree icon
@ -1467,12 +1687,24 @@ end
/// ///
/// @param graphname name of graph window. /// @param graphname name of graph window.
/// ///
/// @param do_grids select which optional grids to draw.
/// value must be the arithmetic OR of all selected items.
/// default: 3
/// @arg 0 none
/// @arg 1 radius at 0 and 90 degree azimuth
/// @arg 2 circle at 30 and 60 degree polar
///
/// @warning EXPERIMENTAL! /// @warning EXPERIMENTAL!
/// this function is under development. /// this function is under development.
/// the interface and behaviour of this function may change significantly in future versions. /// the interface and behaviour of this function may change significantly in future versions.
static function /s draw_hemi_axes(graphname) static function /s draw_hemi_axes(graphname, [do_grids])
string graphname string graphname
variable do_grids
if (ParamIsDefault(do_grids))
do_grids = 3
endif
dfref savedf = GetDataFolderDFR() dfref savedf = GetDataFolderDFR()
string sproj = GetUserData(graphname, "", "projection") string sproj = GetUserData(graphname, "", "projection")
@ -1490,26 +1722,96 @@ static function /s draw_hemi_axes(graphname)
//SetDrawEnv /W=$graphname linefgc=(65535,65535,65535) //SetDrawEnv /W=$graphname linefgc=(65535,65535,65535)
SetDrawEnv /W=$graphname save SetDrawEnv /W=$graphname save
variable radi if (do_grids & 1)
radi = calc_graph_radius(0.5, projection=projection) DrawLine /W=$graphname 0, -2, 0, 2
DrawOval /W=$graphname -radi, radi, radi, -radi DrawLine /W=$graphname -2, 0, 2, 0
radi = calc_graph_radius(30, projection=projection) endif
DrawOval /W=$graphname -radi, radi, radi, -radi
radi = calc_graph_radius(60, projection=projection)
DrawOval /W=$graphname -radi, radi, radi, -radi
DrawLine /W=$graphname 0, -2, 0, 2
DrawLine /W=$graphname -2, 0, 2, 0
SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2 variable radi
SetDrawEnv /W=$graphname save if (do_grids & 2)
radi = calc_graph_radius(30, projection=projection) radi = calc_graph_radius(0.5, projection=projection)
DrawText /W=$graphname radi, -0.1, "30<33>" DrawOval /W=$graphname -radi, radi, radi, -radi
radi = calc_graph_radius(60, projection=projection) radi = calc_graph_radius(30, projection=projection)
DrawText /W=$graphname radi, -0.1, "60<36>" DrawOval /W=$graphname -radi, radi, radi, -radi
radi = calc_graph_radius(60, projection=projection)
DrawOval /W=$graphname -radi, radi, radi, -radi
SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
SetDrawEnv /W=$graphname save
radi = calc_graph_radius(30, projection=projection)
DrawText /W=$graphname radi, -0.1, "30<33>"
radi = calc_graph_radius(60, projection=projection)
DrawText /W=$graphname radi, -0.1, "60<36>"
endif
setdatafolder savedf setdatafolder savedf
end end
/// draw the circle of a diffraction cone in a stereographic polar graph.
///
/// the diffraction cone consists of a circle marking the diffraction ring, and a dot marking the axis.
/// the cone is drawn as a group of draw objects on the UserFront layer.
/// the objects can be edited interactively.
///
/// @param graphname name of graph window (not implemented yet).
///
/// @param groupname name of a drawing group.
/// if the group exists (from a previous cone) it is replaced.
/// if the group doesn't exist, a new one is created.
///
/// @param theta_axis polar angle of the cone axis in degrees.
///
/// @param theta_inner polar angle of the innermost point of the circle in degrees.
///
/// @param phi azimuthal angle of the cone axis in degrees.
///
/// @warning EXPERIMENTAL!
/// this function is under development.
/// the interface and behaviour of this function may change significantly in future versions.
///
function draw_diffraction_cone(graphname, groupname, theta_axis, theta_inner, phi)
string graphname
string groupname
variable theta_axis
variable theta_inner
variable phi
variable r_axis = calc_graph_radius(theta_axis)
variable r_inner = calc_graph_radius(theta_inner)
variable r_outer = calc_graph_radius(2 * theta_axis - theta_inner)
SetDrawEnv push
SetDrawLayer UserFront
DrawAction getgroup=$groupname, delete
SetDrawEnv gstart, gname=$groupname
variable xc, yc, xr, yr
// cone periphery
variable r_center = (r_outer + r_inner) / 2
variable r_radius = (r_outer - r_inner) / 2
xc = r_center * cos(phi * pi / 180)
yc = r_center * sin(phi * pi / 180)
xr = r_radius
yr = r_radius
SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
SetDrawEnv dash=11, fillpat=0
DrawOval xc - xr, yc - yr, xc + xr, yc + yr
// cone axis
xc = r_axis * cos(phi * pi / 180)
yc = r_axis * sin(phi * pi / 180)
r_radius = calc_graph_radius(2)
xr = r_radius
yr = r_radius
SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
SetDrawEnv fillfgc=(0,0,0)
DrawOval xc - xr, yc - yr, xc + xr, yc + yr
SetDrawEnv gstop
SetDrawEnv pop
end
/// display a polar graph with lines indicating the angles covered by an angle scan. /// display a polar graph with lines indicating the angles covered by an angle scan.
/// ///
/// @param nickname nick name for output data. /// @param nickname nick name for output data.
@ -1603,21 +1905,46 @@ function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_p
return graphname return graphname
end end
static constant kProjScaleLinear = 2 /// @page PageProjections Projections
///
/// the functions of the anglescan package support the following map projections.
/// for a description of the different projections, see, for example,
/// https://en.wikipedia.org/wiki/Map_projection
///
/// | Selector | Projection | Function | Properties |
/// | :----: | :----: | :----: | :---- |
/// | kProjDist = 0 | azimuthal equidistant | r = c * theta | radius is proportional to polar angle. |
/// | kProjStereo = 1 | stereographic | r = c * tan theta/2 | circles on sphere map to circles. |
/// | kProjArea = 2 | azimuthal equal-area | r = c * sin theta/2 | preserves area measure. |
/// | kProjGnom = 3 | gnomonic | r = c * tan theta | great circles map to straight lines. |
/// | kProjOrtho = 4 | orthographic | r = c * sin theta | k-space mapping in ARPES and LEED. |
///
/// the projections in this package are defined for 0 <= theta < 90.
///
constant kProjDist = 0
constant kProjStereo = 1
constant kProjArea = 2
constant kProjGnom = 3
constant kProjOrtho = 4
static constant kProjScaleDist = 2
static constant kProjScaleStereo = 2 static constant kProjScaleStereo = 2
static constant kProjScaleAzim = 2 static constant kProjScaleArea = 2
// scaled so that radius(gnom) = radius(stereo) for polar = 88 // scaled so that radius(gnom) = radius(stereo) for polar = 88
static constant kProjScaleGnomonic = 0.06744519021 static constant kProjScaleGnom = 0.06744519021
static constant kProjScaleOrtho = 2
/// calculate the projected polar angle /// calculate the projected polar angle
/// ///
/// @param polar polar angle in degrees /// @param polar polar angle in degrees
/// ///
/// @param projection mapping function from polar to cartesian coordinates /// @param projection mapping function from polar to cartesian coordinates.
/// @arg 0 linear /// see @ref PageProjections for details.
/// @arg 1 stereographic (default) /// @arg kProjDist = 0 azimuthal equidistant
/// @arg 2 azimuthal /// @arg kProjStereo = 1 stereographic (default)
/// @arg 3 gnomonic (0 <= polar < 90) /// @arg kProjArea = 2 azimuthal equal-area
/// @arg kProjGnom = 3 gnomonic (0 <= polar < 90)
/// @arg kProjOrtho = 4 orthographic
/// ///
/// @return projected radius. /// @return projected radius.
/// the radius is scaled such that grazing emission maps to 2. /// the radius is scaled such that grazing emission maps to 2.
@ -1631,17 +1958,20 @@ threadsafe function calc_graph_radius(polar, [projection])
variable radius variable radius
switch(projection) switch(projection)
case 1: // stereographic case kProjStereo: // stereographic
radius = kProjScaleStereo * tan(polar / 2 * pi / 180) radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
break break
case 2: // azimuthal case kProjArea: // equal area
radius = kProjScaleAzim * cos((180 - polar) / 2 * pi / 180) radius = kProjScaleArea * sin(polar / 2 * pi / 180)
break break
case 3: // gnomonic case kProjGnom: // gnomonic
radius = polar < 90 ? kProjScaleGnomonic * tan(polar * pi / 180) : inf radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
break break
default: // linear case kProjOrtho: // orthographic
radius = kProjScaleLinear * polar / 90 radius = kProjScaleOrtho * sin(polar * pi / 180)
break
default: // equidistant
radius = kProjScaleDist * polar / 90
endswitch endswitch
return radius return radius
@ -1653,10 +1983,13 @@ end
/// ///
/// @param x, y projected Cartesian coordinate /// @param x, y projected Cartesian coordinate
/// ///
/// @param projection mapping function from polar to cartesian coordinates /// @param projection mapping function from polar to cartesian coordinates.
/// @arg 0 linear /// see @ref PageProjections for details.
/// @arg 1 stereographic (default) /// @arg kProjDist = 0 azimuthal equidistant
/// @arg 2 azimuthal /// @arg kProjStereo = 1 stereographic (default)
/// @arg kProjArea = 2 azimuthal equal-area
/// @arg kProjGnom = 3 gnomonic (0 <= polar < 90)
/// @arg kProjOrtho = 4 orthographic
/// ///
/// @returns polar angle in degrees /// @returns polar angle in degrees
/// ///
@ -1674,17 +2007,20 @@ threadsafe function calc_graph_polar(x, y, [projection])
radius = sqrt(x^2 + y^2) radius = sqrt(x^2 + y^2)
switch(projection) switch(projection)
case 1: // stereographic case kProjStereo: // stereographic
polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
break break
case 2: // azimuthal case kProjArea: // equal area
polar = 180 - 2 * acos(radius / kProjScaleAzim) * 180 / pi polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
break break
case 3: // gnomonic case kProjGnom: // gnomonic
polar = atan(radius / kProjScaleGnomonic) * 180 / pi polar = atan(radius / kProjScaleGnom) * 180 / pi
break break
default: // linear case kProjOrtho: // orthographic
polar = 90 * radius / kProjScaleLinear polar = asin(radius / kProjScaleOrtho) * 180 / pi
break
default: // equidistant
polar = 90 * radius / kProjScaleDist
endswitch endswitch
return polar return polar
@ -1694,12 +2030,14 @@ end
/// ///
/// @param x, y projected Cartesian coordinate /// @param x, y projected Cartesian coordinate
/// ///
/// @param projection mapping function from polar to cartesian coordinates /// @param projection mapping function from polar to cartesian coordinates.
/// @arg 0 linear /// all supported projections are azimuthal, they have no effect on the azimuthal coordinate.
/// @arg 1 stereographic (default) /// see @ref PageProjections for details.
/// @arg 2 azimuthal /// @arg kProjDist = 0 azimuthal equidistant
/// /// @arg kProjStereo = 1 stereographic (default)
/// projections 0-2 have no effect on the azimuthal coordinate /// @arg kProjArea = 2 azimuthal equal-area
/// @arg kProjGnom = 3 gnomonic (0 <= polar < 90)
/// @arg kProjOrtho = 4 orthographic
/// ///
/// @param zeroAngle zeroAngleWhere parameter of polar graphs /// @param zeroAngle zeroAngleWhere parameter of polar graphs
/// @arg 0 (default) zero is at the 3 o'clock position /// @arg 0 (default) zero is at the 3 o'clock position
@ -2021,7 +2359,13 @@ function hemi_add_aziscan(nickname, values, polar, azi, [weights])
w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p] w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p]
end end
/// interpolate a hemispherical scan onto a rectangular grid
///
/// @warning experimental /// @warning experimental
/// this function has been tested for one specific set of scan parameters.
/// the interface and code may change at any time.
/// the function depends on the ster_x and ster_y waves that are created by display_hemi_scan.
///
function interpolate_hemi_scan(nickname) function interpolate_hemi_scan(nickname)
string nickname string nickname
@ -2044,21 +2388,26 @@ function interpolate_hemi_scan(nickname)
wave ster_x = $s_ster_x wave ster_x = $s_ster_x
wave ster_y = $s_ster_y wave ster_y = $s_ster_y
wavestats /q/m=0 ster_x variable min_ster_x = wavemin(ster_x)
variable x0 = v_min variable max_ster_x = wavemax(ster_x)
variable x0 = min_ster_x
variable xn = 181 variable xn = 181
variable dx = (v_max - v_min) / (xn - 1) variable dx = (max_ster_x - min_ster_x) / (xn - 1)
make /n=(v_npnts, 3) /free triplet make /n=(numpnts(ster_x), 3) /free triplet
triplet[][0] = ster_x[p] triplet[][0] = ster_x[p]
triplet[][1] = ster_y[p] triplet[][1] = ster_y[p]
triplet[][2] = values[p] triplet[][2] = values[p]
//ImageInterpolate /stw /s={x0, dx, xn, x0, dx, xn} voronoi triplet //ImageInterpolate /stw /s={x0, dx, xn, x0, dx, xn} voronoi triplet
make /n=(181, 181) /d /o $(s_prefix + "matrix") /wave=matrix variable size = 181
make /n=(181, 181) /free mnorm make /n=(size, size) /d /o $(s_prefix + "matrix") /wave=matrix
make /n=(size, size) /free mnorm
ImageFromXYZ /as {ster_x, ster_y, values}, matrix, mnorm ImageFromXYZ /as {ster_x, ster_y, values}, matrix, mnorm
matrix /= mnorm matrix /= mnorm
//matrixfilter NanZapMedian, matrix matrixfilter NanZapMedian, matrix
matrixfilter gauss, matrix
matrix = (x^2 + y^2) < 4 ? matrix : nan
end end
/// map angle scan data onto a rectangular grid in stereographic projection /// map angle scan data onto a rectangular grid in stereographic projection
@ -2234,3 +2583,198 @@ function load_hemi_scan(nickname, pathname, filename)
setdatafolder saveDF setdatafolder saveDF
end end
/// import a hemispherical scan from theta-phi-intensity waves and display it
///
/// @warning EXPERIMENTAL
/// the interface and behaviour of this function may change
///
function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nograph, xpdplot])
string nickname
wave theta
wave phi
wave intensity
variable folding
variable npolar
variable nograph
variable xpdplot
if (ParamIsDefault(npolar))
npolar = 91
endif
if (ParamIsDefault(nograph))
nograph = 0
endif
if (ParamIsDefault(folding))
folding = 1
endif
if (ParamIsDefault(xpdplot))
xpdplot = 0
endif
make_hemi_grid(npolar, nickname, xpdplot=xpdplot)
variable ifold
duplicate /free phi, fold_phi
for (ifold = 0; ifold < folding; ifold += 1)
hemi_add_anglescan(nickname, intensity, theta, fold_phi)
fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
endfor
display_hemi_scan(nickname)
end
/// extract a polar cut from a hemispherical scan.
///
/// for each polar angle, the function first extracts all azimuthal angles.
/// the intensity is then interpolated between the nearest neighbours of the given azimuth.
///
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
/// correct ordering is required.
///
/// @param nickname name of the scan dataset.
/// can be empty if no prefix is used.
/// the dataset must be in the current datafolder.
///
/// @param azim azimuthal angle in degrees
///
/// @return reference of the created wave.
/// the wave has the same name as the intensity wave of the dataset
/// with the suffix "_azi" and the azimuthal angle rounded to integer.
/// it is created in the same datafolder as the original data.
///
function /wave hemi_polar_cut(nickname, azim)
string nickname
variable azim
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"
string s_azim = s_prefix + "az"
string s_index = s_prefix + "index"
string s_theta = s_prefix + "th"
string s_dphi = s_prefix + "dphi"
string s_nphis = s_prefix + "nphis"
string s_cut
sprintf s_cut, "%s_azi%03u", s_int, round(azim)
wave w_polar = $s_polar
wave w_azim = $s_azim
wave w_values = $s_int
wave w_totals = $s_totals
wave w_weights = $s_weights
wave w_index = $s_index
wave w_theta = $s_theta
wave w_dphi = $s_dphi
wave w_nphis = $s_nphis
variable npol = numpnts(w_theta)
variable ipol
variable pol_st = abs(w_theta[1] - w_theta[0])
variable pol
variable pol1, pol2
variable nsel
make /n=(npol) /o $s_cut
wave w_cut = $s_cut
setscale /i x w_theta[0], w_theta[numpnts(w_theta)-1], "deg", w_cut
make /n=1 /free azi_slice
make /n=1 /free values_slice
for (ipol = 0; ipol < npol; ipol += 1)
pol = w_theta[ipol]
pol1 = pol - pol_st / 2
pol2 = pol + pol_st / 2
extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
nsel = numpnts(sel)
if (nsel > 0)
redimension /n=(nsel+2) azi_slice, values_slice
azi_slice[1, nsel] = w_azim[sel[p-1]]
azi_slice[0] = azi_slice[nsel] - 360
azi_slice[nsel+1] = azi_slice[1] + 360
values_slice[1, nsel] = w_values[sel[p-1]]
values_slice[0] = values_slice[nsel]
values_slice[nsel+1] = values_slice[1]
w_cut[ipol] = interp(azim, azi_slice, values_slice)
else
w_cut[ipol] = nan
endif
endfor
return w_cut
end
/// extract an azimuthal cut from a hemispherical scan
///
/// the function extracts all azimuthal angles that are present for the given polar angle.
///
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
/// correct ordering is required.
///
/// @param nickname name of the scan dataset.
/// can be empty if no prefix is used.
/// the dataset must be in the current datafolder.
///
/// @param pol polar angle in degrees
///
/// @return reference of the created wave.
/// the wave has the same name as the intensity wave of the dataset
/// with the suffix "_azi" and the azimuthal angle rounded to integer.
/// it is created in the same datafolder as the original data.
///
function /wave hemi_azi_cut(nickname, pol)
string nickname
variable pol
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"
string s_azim = s_prefix + "az"
string s_index = s_prefix + "index"
string s_theta = s_prefix + "th"
string s_dphi = s_prefix + "dphi"
string s_nphis = s_prefix + "nphis"
string s_cut
sprintf s_cut, "%s_pol%03u", s_int, round(pol)
wave w_polar = $s_polar
wave w_azim = $s_azim
wave w_values = $s_int
wave w_totals = $s_totals
wave w_weights = $s_weights
wave w_index = $s_index
wave w_theta = $s_theta
wave w_dphi = $s_dphi
wave w_nphis = $s_nphis
variable pol_st = abs(w_theta[1] - w_theta[0])
variable pol1, pol2
variable nsel
pol1 = pol - pol_st / 2
pol2 = pol + pol_st / 2
extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
nsel = numpnts(sel)
if (nsel > 0)
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
return w_cut
else
return $""
endif
end

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,25 @@
/// PearlAreaDisplay is declared in @ref pearl-area-display.ipf. /// PearlAreaDisplay is declared in @ref pearl-area-display.ipf.
/// ///
/// compose a valid and unique graph name from a data folder reference
static function /s graphname_from_dfref(df, prefix)
dfref df
string prefix
string name
name = GetDataFolder(1, df)
name = ReplaceString("root:", name, "")
name = name[0, strlen(name) - 2]
name = ReplaceString(" ", name, "")
name = CleanupName(prefix + name, 0)
if (CheckName(name, 6))
name = UniqueName(name, 6, 0)
endif
return name
end
/// open a new graph window with a 2D image. /// open a new graph window with a 2D image.
/// ///
/// this is essentially <code>display; appendimage</code>. /// this is essentially <code>display; appendimage</code>.
@ -72,7 +91,7 @@ function /s ad_display(image)
string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
string graphtitle = dfname + " View" string graphtitle = dfname + " View"
string /g view_graphname = CleanupName("view_" + dfname, 0) string /g view_graphname = graphname_from_dfref(imagedf, "view_")
svar graphname = view_graphname svar graphname = view_graphname
display /k=1/n=$graphname as graphtitle display /k=1/n=$graphname as graphtitle
graphname = s_name graphname = s_name
@ -104,7 +123,7 @@ function /s ad_display_histogram(image)
string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
string graphtitle = dfname + " Histogram" string graphtitle = dfname + " Histogram"
string /g hist_graphname = CleanupName("hist_" + dfname, 0) string /g hist_graphname = graphname_from_dfref(imagedf, "hist_")
svar graphname = hist_graphname svar graphname = hist_graphname
display /k=1/n=$graphname as graphtitle display /k=1/n=$graphname as graphtitle
graphname = s_name graphname = s_name
@ -171,16 +190,15 @@ function /s ad_display_profiles(image, [filter])
duplicate /o image, $viewname /wave=view duplicate /o image, $viewname /wave=view
make /n=(3,3)/o xprofiles // NX x 3 wave with 3 one-dimensional profiles along Y dimension make /n=(3,3)/o xprofiles // NX x 3 wave with 3 one-dimensional profiles along Y dimension
make /n=(3,3)/o yprofiles // NY x 3 wave with 3 one-dimensional profiles along X dimension make /n=(3,3)/o yprofiles // NY x 3 wave with 3 one-dimensional profiles along X dimension
make /n=(1)/o hist // histogram
string /g view_filter string /g view_filter
string /g view_filter_options string /g view_filter_options
view_filter = filter view_filter = filter
view_filter_options = "" view_filter_options = ""
variable /g view_filter_smoothing_x = 1 variable /g view_filter_smoothing_x = 1
variable /g view_filter_smoothing_y = 1 variable /g view_filter_smoothing_y = 1
string dfname = GetDataFolder(0, imagedf) string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
string graphtitle = dfname + ":" + NameOfWave(image) + " Profiles" string graphtitle = dfname + NameOfWave(image) + " Profiles"
string /g prof_graphname = CleanupName("prof_" + dfname, 0) string /g prof_graphname = graphname_from_dfref(imagedf, "prof_")
svar graphname = prof_graphname svar graphname = prof_graphname
variable /g graph_avg // average value in ROI (ROI is defined by the crosshairs A and B) variable /g graph_avg // average value in ROI (ROI is defined by the crosshairs A and B)
variable /g graph_min // minimum value in ROI variable /g graph_min // minimum value in ROI
@ -193,16 +211,13 @@ function /s ad_display_profiles(image, [filter])
graphname = s_name graphname = s_name
AppendToGraph /w=$graphname /L=xprofiles xprofiles[*][0],xprofiles[*][1],xprofiles[*][2] AppendToGraph /w=$graphname /L=xprofiles xprofiles[*][0],xprofiles[*][1],xprofiles[*][2]
AppendToGraph /w=$graphname /VERT/B=yprofiles yprofiles[*][0],yprofiles[*][1],yprofiles[*][2] AppendToGraph /w=$graphname /VERT/B=yprofiles yprofiles[*][0],yprofiles[*][1],yprofiles[*][2]
AppendToGraph /w=$graphname /R=hist/B=yprofiles hist
AppendImage /w=$graphname view AppendImage /w=$graphname view
string imgname = StringFromList(0, ImageNameList(graphname, ";")) string imgname = StringFromList(0, ImageNameList(graphname, ";"))
ModifyImage /w=$graphname $imgname ctab= {*,*,BlueGreenOrange,0} ModifyImage /w=$graphname $imgname ctab= {*,*,BlueGreenOrange,0}
ModifyGraph /w=$graphname rgb(xprofiles)=(39168,0,0),rgb(yprofiles)=(39168,0,0) ModifyGraph /w=$graphname rgb(xprofiles)=(39168,0,0),rgb(yprofiles)=(39168,0,0)
ModifyGraph /w=$graphname rgb(xprofiles#1)=(0,26112,0),rgb(yprofiles#1)=(0,26112,0) ModifyGraph /w=$graphname rgb(xprofiles#1)=(0,26112,0),rgb(yprofiles#1)=(0,26112,0)
ModifyGraph /w=$graphname rgb(xprofiles#2)=(0,9472,39168),rgb(yprofiles#2)=(0,9472,39168) ModifyGraph /w=$graphname rgb(xprofiles#2)=(0,9472,39168),rgb(yprofiles#2)=(0,9472,39168)
ModifyGraph /w=$graphname rgb(hist)=(43520,43520,43520) ModifyGraph /w=$graphname mirror(xprofiles)=2,mirror(bottom)=3,mirror(yprofiles)=2,mirror(left)=3
ModifyGraph /w=$graphname mode(hist)=5,hbFill(hist)=2
ModifyGraph /w=$graphname mirror(xprofiles)=0,mirror(bottom)=3,mirror(yprofiles)=3,mirror(left)=3
ModifyGraph /w=$graphname nticks=3 ModifyGraph /w=$graphname nticks=3
ModifyGraph /w=$graphname minor=1 ModifyGraph /w=$graphname minor=1
ModifyGraph /w=$graphname axThick=0.5 ModifyGraph /w=$graphname axThick=0.5
@ -210,21 +225,33 @@ function /s ad_display_profiles(image, [filter])
ModifyGraph /w=$graphname btLen=4 ModifyGraph /w=$graphname btLen=4
ModifyGraph /w=$graphname freePos(xprofiles)=0 ModifyGraph /w=$graphname freePos(xprofiles)=0
ModifyGraph /w=$graphname freePos(yprofiles)=0 ModifyGraph /w=$graphname freePos(yprofiles)=0
ModifyGraph /w=$graphname freePos(hist)=0
ModifyGraph /w=$graphname axisEnab(xprofiles)={0.64,1} ModifyGraph /w=$graphname axisEnab(xprofiles)={0.64,1}
ModifyGraph /w=$graphname axisEnab(hist)={0.64,1}
ModifyGraph /w=$graphname axisEnab(bottom)={0,0.6} ModifyGraph /w=$graphname axisEnab(bottom)={0,0.6}
ModifyGraph /w=$graphname axisEnab(yprofiles)={0.64,1} ModifyGraph /w=$graphname axisEnab(yprofiles)={0.64,1}
ModifyGraph /w=$graphname axisEnab(left)={0,0.6} ModifyGraph /w=$graphname axisEnab(left)={0,0.6}
ModifyGraph /w=$graphname zero(left)=8 ModifyGraph /w=$graphname zero(left)=8
ModifyGraph /w=$graphname margin(left)=40,margin(bottom)=30,margin(top)=20,margin(right)=40 ModifyGraph /w=$graphname margin(left)=40,margin(bottom)=30,margin(top)=20,margin(right)=40
ModifyGraph /w=$graphname gfSize=10 ModifyGraph /w=$graphname gfSize=10
Label /w=$graphname xprofiles "value (\\U)"
Label /w=$graphname bottom "X (\\U)" // axis labels
Label /w=$graphname yprofiles "value (\\U)" string labels = note(image)
Label /w=$graphname left "Y (\\U)" string lab
Label /w=$graphname hist "\\Epixels" lab = StringByKey("AxisLabelX", labels, "=", "\r")
SetAxis /w=$graphname /A /E=1 hist if (!strlen(lab))
lab = "X"
endif
Label /w=$graphname bottom lab + " (\\U)"
lab = StringByKey("AxisLabelY", labels, "=", "\r")
if (!strlen(lab))
lab = "Y"
endif
Label /w=$graphname left lab + " (\\U)"
lab = StringByKey("AxisLabelD", labels, "=", "\r")
if (!strlen(lab))
lab = "value"
endif
Label /w=$graphname xprofiles lab + " (\\U)"
Label /w=$graphname yprofiles lab + " (\\U)"
// legend // legend
if (show_legend) if (show_legend)
@ -233,13 +260,18 @@ function /s ad_display_profiles(image, [filter])
AppendText /w=$graphname "\\s(xprofiles#2)\tROI average" AppendText /w=$graphname "\\s(xprofiles#2)\tROI average"
AppendText /w=$graphname "min\t\\{" + s_viewdf + "graph_min}" AppendText /w=$graphname "min\t\\{" + s_viewdf + "graph_min}"
AppendText /w=$graphname "max\t\\{" + s_viewdf + "graph_max}" AppendText /w=$graphname "max\t\\{" + s_viewdf + "graph_max}"
AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}" AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}" AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
else else
TextBox /w=$graphname /C/N=text_sum/F=0/B=1/X=1.00/Y=1.00 "sum \\{" + s_viewdf + "graph_sum}" TextBox /w=$graphname /C/N=text0 /F=0 /B=1 /X=1.00 /Y=1.00
TextBox /w=$graphname /C/N=text_avg/F=0/B=1/X=1.00/Y=6.00 "avg \\{" + s_viewdf + "graph_avg}" lab = StringByKey("Dataset", labels, "=", "\r")
TextBox /w=$graphname /C/N=text_sdev/F=0/B=1/X=1.00/Y=11.00 "sdev \\{" + s_viewdf + "graph_sdev}" if (strlen(lab))
AppendText /w=$graphname lab
endif
AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
endif endif
// interactive elements // interactive elements
@ -991,7 +1023,7 @@ function /s ad_display_brick(data)
setdatafolder viewdf setdatafolder viewdf
string dfname = ReplaceString("root:", s_datadf, "") string dfname = ReplaceString("root:", s_datadf, "")
string graphtitle = dfname + " Gizmo" string graphtitle = dfname + " Gizmo"
string /g gizmo_graphname = CleanupName("giz_" + dfname, 0) string /g gizmo_graphname = graphname_from_dfref(datadf, "giz_")
svar graphname = gizmo_graphname svar graphname = gizmo_graphname
if ((strlen(graphname) > 0) && (wintype(graphname) == 13)) if ((strlen(graphname) > 0) && (wintype(graphname) == 13))
@ -1115,13 +1147,32 @@ function ad_brick_slicer(data)
variable /g x_autoinc = 0 variable /g x_autoinc = 0
variable /g y_autoinc = 0 variable /g y_autoinc = 0
variable /g z_autoinc = 0 variable /g z_autoinc = 0
// axis labels
string labels = note(data)
string xlabel = StringByKey("AxisLabelX", labels, "=", "\r")
if (!strlen(xlabel))
xlabel = "X"
endif
string ylabel = StringByKey("AxisLabelY", labels, "=", "\r")
if (!strlen(ylabel))
ylabel = "Y"
endif
string zlabel = StringByKey("AxisLabelZ", labels, "=", "\r")
if (!strlen(zlabel))
zlabel = "Z"
endif
string dlabel = StringByKey("Dataset", labels, "=", "\r")
if (!strlen(dlabel))
dlabel = NameOfWave(data)
endif
// this section copied from slicer panel // this section copied from slicer panel
NewPanel /k=1 /W=(500,600,890,940) /N=SlicerPanel as "Brick Slicer" NewPanel /k=1 /W=(500,600,890,940) /N=SlicerPanel as "Brick Slicer"
string /g slicer_panelname = S_name string /g slicer_panelname = S_name
string panel = s_name string panel = s_name
GroupBox g_xslice win=$panel,pos={8,8},size={376,96},title="X Slice" GroupBox g_xslice win=$panel,pos={8,8},size={376,96},title=xlabel
Slider sl_xslice_position win=$panel,pos={16,32},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_xslice_position win=$panel,pos={16,32},size={240,56},proc=PearlAreaDisplay#slp_slice_position
Slider sl_xslice_position win=$panel,limits={0,100,1},variable=x_slice_pos,vert= 0 Slider sl_xslice_position win=$panel,limits={0,100,1},variable=x_slice_pos,vert= 0
SetVariable sv_xslice_position win=$panel,pos={20,80},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="X" SetVariable sv_xslice_position win=$panel,pos={20,80},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="X"
@ -1141,7 +1192,7 @@ function ad_brick_slicer(data)
Button b_xslice_stop win=$panel,pos={336,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_xslice_stop win=$panel,pos={336,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
Button b_xslice_stop win=$panel,help={"stop animation"} Button b_xslice_stop win=$panel,help={"stop animation"}
GroupBox g_yslice win=$panel,pos={8,108},size={376,96},title="Y Slice" GroupBox g_yslice win=$panel,pos={8,108},size={376,96},title=ylabel
Slider sl_yslice_position win=$panel,pos={16,132},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_yslice_position win=$panel,pos={16,132},size={240,56},proc=PearlAreaDisplay#slp_slice_position
Slider sl_yslice_position win=$panel,limits={0,100,1},variable=y_slice_pos,vert= 0 Slider sl_yslice_position win=$panel,limits={0,100,1},variable=y_slice_pos,vert= 0
SetVariable sv_yslice_position win=$panel,pos={20,180},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Y" SetVariable sv_yslice_position win=$panel,pos={20,180},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Y"
@ -1161,7 +1212,7 @@ function ad_brick_slicer(data)
Button b_yslice_stop win=$panel,pos={336,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_yslice_stop win=$panel,pos={336,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
Button b_yslice_stop win=$panel,help={"stop animation"} Button b_yslice_stop win=$panel,help={"stop animation"}
GroupBox g_zslice win=$panel,pos={8,208},size={376,96},title="Z Slice" GroupBox g_zslice win=$panel,pos={8,208},size={376,96},title=zlabel
Slider sl_zslice_position win=$panel,pos={16,232},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_zslice_position win=$panel,pos={16,232},size={240,56},proc=PearlAreaDisplay#slp_slice_position
Slider sl_zslice_position win=$panel,limits={0,100,1},variable=z_slice_pos,vert= 0 Slider sl_zslice_position win=$panel,limits={0,100,1},variable=z_slice_pos,vert= 0
SetVariable sv_zslice_position win=$panel,pos={20,280},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Z" SetVariable sv_zslice_position win=$panel,pos={20,280},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Z"
@ -1181,7 +1232,7 @@ function ad_brick_slicer(data)
Button b_zslice_stop win=$panel,pos={336,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_zslice_stop win=$panel,pos={336,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
Button b_zslice_stop win=$panel,help={"stop animation"} Button b_zslice_stop win=$panel,help={"stop animation"}
TitleBox t_slicerpath win=$panel,pos={8,316},size={128,20},disable=2,title=GetDataFolder(1,viewdf) TitleBox t_slicerpath win=$panel,pos={8,316},size={128,20},disable=2,title=dlabel
//SetVariable setvar0 win=$panel,pos={240,316},size={120,16},title="slab thickness" //SetVariable setvar0 win=$panel,pos={240,316},size={120,16},title="slab thickness"
//SetVariable setvar0 win=$panel,limits={1,inf,1},value=slab_thickness //SetVariable setvar0 win=$panel,limits={1,inf,1},value=slab_thickness

View File

@ -3,23 +3,35 @@
#pragma ModuleName = PearlAreaImport #pragma ModuleName = PearlAreaImport
#pragma version = 1.06 #pragma version = 1.06
#include <HDF5 Browser> #include <HDF5 Browser>
#include "pearl-gui-tools", version >= 1.01 #include "pearl-gui-tools"
// HDF5 file import from EPICS area detectors // copyright (c) 2013-16 Paul Scherrer Institut
// such as CCD cameras, 2D electron analysers //
// 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
// restriction: as of version 6.3, Igor can open datasets of up to rank 4. /// @file
// i.e. the extra dimension Y of the file plugin cannot be used. /// @brief HDF5 file import from EPICS area detectors
// the extra dimensions N and X are supported. /// @ingroup ArpesPackage
///
///
/// HDF5 file import from EPICS area detectors
/// such as CCD cameras, 2D electron analysers
///
/// as of Igor 6.3, Igor can open datasets of up to rank 4.
/// i.e. the extra dimension Y of the file plugin cannot be used.
/// the extra dimensions N and X are supported.
// created: matthias.muntwiler@psi.ch, 2013-05-31 /// @namespace PearlAreaImport
// Copyright (c) 2013 Paul Scherrer Institut /// @brief HDF5 file import from EPICS area detectors
// $Id$ ///
/// PearlAreaImport is declared in @ref pearl-area-import.ipf.
//------------------------------------------------------------------------------ /// callback function for drag&drop of HDF5 files into Igor.
///
static function BeforeFileOpenHook(refNum,fileName,path,type,creator,kind) static function BeforeFileOpenHook(refNum,fileName,path,type,creator,kind)
// allows drag&drop of data files into an open igor window
// this works only with igor 5.02 or later
variable refNum, kind variable refNum, kind
string fileName, path, type, creator string fileName, path, type, creator
@ -57,20 +69,37 @@ static function BeforeFileOpenHook(refNum,fileName,path,type,creator,kind)
return handledOpen // 1 tells Igor not to open the file return handledOpen // 1 tells Igor not to open the file
End End
/// generate the name of a data folder based on a file name.
///
/// if the file name follows the naming convention source-date-index.extension,
/// the function tries to generate the nick name as source_date_index.
/// otherwise it's just a cleaned up version of the file name.
///
/// date must be in yyyymmdd or yymmdd format and is clipped to the short yymmdd format.
/// index should be a running numeric index of up to 6 digits, or the time encoded as hhmmss.
/// however, in the current version index can be any string that can be a valid Igor folder name.
///
/// @param filename file name, including extension. can also include a folder path (which is ignored).
/// the extension is currently ignored, but may be used to select the parent folder in a later version.
/// @param ignoredate if non-zero, the nick name will not include the date part.
/// defaults to zero.
/// @param sourcename nick name of the data source.
/// by default, the function tries to detect the source from the file name.
/// this option can be used to override auto-detection.
/// the automatic source names are:
/// sci (scienta by area detector),
/// psh (pshell),
/// sl (optics slit camera by area detector),
/// es (end station camera by area detector),
/// xy (unidentified).
/// @param unique if non-zero, the resulting name is made a unique data folder name in the current data folder
/// defaults to zero.
///
function /s ad_suggest_foldername(filename, [ignoredate,sourcename,unique]) function /s ad_suggest_foldername(filename, [ignoredate,sourcename,unique])
// suggests the name of a data folder based on a file name string filename
// if the file name follows the naming convention source-date-index.extension, variable ignoredate
// the function tries to generate the nick name as source_date_index. string sourcename
// otherwise it's just a cleaned up version of the file name. variable unique
string filename // file name, including extension. can also include a folder path (which is ignored)
// the extension is currently ignored, but may be used later to select the parent folder
variable ignoredate // if non-zero, the nick name will not include the date part
// defaults to zero
string sourcename // nick name of the data source
// the function tries to detect the source from the file name
// this option can be used to override auto-detection
variable unique // if non-zero, the resulting name is made a unique data folder name in the current data folder
// defaults to zero
if (ParamIsDefault(ignoredate)) if (ParamIsDefault(ignoredate))
ignoredate = 0 ignoredate = 0
@ -86,6 +115,8 @@ function /s ad_suggest_foldername(filename, [ignoredate,sourcename,unique])
string autosource string autosource
if (strsearch(basename, "scienta", 0, 2) >= 0) if (strsearch(basename, "scienta", 0, 2) >= 0)
autosource = "sci" autosource = "sci"
elseif (strsearch(basename, "pshell", 0, 2) >= 0)
autosource = "psh"
elseif (strsearch(basename, "OP-SL", 0, 2) >= 0) elseif (strsearch(basename, "OP-SL", 0, 2) >= 0)
autosource = "sl" autosource = "sl"
elseif (strsearch(basename, "ES-PS", 0, 2) >= 0) elseif (strsearch(basename, "ES-PS", 0, 2) >= 0)
@ -99,8 +130,12 @@ function /s ad_suggest_foldername(filename, [ignoredate,sourcename,unique])
variable nparts = ItemsInList(basename, "-") variable nparts = ItemsInList(basename, "-")
if (nparts >= 3) if (nparts >= 3)
string datepart = StringFromList(nparts - 2, basename, "-") string datepart = StringFromList(1, basename, "-")
string indexpart = StringFromList(nparts - 1, basename, "-") variable l_datepart = strlen(datepart)
if (l_datepart == 8)
datepart = datepart[l_datepart-6, l_datepart-1]
endif
string indexpart = StringFromList(2, basename, "-")
if (ignoredate) if (ignoredate)
sprintf nickname, "%s_%s", sourcename, indexpart sprintf nickname, "%s_%s", sourcename, indexpart
else else
@ -117,10 +152,12 @@ function /s ad_suggest_foldername(filename, [ignoredate,sourcename,unique])
return nickname return nickname
end end
/// load area detector data files selected in a file dialog window
///
/// @param APathName Igor symbolic path name.
/// if empty, Igor will choose a folder on its own
function ad_load_dialog(APathName) function ad_load_dialog(APathName)
// loads data files selected in a file dialog window string APathName
string APathName // igor symbolic path name
// if empty, Igor will choose a folder on its own
variable refNum variable refNum
string message = "Select data files" string message = "Select data files"
@ -148,17 +185,23 @@ function ad_load_dialog(APathName)
setdatafolder saveDF setdatafolder saveDF
end end
//------------------------------------------------------------------------------ /// import everything from a HDF5 file created by the Area Detector software.
///
/// 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.
///
/// @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 load_data 1 (default): load data; 0: do not load data
/// @param load_attr 1 (default): load attributes; 0: do not load attributes
/// for proper wave scaling, the attributes must be loaded
function /s adh5_load_complete(ANickName, APathName, AFileName, [load_data, load_attr]) function /s adh5_load_complete(ANickName, APathName, AFileName, [load_data, load_attr])
// this function loads everything from a HDF5 file created by the Area Detector software. string ANickName
// if the data is from the electron analyser driver and some special attributes are included, string APathName
// the function will set the scales of the image dimensions. string AFileName
string ANickName // destination folder name (top level under root) variable load_data
string APathName // igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed variable load_attr
string AFileName // if empty a dialog box shows up
variable load_data // 1 (default): load data; 0: do not load data
variable load_attr // 1 (default): load attributes; 0: do not load attributes
// for proper wave scaling, the attributes must be loaded
if (ParamIsDefault(load_data)) if (ParamIsDefault(load_data))
load_data = 1 load_data = 1
@ -222,30 +265,43 @@ function /s adh5_load_complete(ANickName, APathName, AFileName, [load_data, load
return AFileName return AFileName
end end
/// load and reduce a dataset from a HDF5 file created by the Area Detector software.
///
/// 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.
///
/// 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 composed into one result wave.
/// the raw data are discarded.
///
/// 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.
///
/// @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_param parameter string for the reduction function
///
/// @param load_data 1 (default): load data; 0: do not load data
/// @param load_attr 1 (default): load attributes; 0: do not load attributes
/// for proper wave scaling, the attributes must be loaded
/// @param progress 1 (default): show progress window; 0: do not show progress window
///
function /s adh5_load_reduced(ANickName, APathName, AFileName, reduction_func, reduction_param, [load_data, load_attr, progress]) function /s adh5_load_reduced(ANickName, APathName, AFileName, reduction_func, reduction_param, [load_data, load_attr, progress])
// this function loads a reduced dataset from a HDF5 file created by the Area Detector software. string ANickName
// the resulting dataset is reduced in one image dimension by a user-defined reduction function, string APathName
// e.g. by region-of-interest integration, curve fitting, etc. string AFileName
// the function loads the dataset image by image using the hyperslab option funcref adh5_default_reduction reduction_func
// and applies a custom reduction function to each image. string reduction_param
// the results from the reduction function are composed into one result wave.
// the raw data are discarded.
// if the data is from the electron analyser driver and some special attributes are included, variable load_data
// the function will set the scales of the image dimensions. variable load_attr
string ANickName // destination folder name (top level under root) variable progress
string APathName // igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed
string AFileName // if empty a dialog box shows up
funcref adh5_default_reduction reduction_func // custom reduction function
// (any user-defined function which has the same parameters as adh5_default_reduction())
string reduction_param // parameter string for the reduction function
variable load_data // 1 (default): load data; 0: do not load data
variable load_attr // 1 (default): load attributes; 0: do not load attributes
// for proper wave scaling, the attributes must be loaded
variable progress // 1 (default): show progress window; 0: do not show progress window
if (ParamIsDefault(load_data)) if (ParamIsDefault(load_data))
load_data = 1 load_data = 1
@ -306,18 +362,26 @@ function /s adh5_load_reduced(ANickName, APathName, AFileName, reduction_func, r
return AFileName return AFileName
end end
/// load a single image from a HDF5 file created by the Area Detector software.
///
/// the data wave is loaded into the current data folder.
/// attributes are loaded into the attr subfolder. existing waves in attr are deleted.
///
/// @warning EXPERIMENTAL
/// this function uses the root:pearl_area:preview data folder. existing data there may be deleted!
///
/// @param ANickName destination wave name. the wave is created in the current data folder.
/// @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 load_data 1 (default): load data; 0: do not load data
/// @param load_attr 1 (default): load attributes; 0: do not load attributes
/// note: for correct scaling of the image, the attributes need to be loaded
function /s adh5_load_preview(ANickName, APathName, AFileName, [load_data, load_attr]) function /s adh5_load_preview(ANickName, APathName, AFileName, [load_data, load_attr])
// this function loads one image from a HDF5 file created by the Area Detector software. string ANickName
// the data wave is loaded into the current data folder. string APathName
// attributes are loaded into the attr subfolder. existing waves in attr are deleted. string AFileName
// EXPERIMENTAL variable load_data
// this function uses the root:pearl_area:preview data folder. existing data there may be deleted! variable load_attr
string ANickName // destination wave name. the wave is created in the current data folder.
string APathName // igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed
string AFileName // if empty a dialog box shows up
variable load_data // 1 (default): load data; 0: do not load data
variable load_attr // 1 (default): load attributes; 0: do not load attributes
// note: for correct scaling of the image, the attributes need to be loaded
if (ParamIsDefault(load_data)) if (ParamIsDefault(load_data))
load_data = 1 load_data = 1
@ -412,13 +476,19 @@ function /s adh5_load_preview(ANickName, APathName, AFileName, [load_data, load_
return AFileName return AFileName
end end
/// load descriptive info from a HDF5 file created by the Area Detector software.
///
/// the information returned is the array size and active scans
///
/// @attention EXPERIMENTAL
/// this function should be merged with adh5_load_preview
///
/// @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
///
function /s adh5_load_info(APathName, AFileName) function /s adh5_load_info(APathName, AFileName)
// this function loads descriptive info from a HDF5 file created by the Area Detector software. string APathName
// the information returned is the array size and active scans string AFileName
// EXPERIMENTAL
// this function should be merged with adh5_load_preview
string APathName // igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed
string AFileName // if empty a dialog box shows up
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
@ -492,12 +562,17 @@ function /s adh5_load_info(APathName, AFileName)
return s_info return s_info
end end
/// load the detector dataset from the open HDF5 file.
///
/// the function loads the whole dataset at once
/// and redimensions it so that the image dimensions are X and Y
///
/// @param fileID ID of open HDF5 file from HDF5OpenFile
/// @param detectorpath path to detector group in the HDF5 file
///
function adh5_load_detector(fileID, detectorpath) function adh5_load_detector(fileID, detectorpath)
// loads the detector dataset from the open HDF5 file variable fileID
// the function loads the whole dataset at once string detectorpath
// and redimensions it so that the image dimensions are X and Y
variable fileID // ID of open HDF5 file from HDF5OpenFile
string detectorpath // path to detector group in the HDF5 file
// avoid compilation error if HDF5 XOP has not been loaded // avoid compilation error if HDF5 XOP has not been loaded
#if Exists("HDF5LoadData") #if Exists("HDF5LoadData")
@ -526,19 +601,22 @@ function adh5_load_detector(fileID, detectorpath)
#endif #endif
end end
/// redimension a multi-dimensional area detector array loaded from HDF5.
///
/// so that the image dimensions are X and Y
/// singleton dimensions are removed (most common cases only)
///
/// in the redimensioned array, the original dimension type is noted in the dimension label:
/// AD_Dim0 = first image dimension
/// AD_Dim1 = second image dimension
/// AD_DimN = frame sequence
/// AD_DimX = extra dimension X
/// AD_DimY = extra dimension Y (cannot be loaded in Igor)
///
/// @param data area detector data loaded from HDF5 to be redimensioned
///
function adh5_redim(data) function adh5_redim(data)
// redimensions a multi-dimensional area detector array loaded from HDF5 wave data
// so that the image dimensions are X and Y
// singleton dimensions are removed (most common cases only)
// in the redimensioned array, the original dimension type is noted in the dimension label:
// AD_Dim0 = first image dimension
// AD_Dim1 = second image dimension
// AD_DimN = frame sequence
// AD_DimX = extra dimension X
// AD_DimY = extra dimension Y (cannot be loaded in Igor)
wave data // area detector data loaded from HDF5 to be redimensioned
duplicate /free data, tempdata duplicate /free data, tempdata
variable nd = wavedims(tempdata) variable nd = wavedims(tempdata)
@ -608,29 +686,36 @@ function adh5_redim(data)
endswitch endswitch
end end
/// find the attributes data folder of an area detector dataset.
///
/// since version 1.04 attributes should be stored in a subfolder named attr.
/// earlier versions had the attributes in the same data folder as the actual dataset.
///
/// @param data wave containing the main dataset.
///
/// @return data folder reference of the attributes folder.
/// the reference may be invalid (and default to root) if the folder cannot be found,
/// cf. built-in DataFolderRefStatus function.
static function /DF GetAttrDataFolderDFR(data) static function /DF GetAttrDataFolderDFR(data)
// returns a data folder reference to the ND attributes
// since version 1.04 attributes should be written in a subfolder named attr
// earlier versions had the attributes in the same data folder as the actual dataset
wave data wave data
dfref saveDF = GetDataFolderDFR()
dfref dataDF = GetWavesDataFolderDFR(data) dfref dataDF = GetWavesDataFolderDFR(data)
setdatafolder dataDF dfref attrDF = dataDF:attr
if (DataFolderExists(":attr")) if (DataFolderRefStatus(attrDF) == 0)
setdatafolder :attr attrDF = dataDF
endif endif
dfref attrDF = GetDataFolderDFR()
setdatafolder saveDF
return attrDF return attrDF
end end
/// set the dimension scales of an area detector dataset.
///
/// the intrinsic dimensions 0 and 1 are scaled according to the data source
/// (currently supported: Prosilica cameras, Scienta electron analyser).
/// the extra dimensions are scaled according to the scan.
/// the latter requires that the positioner names and position values are available.
///
function adh5_scale(data,[source]) function adh5_scale(data,[source])
// tries to set the dimension scales of an area detector dataset.
// the intrinsic dimensions 0 and 1 are scaled according to the data source
// (currently supported: Prosilica cameras, Scienta electron analyser).
// the extra dimensions are scaled according to the scan.
// the latter requires that the positioner names and position values are available.
wave data wave data
string source string source
@ -671,14 +756,23 @@ function adh5_scale(data,[source])
setdatafolder saveDF setdatafolder saveDF
end end
/// load the detector dataset from the open HDF5 file.
///
/// the function loads the dataset image by image using the hyperslab option.
/// this function gives the same result as adh5_load_detector.
/// it is about 5% slower, and it depends on HDF5 Browser code.
/// but it does not choke on large datasets (as long as the final wave fits into memory).
///
/// @param fileID ID of open HDF5 file from HDF5OpenFile.
/// @param detectorpath path to detector group in the HDF5 file.
/// @param progress 1 (default): show progress window; 0: do not show progress window.
///
/// @return 0 if successful, non-zero if an error occurred.
///
function adh5_load_detector_slabs(fileID, detectorpath, [progress]) function adh5_load_detector_slabs(fileID, detectorpath, [progress])
// loads the detector dataset from the open HDF5 file variable fileID
// the function loads the dataset image by image using the hyperslab option string detectorpath
// this function gives the same result as adh5_load_detector variable progress
// it is about 5% slower, and it depends on HDF5 Browser code.
variable fileID // ID of open HDF5 file from HDF5OpenFile
string detectorpath // path to detector group in the HDF5 file
variable progress // 1 (default): show progress window; 0: do not show progress window
if (ParamIsDefault(progress)) if (ParamIsDefault(progress))
progress = 1 progress = 1
@ -821,23 +915,32 @@ function adh5_load_detector_slabs(fileID, detectorpath, [progress])
return result return result
end end
/// load a single image from the detector dataset of the open HDF5 file
///
/// the function can average over a region in the extra dimensions.
///
/// @param fileID ID of open HDF5 file from HDF5OpenFile
/// @param detectorpath path to detector group in the HDF5 file
/// @param dim2start 2nd dimension coordinate of the first image
/// note that the order of dimensions is reversed in the file
/// 2nd dimension = N dimension in area detector = dimension 0 of the three-dimensional HDF dataset
/// set to 0 if dimension may not be present
/// @param dim2count number of subsequent images to average
/// set to 1 if dimension may not be present
/// @param dim3start 3rd dimension coordinate of the first image
/// note that the order of dimensions is reversed in the file
/// 3rd dimension = extra X dimension in area detector = dimension 0 of the four-dimensional HDF dataset
/// set to 0 if dimension may not be present
/// @param dim3count number of subsequent images to average
/// set to 1 if dimension may not be present
///
function adh5_load_detector_image(fileID, detectorpath, dim2start, dim2count, dim3start, dim3count) function adh5_load_detector_image(fileID, detectorpath, dim2start, dim2count, dim3start, dim3count)
// loads a single image from the detector dataset of the open HDF5 file variable fileID
// the function can average over a region in the extra dimensions string detectorpath
variable fileID // ID of open HDF5 file from HDF5OpenFile variable dim2start
string detectorpath // path to detector group in the HDF5 file variable dim2count
variable dim2start // 2nd dimension coordinate of the first image variable dim3start
// note that the order of dimensions is reversed in the file variable dim3count
// 2nd dimension = N dimension in area detector = dimension 0 of the three-dimensional HDF dataset
// set to 0 if dimension may not be present
variable dim2count // number of subsequent images to average
// set to 1 if dimension may not be present
variable dim3start // 3rd dimension coordinate of the first image
// note that the order of dimensions is reversed in the file
// 3rd dimension = extra X dimension in area detector = dimension 0 of the four-dimensional HDF dataset
// set to 0 if dimension may not be present
variable dim3count // number of subsequent images to average
// set to 1 if dimension may not be present
// avoid compilation error if HDF5 XOP has not been loaded // avoid compilation error if HDF5 XOP has not been loaded
#if Exists("HDF5LoadData") #if Exists("HDF5LoadData")
@ -922,10 +1025,12 @@ function adh5_load_detector_image(fileID, detectorpath, dim2start, dim2count, di
#endif #endif
end end
/// get a list of functions which can be used as reduction functions.
///
/// the function evaluates only the function arguments,
/// it may thus include functions which are not suitable as reduction functions.
///
function /s adh5_list_reduction_funcs() function /s adh5_list_reduction_funcs()
// returns a list of functions which can be used as reduction functions
// the function evaluates only the function arguments,
// it may thus include functions which are not suitable as reduction functions.
string all_funcs = FunctionList("*", ";", "KIND:6,NPARAMS:4,VALTYPE:1") string all_funcs = FunctionList("*", ";", "KIND:6,NPARAMS:4,VALTYPE:1")
string result = "" string result = ""
@ -960,26 +1065,35 @@ function /s adh5_list_reduction_funcs()
return result return result
end end
/// function prototype for adh5_load_reduced_detector
///
/// derived functions reduce a two-dimensional dataset to a one-dimensional dataset,
/// e.g. by ROI-integration, curve fitting, etc.
// the resulting wave must have the same size as either dimension of the source image.
///
/// each destination wave is a one-dimensional intensity distribution.
/// the function must redimension each of these waves to one of the image dimensions
/// by calling the adh5_setup_profile() function.
/// this function will also copy the scale information and dimension labels,
/// which is important for the proper scaling of the result.
///
/// the meaning of the data in 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 source source wave
/// two-dimensional intensity distribution (image)
/// @param dest1, dest2 destination waves
/// @param param string with optional parameters, shared between calls.
/// this is a pass-by-reference argument,
/// the function may modify the string
///
/// @return zero if successful, non-zero if an error occurs.
///
threadsafe function adh5_default_reduction(source, dest1, dest2, param) threadsafe function adh5_default_reduction(source, dest1, dest2, param)
// function prototype for adh5_load_reduced_detector wave source
// derived functions reduce a two-dimensional dataset to a one-dimensional dataset, wave dest1, dest2
// e.g. by ROI-integration, curve fitting, etc. string &param
// the resulting wave must have the same size as either dimension of the source image.
wave source // source wave
// two-dimensional intensity distribution (image)
wave dest1, dest2 // destination waves
// each wave is a one-dimensional intensity distribution
// the function must redimension each of these waves to one of the image dimensions
// by calling the adh5_setup_profile() function.
// this function will also copy the scale information and dimension labels,
// which is important for the proper scaling of the result.
// the meaning of the data in 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.
string &param // string with optional parameters, shared between calls
// this is a pass-by-reference argument,
// the function may modify the string
// demo code // demo code
// integrate along the dimensions // integrate along the dimensions
@ -988,13 +1102,15 @@ threadsafe function adh5_default_reduction(source, dest1, dest2, param)
adh5_setup_profile(source, dest2, 1) adh5_setup_profile(source, dest2, 1)
ad_profile_y_w(source, 0, -1, dest2) ad_profile_y_w(source, 0, -1, dest2)
return 0 // return zero if successful, non-zero if an error occurs return 0
end end
/// set up a one-dimensional wave for a line profile based on a 2D original wave.
///
/// redimensions the profile wave to the given dimension.
/// copies the scale and dimension label of the given dimension.
///
threadsafe function adh5_setup_profile(image, profile, dim) threadsafe function adh5_setup_profile(image, profile, dim)
// sets up a one-dimensional wave for a line profile based on a 2D original wave
// redimensions the profile wave to the given dimension
// copies the scale and dimension label of the given dimension
wave image // prototype wave image // prototype
wave profile // destination wave wave profile // destination wave
variable dim // which dimension to keep: 0 = X, 1 = Y variable dim // which dimension to keep: 0 = X, 1 = Y
@ -1005,10 +1121,11 @@ threadsafe function adh5_setup_profile(image, profile, dim)
setdimlabel 0, -1, $getdimlabel(image, dim, -1), profile setdimlabel 0, -1, $getdimlabel(image, dim, -1), profile
end end
/// wrapper function for testing reduction functions from the command line.
///
/// Igor does not allow global variables as pass-by-reference parameter for reduction_param.
///
function /s adh5_test_reduction_func(source, dest1, dest2, reduction_func, reduction_param) function /s adh5_test_reduction_func(source, dest1, dest2, reduction_func, reduction_param)
// wrapper function for testing reduction functions from the command line.
// Igor does not allow global variables as pass-by-reference parameter for reduction_param.
wave source wave source
wave dest1 wave dest1
wave dest2 wave dest2
@ -1020,28 +1137,35 @@ function /s adh5_test_reduction_func(source, dest1, dest2, reduction_func, reduc
return reduction_param return reduction_param
end end
/// load a reduced detector dataset from the open HDF5 file.
///
/// 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 composed into one result wave.
/// the raw data are discarded.
///
/// by default, the reduction function is called in separate threads to reduce the total loading time.
/// (see the global variable adh5_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 fileID ID of open HDF5 file from HDF5OpenFile
/// @param detectorpath path to detector group in the HDF5 file
/// @param reduction_func custom reduction function
/// (any user-defined function which has the same parameters as adh5_default_reduction())
/// @param reduction_param parameter string for the reduction function
/// @param progress 1 (default): show progress window; 0: do not show progress window
/// @param nthreads -1 (default): use as many threads as there are processor cores (in addition to main thread)
/// 0: use main thread only (e.g. for debugging the reduction function)
/// >= 1: use a fixed number of (additional) threads
function adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduction_param, [progress, nthreads]) function adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduction_param, [progress, nthreads])
// loads a reduced detector dataset from the open HDF5 file variable fileID
// the function loads the dataset image by image using the hyperslab option string detectorpath
// and applies a custom reduction function to each image. funcref adh5_default_reduction reduction_func
// the results from the reduction function are composed into one result wave. string reduction_param
// the raw data are discarded. variable progress
variable nthreads
// by default, the reduction function is called in separate threads to reduce the total loading time.
// (see the global variable adh5_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.
variable fileID // ID of open HDF5 file from HDF5OpenFile
string detectorpath // path to detector group in the HDF5 file
funcref adh5_default_reduction reduction_func // custom reduction function
// (any user-defined function which has the same parameters as adh5_default_reduction())
string reduction_param // parameter string for the reduction function
variable progress // 1 (default): show progress window; 0: do not show progress window
variable nthreads // -1 (default): use as many threads as there are processor cores (in addition to main thread)
// 0: use main thread only (e.g. for debugging the reduction function)
// >= 1: use a fixed number of (additional) threads
if (ParamIsDefault(progress)) if (ParamIsDefault(progress))
progress = 1 progress = 1
@ -1340,17 +1464,21 @@ threadsafe static function reduce_slab_image(slabdata, image, profile1, profile2
return reduction_func(image, profile1, profile2, reduction_param) return reduction_func(image, profile1, profile2, reduction_param)
end end
/// load an NDAttributes group from an open HDF5 file into the current data folder.
///
/// datasets contained in the group are loaded as waves.
/// if a dataset contains only one data point, it is added to the IN, ID, IV, IU waves,
/// where IN = EPICS channel name, ID = attribute name, IV = value, IU = unit
/// (units are left empty as they are not saved in HDF5).
/// attributes of the NDAttributes group are added to the IN, ID, IV, IU waves,
/// however, IN and IU are left empty as this information is not saved in the HDF5 file.
///
/// @param fileID ID of open HDF5 file from HDF5OpenFile
/// @param attributespath path to NDAttributes group in the HDF5 file
///
function adh5_loadattr_all(fileID, attributespath) function adh5_loadattr_all(fileID, attributespath)
// loads an NDAttributes group from an open HDF5 file into the current data folder. variable fileID
// datasets contained in the group are loaded as waves. string attributespath
// if a dataset contains only one data point, it is added to the IN, ID, IV, IU waves,
// where IN = EPICS channel name, ID = attribute name, IV = value, IU = unit
// (units are left empty as they are not saved in HDF5).
// attributes of the NDAttributes group are added to the IN, ID, IV, IU waves,
// however, IN and IU are left empty as this information is not saved in the HDF5 file.
variable fileID // ID of open HDF5 file from HDF5OpenFile
string attributespath // path to NDAttributes group in the HDF5 file
string datasetname string datasetname
string datawavename string datawavename
@ -1417,11 +1545,20 @@ function adh5_loadattr_all(fileID, attributespath)
end end
/// sub-function of adh5_loadattr_all.
///
/// reads one attribute from a wave which was loaded from an HDF5 file into the info waves IN, ID, IV, IU.
/// the attribute is read only if the input wave contains exactly one item,
/// i.e. either the measurement is a single image, or the attribute has string type.
///
/// @param datawavename name of the attribute wave in the current folder.
/// can be text or numeric.
/// @param source source identifier (EPICS name) of the attribute.
/// @param idest destination index in IN, ID, IV, IU where the results are written.
/// the variable is incremented if data was written, otherwise it is left unchanged.
/// make sure IN, ID, IV, IU have at least idest + 1 elements.
///
static function read_attribute_info(datawavename, source, idest) static function read_attribute_info(datawavename, source, idest)
// sub-function of adh5_loadattr_all.
// reads one attribute from a wave which was loaded from an HDF5 file into the info waves IN, ID, IV, IU.
// the attribute is read only if the input wave contains exactly one item,
// i.e. either the measurement is a single image, or the attribute has string type.
string datawavename // name of the attribute wave in the current folder. string datawavename // name of the attribute wave in the current folder.
// can be text or numeric. // can be text or numeric.
string source string source
@ -1467,12 +1604,14 @@ static function read_attribute_info(datawavename, source, idest)
endif endif
end end
/// set the energy and angle scales of an area detector dataset from the Scienta analyser.
///
/// the dimension labels of the energy and angle scales must be set correctly:
/// AD_Dim0 = energy dimension; AD_Dim1 = angle dimension.
/// these dimensions must be the first two dimensions of a multi-dimensional dataset.
/// normally, AD_Dim0 is the X dimension, and AD_Dim1 the Y dimension.
///
function adh5_scale_scienta(data) function adh5_scale_scienta(data)
// sets the energy and angle scales of an area detector dataset from the Scienta analyser
// the dimension labels of the energy and angle scales must be set correctly:
// AD_Dim0 = energy dimension; AD_Dim1 = angle dimension
// these dimensions must be the first two dimensions of a multi-dimensional dataset.
// normally, AD_Dim0 is the X dimension, and AD_Dim1 the Y dimension.
wave data wave data
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
@ -1571,11 +1710,13 @@ function adh5_scale_scienta(data)
setdatafolder saveDF setdatafolder saveDF
end end
/// scales the extra dimensions of an area detector dataset according to the EPICS scan
///
/// the scan positioner name and its values must be available
///
/// @todo incomplete
///
function adh5_scale_scan(data) function adh5_scale_scan(data)
// scales the extra dimensions of an area detector dataset according to the EPICS scan
// the scan positioner name and its values must be available
// TODO: incomplete
wave data wave data
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()

View File

@ -1,368 +0,0 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlAreaLive
#pragma version = 1.03
#include "pearl-epics", version >= 1.02
// preview panel for EPICS area detectors
// such as CCD cameras, 2D electron analysers
// the image is read from the NDPluginStdArrays plugin of the area detector
// make sure that plugin is enabled
// created: matthias.muntwiler@psi.ch, 2013-05-29
// $Id$
static strconstant package_name = "pearl_epics"
static strconstant package_path = "root:pearl_epics:"
// semicolon-separated list of persistent variable, string, and wave names
static strconstant prefs_objects = ""
function ad_connect(epicsname, nickname)
// connects to the necessary EPICS channels of the detector
// to disconnect, call epics_disconnect()
// (caution: this will disconnect all EPICS channels of all PEARL EPICS procedures!)
string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
// image1: and cam1: are appended by the function
string nickname // nick name under which this detector is referred to in Igor
// must be a valid data folder name
// the data folder is created under root:pearl_epics
dfref savedf = GetDataFolderDFR()
setdatafolder root:
// data folder for common EPICS metadata
newdatafolder /o/s $package_name
dfref epicsdf = GetDataFolderDFR()
string /g ad_chids
string /g ad_nicknames
// data folder this detector
string foldername = nickname
newdatafolder /s/o $foldername
dfref detectordf = GetDataFolderDFR()
// create variables and waves
make /n=(1)/o arraydata, xscale, yscale
make /n=(1,1)/o image
variable /g ndimensions
variable /g arraysize0, arraysize1
variable /g datatype
variable /g colormode
string /g controls, monitors
string /g xunits, yunits
print "connecting EPICS channels..."
// channel lists
controls = ""
monitors = ""
string imagename = epicsname + "image1:"
string camname = epicsname + "cam1:"
// we will set our own monitor on ArrayData, so add this to the controls list
controls = ReplaceStringByKey("ArrayData", controls, imagename + "ArrayData", "=")
// check whether it has been set already
variable chidArrayData = epics_chid(imagename + "ArrayData")
variable array_connected = chidArrayData > 0
monitors = ReplaceStringByKey("NDimensions", monitors, imagename + "NDimensions_RBV", "=")
monitors = ReplaceStringByKey("ArraySize0", monitors, imagename + "ArraySize0_RBV", "=")
monitors = ReplaceStringByKey("ArraySize1", monitors, imagename + "ArraySize1_RBV", "=")
monitors = ReplaceStringByKey("DataType", monitors, imagename + "DataType_RBV", "=")
monitors = ReplaceStringByKey("ColorMode", monitors, imagename + "ColorMode_RBV", "=")
monitors = ReplaceStringByKey("XScale", monitors, camname + "CHANNEL_SCALE_RBV", "=")
monitors = ReplaceStringByKey("YScale", monitors, camname + "SLICE_SCALE_RBV", "=")
variable nroi = 4
variable iroi
string roikey, roiname
for (iroi = 0; iroi < nroi; iroi += 1)
roikey = "ROI" + num2str(iroi + 1)
roiname = epicsname + "ROI" + num2str(iroi + 1) + ":"
controls = ReplaceStringByKey(roikey + "Enable", controls, roiname + "EnableCallbacks", "=")
controls = ReplaceStringByKey(roikey + "EnableX", controls, roiname + "EnableX", "=")
controls = ReplaceStringByKey(roikey + "MinX", controls, roiname + "MinX", "=")
controls = ReplaceStringByKey(roikey + "SizeX", controls, roiname + "SizeX", "=")
controls = ReplaceStringByKey(roikey + "EnableY", controls, roiname + "EnableY", "=")
controls = ReplaceStringByKey(roikey + "MinY", controls, roiname + "MinY", "=")
controls = ReplaceStringByKey(roikey + "SizeY", controls, roiname + "SizeY", "=")
monitors = ReplaceStringByKey(roikey + "Enable", monitors, roiname + "EnableCallbacks_RBV", "=")
monitors = ReplaceStringByKey(roikey + "EnableX", monitors, roiname + "EnableX_RBV", "=")
monitors = ReplaceStringByKey(roikey + "MinX", monitors, roiname + "MinX_RBV", "=")
monitors = ReplaceStringByKey(roikey + "SizeX", monitors, roiname + "SizeX_RBV", "=")
monitors = ReplaceStringByKey(roikey + "EnableY", monitors, roiname + "EnableY_RBV", "=")
monitors = ReplaceStringByKey(roikey + "MinY", monitors, roiname + "MinY_RBV", "=")
monitors = ReplaceStringByKey(roikey + "SizeY", monitors, roiname + "SizeY_RBV", "=")
endfor
// connect EPICS channels
epics_connect(controls, monitors)
// keep track of detector IDs
ad_nicknames = AddListItem(nickname, ad_nicknames)
variable iad = WhichListItem(nickname, ad_nicknames, ";", 0, 0)
ad_chids = AddListItem(num2istr(epics_chid(imagename + "ArrayData")), ad_chids, ";", iad)
// set callback function
if (!array_connected)
pvMonitor /F=ad_live_callback epics_chid(imagename + "ArrayData")
endif
print "...done"
setdatafolder savedf
end
function ad_live_callback(chan)
variable chan
dfref savedf = GetDataFolderDFR()
setdatafolder $package_path
// find the data folder of the detector
svar ad_chids
svar ad_nicknames
variable iad = WhichListItem(num2istr(chan), ad_chids, ";", 0, 0)
if (iad >= 0)
string nickname = StringFromList(iad, ad_nicknames)
else
return -1
endif
setdatafolder $nickname
// retrieve data
svar controls
svar monitors
variable chidArrayData = epics_chid(StringByKey("ArrayData", controls, "="))
variable chidNDimensions = epics_chid(StringByKey("NDimensions", monitors, "="))
variable chidArraySize0 = epics_chid(StringByKey("ArraySize0", monitors, "="))
variable chidArraySize1 = epics_chid(StringByKey("ArraySize1", monitors, "="))
variable chidDataType = epics_chid(StringByKey("DataType", monitors, "="))
variable chidColorMode = epics_chid(StringByKey("ColorMode", monitors, "="))
variable chidXScale = epics_chid(StringByKey("XScale", monitors, "="))
variable chidYScale = epics_chid(StringByKey("YScale", monitors, "="))
wave arraydata
wave image
nvar ndimensions
nvar arraysize0
nvar arraysize1
nvar datatype
nvar colormode
wave xscale
wave yscale
pvGet chidNDimensions, ndimensions
pvGet chidArraySize0, arraysize0
pvGet chidArraySize1, arraysize1
pvGet chidDataType, datatype
pvGet chidColorMode, colormode
// sanity checks
if (ndimensions != 2)
return -2
endif
if (colormode != 0)
return -3
endif
redimension /n=(arraysize0 * arraysize1) arraydata
redimension /n=(arraysize0, arraysize1) image
redimension /n=(arraysize0) xscale
redimension /n=(arraysize1) yscale
switch(datatype)
case 0: // int8
redimension /b arraydata, image
break
case 1: // uint8
redimension /b/u arraydata, image
break
case 2: // int16
redimension /w arraydata, image
break
case 3: // uint16
redimension /w/u arraydata, image
break
case 4: // int32
redimension /i arraydata, image
break
case 5: // uint32
redimension /i/u arraydata, image
break
case 6: // float32
redimension /s arraydata, image
break
case 7: // float64
redimension /d arraydata, image
break
endswitch
pvGetWave chidArrayData, arraydata
pvGetWave chidXScale, xscale
pvGetWave chidYScale, yscale
image = arraydata[p + q * arraysize0]
setscale /i x xscale[0], xscale[numpnts(xscale)-1], image
setscale /i y yscale[0], yscale[numpnts(yscale)-1], image
ad_update_profiles(image)
// update ROI rectangles
svar /z graphname = :view_image:prof_graphname
if (svar_exists(graphname))
variable nroi = 4
variable iroi
for (iroi = 0; iroi < nroi; iroi += 1)
ad_update_ROI(graphname, iroi)
endfor
endif
setdatafolder savedf
return 0
end
static function ad_update_ROI(graphname, iroi)
string graphname
variable iroi
string roikey
variable enable
svar monitors
wave xscale
wave yscale
variable enableX = 0
variable minX = 0
variable sizeX = numpnts(xscale)
variable enableY = 0
variable minY = 0
variable sizeY = numpnts(yscale)
roikey = "ROI" + num2str(iroi + 1)
enable = epics_get_num(StringByKey(roikey + "Enable", monitors, "="))
if (enable)
enableX = epics_get_num(StringByKey(roikey + "EnableX", monitors, "="))
if (enableX)
minX = epics_get_num(StringByKey(roikey + "MinX", monitors, "="))
sizeX = epics_get_num(StringByKey(roikey + "SizeX", monitors, "="))
endif
enableY = epics_get_num(StringByKey(roikey + "EnableY", monitors, "="))
if (enableY)
minY = epics_get_num(StringByKey(roikey + "MinY", monitors, "="))
sizeY = epics_get_num(StringByKey(roikey + "SizeY", monitors, "="))
endif
variable x1 = xscale[minX]
variable x2 = xscale[minX + sizeX - 1]
variable y1 = yscale[minY]
variable y2 = yscale[minY + sizeY - 1]
endif
ad_update_ROI_rect(graphname, iroi, x1, y1, x2, y2, enable)
end
static function ad_update_ROI_rect(graphname, iroi, x1, y1, x2, y2, enable)
string graphname
variable iroi // 0...3
variable x1,y1,x2,y2
variable enable // enable = 1; disable = 0
string roiname = "roi" + num2str(iroi + 1)
variable color = 65536 * (1 - iroi/8) - 1
if (enable)
DrawAction /w=$graphname getgroup=$roiname, delete, begininsert
SetDrawEnv /w=$graphname gstart,gname=$roiname
SetDrawEnv /w=$graphname xcoord= bottom,ycoord= left
SetDrawEnv /w=$graphname linefgc= (65535,color,color)
SetDrawEnv /w=$graphname fillpat= 0
SetDrawEnv /w=$graphname linethick= 0.50
DrawRect /w=$graphname x1,y1,x2,y2
SetDrawEnv /w=$graphname gstop
DrawAction /w=$graphname endinsert
else
DrawAction /w=$graphname getgroup=$roiname, delete
endif
end
function ad_set_ROI(nickname, iroi, p1, q1, p2, q2, enable)
// set a ROI rectangle to the given coordinates
string nickname
variable iroi // 0...3
variable p1,q1,p2,q2 // rectangular coordinates of the new ROI (point scaling)
variable enable // enable = 1; disable = 0
string roiname = "roi" + num2str(iroi + 1)
string roikey
dfref savedf = GetDataFolderDFR()
setdatafolder $package_path
setdatafolder $nickname
svar controls
wave xscale
wave yscale
variable minX = min(p1, p2)
variable sizeX = max(p1, p2) - min(p1, p2) + 1
variable enableX = sizeX > 0
variable minY = min(q1, q2)
variable sizeY = max(q1, q2) - min(q1, q2) + 1
variable enableY = sizeY > 0
roikey = "ROI" + num2str(iroi + 1)
epics_set_num(StringByKey(roikey + "Enable", controls, "="), enable)
if (enable)
epics_set_num(StringByKey(roikey + "EnableX", controls, "="), enableX)
if (enableX)
epics_set_num(StringByKey(roikey + "MinX", controls, "="), minX)
epics_set_num(StringByKey(roikey + "SizeX", controls, "="), sizeX)
endif
epics_set_num(StringByKey(roikey + "EnableY", controls, "="), enableY)
if (enableY)
epics_set_num(StringByKey(roikey + "MinY", controls, "="), minY)
epics_set_num(StringByKey(roikey + "SizeY", controls, "="), sizeY)
endif
endif
svar graphname = :view_image:prof_graphname
ad_update_ROI(graphname, iroi)
setdatafolder savedf
end
function add_roi_controls()
PopupMenu pm_set_roi mode=0,value="ROI 1;ROI 2;ROI 3;ROI 4",title="Set ROI"
PopupMenu pm_set_roi pos={400,0},bodyWidth=60,proc=PearlAreaLive#pmp_set_roi
PopupMenu pm_set_roi help={"Set a detector ROI to the current cursor selection"}
end
static function pmp_set_roi(pa) : PopupMenuControl
STRUCT WMPopupAction &pa
switch( pa.eventCode )
case 2: // mouse up
variable popNum = pa.popNum
string imgname = StringFromList(0, ImageNameList(pa.win, ";"))
wave /z image = ImageNameToWaveRef(pa.win, imgname)
if (waveexists(image))
wave /z source = PearlAreaDisplay#get_source_image(image)
if (waveexists(source))
dfref sourcedf = GetWavesDataFolderDFR(source)
string nickname = GetDataFolder(0, sourcedf)
ad_set_ROI(nickname, popNum - 1, pcsr(A, pa.win), qcsr(A, pa.win), pcsr(B, pa.win), qcsr(B, pa.win), 1)
endif
endif
break
case -1: // control being killed
break
endswitch
return 0
End

View File

@ -1,454 +0,0 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlAreaProfilesTest
#pragma version = 1.02
#include "pearl-area-profiles"
#include "unit-testing"
/// @file
/// @brief test suite for pearl-area-profiles.ipf
///
/// unit testing framework: http://www.igorexchange.com/project/unitTesting.
/// run all test cases with <code>RunTest("pearl-area-profiles-test.ipf")</code>.
/// if wave equalities fail, EnableDebugOutput() and read Igor help on equalWaves().
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2013-15 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 PearlAreaProfilesTest
/// @brief profile extraction for multi-dimensional datasets acquired from area detectors.
///
/// PearlAreaProfilesTest is declared in @ref pearl-area-profiles-test.ipf.
///
/// test the ad_profile_x() function
static function test_ad_profile_x_w()
make /n=(11,21) /d /free source
setscale /p x 10, 1, "X", source
setscale /p y 100, 100, "Y", source
setscale d 0, 0, "D", source
source = x + y
make /n=11 /d /free expected
setscale /p x 10, 1, "X", expected
setscale d 0, 0, "D", expected
expected = 30 + 3 * p + 500 + 600 + 700
make /n=1 /d /free result1, result0
variable p1, p2
p1 = 4
p2 = 6
ad_profile_x_w(source, p1, p2, result1, noavg=1)
CHECK_EQUAL_WAVES(result1, expected, tol=1e-6)
expected /= 3
ad_profile_x_w(source, p1, p2, result0, noavg=0)
CHECK_EQUAL_WAVES(result0, expected, tol=1e-6)
end
/// test the ad_profile_y() function
static function test_ad_profile_y_w()
make /n=(11,21) /d /free source
setscale /p x 10, 1, "X", source
setscale /p y 100, 100, "Y", source
setscale d 0, 0, "D", source
source = x + y
make /n=21 /d /free expected
setscale /p x 100, 100, "Y", expected
setscale d 0, 0, "D", expected
expected = 3 * x + 14 + 15 + 16
make /n=1 /d /free result1, result0
variable p1, p2
p1 = 4
p2 = 6
ad_profile_y_w(source, p1, p2, result1, noavg=1)
CHECK_EQUAL_WAVES(result1, expected)
expected /= 3
ad_profile_y_w(source, p1, p2, result0, noavg=0)
CHECK_EQUAL_WAVES(result0, expected)
end
/// test the ad_extract_slab_x() function
static function test_ad_extract_slab_x()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[4][][] = 1
source[5][][] = 1
make /n=(ny,nz) /d /free expected
setscale /i x -2, 2, "Y", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
expected = 2
variable p1, p2
p1 = 4
p2 = 5
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = -inf
p2 = 5
source = y + z
expected = (x + y) * 6
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = 4
p2 = +inf
expected = (x + y) * (nx - 4)
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_slab_y() function
static function test_ad_extract_slab_y()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[][4][] = 1
source[][5][] = 1
make /n=(nx,nz) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
expected = 2
variable p1, p2
p1 = 4
p2 = 5
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = -inf
p2 = 5
source = x + z
expected = (x + y) * 6
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = 4
p2 = +inf
expected = (x + y) * (ny - 4)
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_slab_z() function
static function test_ad_extract_slab_z()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[][][4] = 1
source[][][5] = 1
make /n=(nx,ny) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -2, 2, "Y", expected
setscale d 0, 0, "D", expected
expected = 2
variable p1, p2
p1 = 4
p2 = 5
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = -inf
p2 = 5
source = x + y
expected = (x + y) * 6
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = 4
p2 = +inf
expected = (x + y) * (nz - 4)
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_slab() function
static function test_ad_extract_slab()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(ny,nz) /d /free expected
setscale /i x -2, 2, "Y", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
x1 = 0
x2 = 0
y1 = nan
y2 = nan
z1 = nan
z2 = nan
expected = source[(nx-1)/2][p][q]
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
x1 = -inf
x2 = inf
expected = (x + y) * nx
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
make /n=(nx,nz) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
x1 = nan
x2 = nan
y1 = 0
y2 = 0
z1 = nan
z2 = nan
expected = source[p][(ny-1)/2][q]
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
y1 = -inf
y2 = +inf
expected = (x + y) * ny
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
make /n=(nx,ny) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -2, 2, "Y", expected
setscale d 0, 0, "D", expected
x1 = nan
x2 = nan
y1 = nan
y2 = nan
z1 = 0
z2 = 0
expected = source[p][q][(nz-1)/2]
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
z1 = -inf
z2 = inf
expected = (x + y) * nz
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod_x() function
static function test_ad_extract_rod_x()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[][4][4] = 1
source[][4][5] = 1
source[][5][4] = 1
source[][5][5] = 1
make /n=(nx) /d /free expected
setscale /i x -1, 1, "X", expected
setscale d 0, 0, "D", expected
expected = 4
variable q1, q2
variable r1, r2
q1 = 4
q2 = 5
r1 = 4
r2 = 5
wave result = ad_extract_rod_x(source, q1, q2, r1, r2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_rod_x(source, q1, q2, r1, r2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod() function, X coordinate
static function test_ad_extract_rod__x()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(nx) /d /free expected
setscale /i x -1, 1, "X", expected
setscale d 0, 0, "D", expected
x1 = nan
x2 = nan
y1 = 0
y2 = 0
z1 = 0
z2 = 0
expected = source[p][(ny-1)/2][(nz-1)/2]
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
y1 = -inf
y2 = +inf
z1 = -inf
z2 = +inf
expected = x * ny * nz
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod() function, Y coordinate
static function test_ad_extract_rod__y()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(ny) /d /free expected
setscale /i x -2, 2, "Y", expected
setscale d 0, 0, "D", expected
x1 = 0
x2 = 0
y1 = nan
y2 = nan
z1 = 0
z2 = 0
expected = source[(nx-1)/2][p][(nz-1)/2]
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
x1 = -inf
x2 = +inf
z1 = -inf
z2 = +inf
expected = x * nx * nz
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod() function, Z coordinate
static function test_ad_extract_rod__z()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(nz) /d /free expected
setscale /i x -3, 3, "Z", expected
setscale d 0, 0, "D", expected
x1 = 0
x2 = 0
y1 = 0
y2 = 0
z1 = nan
z2 = nan
expected = source[(nx-1)/2][(ny-1)/2][p]
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
x1 = -inf
x2 = +inf
y1 = -inf
y2 = +inf
expected = x * nx * ny
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end

View File

@ -613,3 +613,36 @@ threadsafe function calc_y_profile_mins(image)
yminlocs[ix] = v_minloc yminlocs[ix] = v_minloc
endfor endfor
end end
/// collect profiles from a multi-scan.
///
/// @warning experimental: name and interface of this function may change.
///
function ad_collect_multiscan_y(dataset, positions, destwave, [noavg])
wave dataset
wave positions
wave destwave
variable noavg
variable tol = (wavemax(positions) - wavemin(positions)) / numpnts(positions) / 100
duplicate /free positions, positions_sorted
sort positions_sorted, positions_sorted
duplicate /free positions_sorted, positions_diff
differentiate /p /meth=2 positions_sorted /d=positions_diff
positions_diff[0] = 1
extract /free positions_sorted, positions_unique, positions_diff > tol
variable n_unique = numpnts(positions_unique)
redimension /n=(dimsize(dataset, 0), n_unique) destwave
variable i
variable nx, ny
for (i = 0; i < n_unique; i += 1)
extract /free dataset, data_extract, abs(positions[q] - positions_unique[i]) < tol
nx = dimsize(dataset, 0)
ny = dimsize(data_extract, 0) / nx
redimension /n=(nx, ny) data_extract
wave profile = ad_profile_x(data_extract, -inf, inf, "", noavg=noavg)
destwave[][i] = profile[p]
endfor
end

View File

@ -1,152 +0,0 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlArpesScans
#pragma version = 1.01
#include "mm-physconst"
#include "pearl-optics-theory"
#include "pearl-epics", version >= 1.01
// EPICS scans of Scienta
// matthias muntwiler, 2013-03-15
// $Id: pearl-optics-scans.ipf 129 2013-06-26 15:53:13Z muntwiler_m $
static strconstant basename = "X03DA-SCIENTA:"
static strconstant camname = "cam1:"
static strconstant hdfname = "HDF1:"
static strconstant imgname = "image1:"
static strconstant statsname = "Stats1:"
function scienta_connect()
dfref savedf = GetDataFolderDFR()
print "connecting EPICS channels..."
// channel lists
string controls = ""
controls += basename + camname + "PASS_ENERGY;"
controls += basename + camname + "LOW_ENERGY;"
controls += basename + camname + "CENTRE_ENERGY;"
controls += basename + camname + "HIGH_ENERGY;"
controls += basename + camname + "LENS_MODE;"
controls += basename + camname + "ACQ_MODE;"
controls += basename + camname + "ENERGY_MODE;"
controls += basename + camname + "DETECTOR_MODE;"
controls += basename + camname + "ELEMENT_SET;"
controls += basename + camname + "STEP_SIZE;"
controls += basename + camname + "SLICES;"
controls += basename + camname + "NumExposures;"
controls += basename + camname + "FRAMES;"
controls += basename + camname + "STEP_TIME;"
string monitors = ""
monitors += basename + camname + "PASS_ENERGY_RBV;"
monitors += basename + camname + "LOW_ENERGY_RBV;"
monitors += basename + camname + "CENTRE_ENERGY_RBV;"
monitors += basename + camname + "HIGH_ENERGY_RBV;"
monitors += basename + camname + "ENERGY_WIDTH_RBV;"
monitors += basename + camname + "LENS_MODE_RBV;"
monitors += basename + camname + "ACQ_MODE_RBV;"
monitors += basename + camname + "ENERGY_MODE_RBV;"
monitors += basename + camname + "DETECTOR_MODE_RBV;"
monitors += basename + camname + "ELEMENT_SET_RBV;"
monitors += basename + camname + "STEP_SIZE_RBV;"
monitors += basename + camname + "SLICES_RBV;"
monitors += basename + camname + "NumExposures_RBV;"
monitors += basename + camname + "CURRENT_CHANNEL_RBV;"
monitors += basename + camname + "TOTAL_POINTS_RBV;"
monitors += basename + camname + "PROGRESS_RBV;"
//monitors += basename + camname + "INT_SPECTRUM;"
monitors += basename + camname + "BinX_RBV;"
monitors += basename + camname + "BinY_RBV;"
monitors += basename + camname + "MinX_RBV;"
monitors += basename + camname + "MinY_RBV;"
monitors += basename + camname + "SizeX_RBV;"
monitors += basename + camname + "SizeY_RBV;"
monitors += basename + camname + "ReverseX_RBV;"
monitors += basename + camname + "ReverseY_RBV;"
// variable name list corresponding to channel lists
string variables = ""
variables = AddListItem("ArrayData", variables, ";", ItemsInList(variables))
// connect EPICS channels
epics_connect(controls, monitors)
print "...done"
setdatafolder savedf
end
function pearl_set_attr_ch(attr_wave_name, attr_channel_name)
string attr_wave_name
string attr_channel_name
variable result
variable chid
pvOpen chid, attr_channel_name
switch(wavetype($attr_wave_name, 1))
case 1: // numeric
wave w_attr = $attr_wave_name
pvPutNumber /Q chid, w_attr[0]
result = 0
break
case 2: // text
wave /t wt_attr = $attr_wave_name
pvPutString /Q chid, wt_attr[0]
result = 0
break
default: // error
result = -1
endswitch
pvClose chid
return result
end
function pearl_set_sscan(scan_rec_num)
variable scan_rec_num
string chan_base = "X03DA-PC:scan" + num2str(scan_rec_num) + ":"
string wave_base = "Scan" + num2str(scan_rec_num)
variable nfields
variable ifield
string wave_name
string chan_name
wave /z w_active = $(wave_base + "Active")
if (WaveExists(w_active))
if (w_active[0] != 0)
nfields = 4
for (ifield = 1; ifield <= nfields; ifield += 1)
sscanf wave_name, "%sPositioner%u", ifield
sscanf chan_name, "%sP%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
sscanf wave_name, "%sReadback%u", ifield
sscanf chan_name, "%sR%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
sscanf wave_name, "%sTrigger%u", ifield
sscanf chan_name, "%sT%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
endfor
nfields = 20
for (ifield = 1; ifield <= nfields; ifield += 1)
sscanf wave_name, "%sDetector%u", ifield
sscanf chan_name, "%sD%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
endfor
endif
endif
end
function pearl_repeat_scan()
// set up a scan according to the attributes of the given dataset
dfref savedf = GetDataFolderDFR()
setdatafolder :attr
setdatafolder savedf
end

View File

@ -5,6 +5,7 @@
#include "pearl-area-display" // 2D and 3D data visualization #include "pearl-area-display" // 2D and 3D data visualization
#include "pearl-area-profiles" // data processing for multi-dimensional datasets #include "pearl-area-profiles" // data processing for multi-dimensional datasets
#include "pearl-area-import" // import data files generated by area detector software #include "pearl-area-import" // import data files generated by area detector software
#include "pearl-pshell-import"
#include "pearl-data-explorer" // preview and import panel for PEARL data #include "pearl-data-explorer" // preview and import panel for PEARL data
#include "pearl-anglescan-process" #include "pearl-anglescan-process"
#include "pearl-anglescan-tracker" // live preview of hemispherical angle scan #include "pearl-anglescan-tracker" // live preview of hemispherical angle scan

View File

@ -1,36 +1,58 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access. #pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1 #pragma IgorVersion = 6.1
#pragma ModuleName = PearlDataExplorer #pragma ModuleName = PearlDataExplorer
#pragma version = 1.41 #pragma version = 1.50
#include "pearl-area-import", version >= 1.06 #include "pearl-area-import"
#include "pearl-area-profiles", version >= 1.04 #include "pearl-area-profiles"
#include "pearl-area-display", version >= 1.04 #include "pearl-area-display"
#include "pearl-pshell-import"
// preview and import panel for PEARL data: #if exists("MFR_OpenResultFile")
// scienta analyser, prosilica cameras, s-scans, otf-scans #include "pearl-matrix-import"
#endif
// $Id$
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2013-14 Paul Scherrer Institut
// copyright (c) 2013-16 Paul Scherrer Institut
//
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0 // http:///www.apache.org/licenses/LICENSE-2.0
/// @file
/// @brief preview and import panel for PEARL data
/// @ingroup ArpesPackage
///
///
/// preview and import panel for PEARL data:
/// @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
///
/// PearlDataExplorer is declared in @ref pearl-data-explorer.ipf.
static strconstant package_name = "pearl_explorer" static strconstant package_name = "pearl_explorer"
static strconstant package_path = "root:packages:pearl_explorer:" 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() function pearl_data_explorer()
init_package() init_package()
load_prefs() load_prefs()
execute /q/z "PearlDataExplorer()" execute /q/z "PearlDataExplorer()"
end end
/// initialize the global variables of the data explorer.
///
/// initializes the global variables and data folder for this procedure file
/// must be called once before the panel is created
/// warning: this function overwrites previous values
static function init_package() static function init_package()
// initializes the global variables and data folder for this procedure file
// must be called once before the panel is created
// warning: this function overwrites previous values
dfref savefolder = GetDataFolderDFR() dfref savefolder = GetDataFolderDFR()
SetDataFolder root: SetDataFolder root:
@ -64,7 +86,8 @@ static function init_package()
string /g s_preview_source = "" // data source, e.g. EPICS channel name, of the current preview string /g s_preview_source = "" // data source, e.g. EPICS channel name, of the current preview
string /g s_profiles_graph = "" // window name of the current preview if the data is two-dimensional string /g s_profiles_graph = "" // window name of the current preview if the data is two-dimensional
string /g s_preview_trace_graph = "" // window name of the current preview if the data is one-dimensional string /g s_preview_trace_graph = "" // window name of the current preview if the data is one-dimensional
string /g s_file_info = "" // description of selected file
variable/g v_InitPanelDone = 1 variable/g v_InitPanelDone = 1
SetDataFolder savefolder SetDataFolder savefolder
@ -124,31 +147,64 @@ static function load_prefs()
return result return result
end 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() static function update_filelist()
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
string hdf_files, itx_files, all_files string all_files
wave /t wtFiles = $(package_path + "wtFiles") wave /t wtFiles = $(package_path + "wtFiles")
wave wSelectedFiles = $(package_path + "wSelectedFiles") wave wSelectedFiles = $(package_path + "wSelectedFiles")
variable nn variable nn
PathInfo pearl_explorer_filepath PathInfo pearl_explorer_filepath
if (v_flag == 1) if (v_flag == 1)
hdf_files = IndexedFile(pearl_explorer_filepath, -1, ".h5") all_files = IndexedFile(pearl_explorer_filepath, -1, "????")
itx_files = IndexedFile(pearl_explorer_filepath, -1, ".itx")
all_files = hdf_files + itx_files
all_files = SortList(hdf_files + itx_files, ";", 4)
nn = ItemsInList(all_files) nn = ItemsInList(all_files)
else else
all_files = "" all_files = ""
nn = 0 nn = 0
endif endif
redimension /n=(nn) wtFiles, wSelectedFiles make /n=(nn) /t /free wtAllFiles
if (nn > 0) wtAllFiles = StringFromList(p, all_files)
wtFiles = StringFromList(p, all_files) Extract /o /t wtAllFiles, wtFiles, pearl_file_type(wtAllFiles[p])
wSelectedFiles = 0 Sort /A /R wtFiles, wtFiles
endif
redimension /n=(numpnts(wtFiles)) wSelectedFiles
wSelectedFiles = 0
setdatafolder saveDF setdatafolder saveDF
end end
@ -200,12 +256,24 @@ static function preview_file(filename)
string filename string filename
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, "*.h5")) variable ft = pearl_file_type(filename)
wave /z image = preview_hdf_file(filename) switch(ft)
elseif (StringMatch(filename, "*.itx")) case 1:
wave /z image = preview_itx_file(filename) wave /z image = preview_pshell_file(filename)
endif 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)) if (WaveExists(image))
string graphname = show_preview_graph(image) string graphname = show_preview_graph(image)
@ -222,6 +290,50 @@ static function preview_file(filename)
endif endif
setdatafolder saveDF setdatafolder saveDF
return 0
end
/// 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.
///
/// 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_pshell_file(filename)
string filename
dfref saveDF = GetDataFolderDFR()
setdatafolder $package_path
svar s_preview_file
svar s_preview_source
psh5_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 = psh5_load_info("pearl_explorer_filepath", filename)
else
s_file_info = ""
endif
if (DataFolderExists("attr"))
setdatafolder attr
preview_attributes(GetDataFolderDFR())
setdatafolder ::
endif
setdatafolder saveDF
return preview_image
end end
/// load the preview of a PEARL HDF5 file. /// load the preview of a PEARL HDF5 file.
@ -293,6 +405,63 @@ static function /wave preview_itx_file(filename)
return preview_image return preview_image
end 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) static function extract_preview_image(data, preview)
// extracts a preview image from a wave of arbitrary dimension // extracts a preview image from a wave of arbitrary dimension
wave data wave data
@ -698,18 +867,21 @@ static function /s show_preview_graph(data, [xdata])
svar s_profiles_graph svar s_profiles_graph
svar s_preview_file svar s_preview_file
svar s_preview_source svar s_preview_source
svar s_preview_trace_graph
if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1))
KillWindow $s_profiles_graph
endif
if ((strlen(s_preview_trace_graph) > 0) && (WinType(s_preview_trace_graph) == 1))
KillWindow $s_preview_trace_graph
endif
string graphname string graphname
if (wavedims(data) == 2) if (wavedims(data) == 2)
if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1)) s_profiles_graph = ad_display_profiles(data)
ad_update_profiles(data) ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160)
else
s_profiles_graph = ad_display_profiles(data)
ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160)
endif
graphname = s_profiles_graph graphname = s_profiles_graph
elseif (wavedims(data) == 1) elseif (wavedims(data) == 1)
svar s_preview_trace_graph
duplicate /o data, preview_trace duplicate /o data, preview_trace
if (!ParamIsDefault(xdata)) if (!ParamIsDefault(xdata))
duplicate /o xdata, preview_trace_x duplicate /o xdata, preview_trace_x
@ -718,20 +890,8 @@ static function /s show_preview_graph(data, [xdata])
preview_trace_x = x preview_trace_x = x
setscale d 0, 0, WaveUnits(data, 0), preview_trace_x setscale d 0, 0, WaveUnits(data, 0), preview_trace_x
endif endif
if ((strlen(s_preview_trace_graph) == 0) || (WinType(s_preview_trace_graph) != 1)) s_preview_trace_graph = display_preview_trace(preview_trace_x, preview_trace)
display /n=pearl_explorer_1d /k=1 preview_trace vs preview_trace_x as "Preview" ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160)
s_preview_trace_graph = s_name
ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160)
ModifyGraph /w=$s_preview_trace_graph rgb[0]=(0,0,0)
ModifyGraph /w=$s_preview_trace_graph grid=2
ModifyGraph /w=$s_preview_trace_graph mirror=1
ModifyGraph /w=$s_preview_trace_graph minor=1
ModifyGraph /w=$s_preview_trace_graph axThick=0.5
ModifyGraph /w=$s_preview_trace_graph gridRGB=(52224,52224,52224)
ModifyGraph /w=$s_preview_trace_graph gridHair=0
ModifyGraph /w=$s_preview_trace_graph tick=0
ModifyGraph /w=$s_preview_trace_graph btLen=4
endif
graphname = s_preview_trace_graph graphname = s_preview_trace_graph
else else
return "" return ""
@ -747,6 +907,39 @@ static function /s show_preview_graph(data, [xdata])
return graphname return graphname
end end
static function /s display_preview_trace(xtrace, ytrace)
wave xtrace
wave ytrace
display /n=pearl_explorer_1d /k=1 ytrace vs xtrace as "Preview"
string graphname = s_name
ModifyGraph /w=$graphname rgb[0]=(0,0,0)
ModifyGraph /w=$graphname grid=2
ModifyGraph /w=$graphname mirror=1
ModifyGraph /w=$graphname minor=1
ModifyGraph /w=$graphname axThick=0.5
ModifyGraph /w=$graphname gridRGB=(52224,52224,52224)
ModifyGraph /w=$graphname gridHair=0
ModifyGraph /w=$graphname tick=0
ModifyGraph /w=$graphname btLen=4
// axis labels
string labels = note(ytrace)
string lab
lab = StringByKey("AxisLabelX", labels, "=", "\r")
if (!strlen(lab))
lab = "X"
endif
Label /w=$graphname bottom lab + " (\\U)"
lab = StringByKey("AxisLabelD", labels, "=", "\r")
if (!strlen(lab))
lab = "value"
endif
Label /w=$graphname left lab + " (\\U)"
return s_name
end
static function load_selected_files([options]) static function load_selected_files([options])
string options string options
@ -777,16 +970,32 @@ static function load_file(filename, [options])
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, "*.h5")) variable ft = pearl_file_type(filename)
if (ParamIsDefault(options)) switch(ft)
load_hdf_file(filename) case 1:
else if (ParamIsDefault(options))
load_hdf_file(filename, options=options) load_pshell_file(filename)
endif else
elseif (StringMatch(filename, "*.itx")) load_pshell_file(filename, options=options)
load_itx_file(filename) endif
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 setdatafolder saveDF
end end
@ -796,7 +1005,7 @@ static function prompt_hdf_options(options)
string mode = StringByKey("mode", options, ":", ";") string mode = StringByKey("mode", options, ":", ";")
string reduction_func = StringByKey("reduction_func", options, ":", ";") string reduction_func = StringByKey("reduction_func", options, ":", ";")
string modes = "adh5_load_reduced" string modes = "load_reduced"
string reduction_functions = adh5_list_reduction_funcs() string reduction_functions = adh5_list_reduction_funcs()
if (strlen(mode) == 0) if (strlen(mode) == 0)
@ -817,17 +1026,19 @@ static function prompt_hdf_options(options)
return v_flag // 0 = OK, 1 = cancel return v_flag // 0 = OK, 1 = cancel
end end
/// prototype for prompting for processing function parameters.
///
/// the function should prompt the user for function parameters,
/// and update the param argument if the user clicked OK.
/// returns 0 if the user clicked OK, 1 if the user cancelled.
///
/// prompt functions must have the same name as the corresponding reduction function
/// with the prefix "prompt_".
/// be aware of the limited length of function names in Igor.
///
/// this function is a prototype. it does nothing but returns OK.
///
function prompt_default_process(param) function prompt_default_process(param)
// prototype for prompting for processing function parameters.
// the function should prompt the user for function parameters,
// and update the param argument if the user clicked OK.
// returns 0 if the user clicked OK, 1 if the user cancelled.
// prompt functions must have the same name as the corresponding reduction function
// with the prefix "prompt_".
// be aware of the limited length of function names in Igor.
// this function is a prototype. it does nothing but returns OK.
string &param string &param
return 0 return 0
@ -847,6 +1058,57 @@ function prompt_func_params(func_name, func_param)
endif endif
end end
static function /df load_pshell_file(filename, [options])
string filename
string options
dfref saveDF = GetDataFolderDFR()
string nickname = ad_suggest_foldername(filename)
string loaded_filename = ""
if (ParamIsDefault(options))
loaded_filename = psh5_load_complete(nickname, "pearl_explorer_filepath", filename)
else
if (strlen(options) == 0)
svar pref_options = $(package_path + "s_hdf_options")
options = pref_options
if (prompt_hdf_options(options) == 0)
// OK
pref_options = options
else
// cancel
options = ""
endif
endif
string mode = StringByKey("mode", options, ":", ";")
strswitch(mode)
case "load_reduced":
string reduction_func = StringByKey("reduction_func", options, ":", ";")
svar pref_params = $(package_path + "s_reduction_params")
string reduction_params = pref_params
if (prompt_func_params(reduction_func, reduction_params) == 0)
pref_params = reduction_params
psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
svar s_filepath
loaded_filename = s_filepath
endif
break
endswitch
endif
dfref dataDF
if (strlen(loaded_filename) > 0)
setdatafolder $("root:" + nickname)
dataDF = GetDataFolderDFR()
string /g pearl_explorer_import = "load_pshell_file"
endif
setdatafolder saveDF
return dataDF
end
static function /df load_hdf_file(filename, [options]) static function /df load_hdf_file(filename, [options])
string filename string filename
string options string options
@ -873,7 +1135,7 @@ static function /df load_hdf_file(filename, [options])
string mode = StringByKey("mode", options, ":", ";") string mode = StringByKey("mode", options, ":", ";")
strswitch(mode) strswitch(mode)
case "adh5_load_reduced": case "load_reduced":
string reduction_func = StringByKey("reduction_func", options, ":", ";") string reduction_func = StringByKey("reduction_func", options, ":", ";")
svar pref_params = $(package_path + "s_reduction_params") svar pref_params = $(package_path + "s_reduction_params")
string reduction_params = pref_params string reduction_params = pref_params
@ -936,6 +1198,32 @@ static function /df load_itx_file(filename, [options])
return actDF return actDF
end 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]) function /s itx_suggest_foldername(filename, [ignoredate,sourcename,unique])
// suggests the name of a data folder based on a file name // suggests the name of a data folder based on a file name
// if the file name follows the naming convention source-date-index.extension, // if the file name follows the naming convention source-date-index.extension,
@ -1306,6 +1594,9 @@ static function bp_dataset_folder(ba) : ButtonControl
string cmd string cmd
sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset) sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset)
execute /q /z cmd execute /q /z cmd
cmd = "setdatafolder :scan1"
execute /q /z cmd
sprintf cmd, "setdatafolder %s", GetDataFolder(1)
print cmd print cmd
endif endif
break break

View File

@ -1,28 +0,0 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
function export_otf()
// export OTF folders to text files
string objname
variable index= 0
setdatafolder root:
dfref parentfolder = getdatafolderdfr()
string filename
do
objname = GetindexedObjNameDFR(parentfolder, 4, index)
if (strlen(objname) > 0)
if (cmpstr(StringFromList(0, objname, "_"), "otf") == 0)
setdatafolder parentfolder
setdatafolder $objname
wave ringcurrent,photonenergy,current_ch1,current_ch2
filename = objname + ".txt"
Save/G/M="\r\n"/W/P=pearl_explorer_filepath photonenergy,current_ch1,current_ch2,ringcurrent as filename
endif
index += 1
else
break
endif
while(1)
end

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
#pragma IgorVersion = 6.2 #pragma IgorVersion = 6.2
#pragma ModuleName = PearlFitFuncs #pragma ModuleName = PearlFitFuncs
#pragma version = 1.01 #pragma version = 1.01
#include "mm-physconst", version >= 1.05
// various fit functions for photoelectron spectroscopy // various fit functions for photoelectron spectroscopy
@ -453,7 +454,7 @@ function Au4f(w, x): fitfunc
vc1 = w[ip] / sqrt(pi) * vc2 vc1 = w[ip] / sqrt(pi) * vc2
vc3 = w[ip+1] vc3 = w[ip+1]
vc4 = vc2 * w[ip+2] / 2 vc4 = vc2 * w[ip+2] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
endfor endfor
return v return v
@ -490,25 +491,25 @@ function Au4f_2p2(w, x): fitfunc
vc1 = w[3] / sqrt(pi) * vc2 vc1 = w[3] / sqrt(pi) * vc2
vc3 = w[4] vc3 = w[4]
vc4 = vc2 * w[5] / 2 vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 5/2 surface // 5/2 surface
vc1 = w[3] / sqrt(pi) * vc2 * w[9] vc1 = w[3] / sqrt(pi) * vc2 * w[9]
vc3 = w[4] + w[10] vc3 = w[4] + w[10]
vc4 = vc2 * w[5] / 2 vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 bulk // 7/2 bulk
vc1 = w[6] / sqrt(pi) * vc2 vc1 = w[6] / sqrt(pi) * vc2
vc3 = w[7] vc3 = w[7]
vc4 = vc2 * w[8] / 2 vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 surface // 7/2 surface
vc1 = w[6] / sqrt(pi) * vc2 * w[9] vc1 = w[6] / sqrt(pi) * vc2 * w[9]
vc3 = w[7] + w[10] vc3 = w[7] + w[10]
vc4 = vc2 * w[8] / 2 vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
return v return v
@ -577,37 +578,37 @@ function Au4f_2p3(w, x): fitfunc
vc1 = w[3] / sqrt(pi) * vc2 vc1 = w[3] / sqrt(pi) * vc2
vc3 = w[4] vc3 = w[4]
vc4 = vc2 * w[5] / 2 vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 5/2 surface // 5/2 surface
vc1 = w[3] / sqrt(pi) * vc2 * w[9] vc1 = w[3] / sqrt(pi) * vc2 * w[9]
vc3 = w[4] + w[10] vc3 = w[4] + w[10]
vc4 = vc2 * w[5] / 2 vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 5/2 2nd layer // 5/2 2nd layer
vc1 = w[3] / sqrt(pi) * vc2 * w[11] vc1 = w[3] / sqrt(pi) * vc2 * w[11]
vc3 = w[4] + w[12] vc3 = w[4] + w[12]
vc4 = vc2 * w[5] / 2 vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 bulk // 7/2 bulk
vc1 = w[6] / sqrt(pi) * vc2 vc1 = w[6] / sqrt(pi) * vc2
vc3 = w[7] vc3 = w[7]
vc4 = vc2 * w[8] / 2 vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 surface // 7/2 surface
vc1 = w[6] / sqrt(pi) * vc2 * w[9] vc1 = w[6] / sqrt(pi) * vc2 * w[9]
vc3 = w[7] + w[10] vc3 = w[7] + w[10]
vc4 = vc2 * w[8] / 2 vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 2nd layer // 7/2 2nd layer
vc1 = w[6] / sqrt(pi) * vc2 * w[11] vc1 = w[6] / sqrt(pi) * vc2 * w[11]
vc3 = w[7] + w[12] vc3 = w[7] + w[12]
vc4 = vc2 * w[8] / 2 vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4) v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
return v return v
@ -682,7 +683,7 @@ function FermiGaussConv(pw, yw, xw) : FitFunc
variable xd = wavemin(xdw) / oversampling variable xd = wavemin(xdw) / oversampling
// calculate gausswave size based on pw[5] and precision variable // calculate gausswave size based on pw[5] and precision variable
variable x0g = pw[5] * precision_g variable x0g = abs(pw[5]) * precision_g
variable ng = 2 * floor(x0g / xd) + 1 variable ng = 2 * floor(x0g / xd) + 1
// calculate fermiwave size based on desired range for yw // calculate fermiwave size based on desired range for yw

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

@ -55,10 +55,8 @@ menu "PEARL"
end end
submenu "Services" submenu "Services"
PearlMenuEnableFunc("pearl_elog") + "ELOG Experiments", /Q, pearl_elog("Experiments") PearlMenuEnableFunc("pearl_elog") + "Open ELOG Panel", /Q, pearl_elog("")
help = {"Create entries in ELOG experiments logbook"} help = {"Open an ELOG panel to send entries to an ELOG logbook"}
PearlMenuEnableFunc("pearl_elog") + "ELOG Calculations", /Q, pearl_elog("Calculations")
help = {"Create entries in ELOG calculations logbook"}
end end
submenu "Sample Preparation" submenu "Sample Preparation"

View File

@ -1,73 +0,0 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlPreparation
#pragma version = 1.04
#include "pearl-area-display" // 2D and 3D data visualization
#include "pearl-area-profiles" // data processing for multi-dimensional datasets
#include "pearl-elog"
#if exists("pvOpen")
#include "pearl-epics" // EPICS access under Igor
#include "pearl-anneal" // automated sample annealing
#endif
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2015 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 PEARL sample preparation package
///
/// this procedure defines the PEARL sample preparation package
/// the main purpose of this file is to load the necessary dependent procedures
/// (see the include statements at the top)
///
/// @pre
/// * on-line process control functionality requires the EPICS XOP to be loaded
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2015 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 PearlPreparation
/// @brief PEARL sample preparation package
///
/// PearlPreparation is declared in @ref pearl-preparation.ipf.
///
/// @defgroup PreparationPackage Sample preparation package
/// @brief PEARL sample preparation package
///
/// The purpose of a package is to load a bunch of dependent procedure files.
/// The sample preparation package loads the following files.
///
/// * pearl-area-import.ipf
/// * pearl-area-display.ipf
/// * pearl-area-profiles.ipf
/// * pearl-elog.ipf
/// * pearl-anneal.ipf
///
/// The following files are loaded if the EPICS.XOP is present:
///
/// * pearl-epics.ipf
///
/// initializes package data once when the procedure is first loaded
static function AfterCompiledHook()
dfref savefolder = GetDataFolderDFR()
return 0
end
function UnloadPearlPreparationPackage()
execute /p/q/z "DELETEINCLUDE \"pearl-preparation\""
execute /p/q/z "COMPILEPROCEDURES "
end

File diff suppressed because it is too large Load Diff

View File

@ -703,3 +703,99 @@ function scienta_poly_bg(w, e, a): fitfunc
return bg * (base + pk1 + pk2 + pk3) return bg * (base + pk1 + pk2 + pk3)
end 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