mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-11-16 04:18:00 +09:00
initial commit
This commit is contained in:
commit
91ad25aca9
1012 files changed
+159314
No files matched your search
@@ -0,0 +1,48 @@
|
|||||||
|
%ASTRA_GPU_WRAPPER wrapper around the astra toolkit, it automatically
|
||||||
|
%recompiles the wrapper if some problems with the MEX file are detected
|
||||||
|
%
|
||||||
|
% varargout = ASTRA_GPU_wrapper(direction, input_array, cfg, vectors,output_array,varargin)
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% ** direction 'fp' or 'bp' - forward or backward projection operator
|
||||||
|
% ** input_array either projected volume or backprojected projection array
|
||||||
|
% ** cfg cfg structed created by ASTRA_initialize
|
||||||
|
% ** vectors projection geometry created by ASTRA_initialize
|
||||||
|
%
|
||||||
|
% optional:
|
||||||
|
% ** output_array either reconstructed volume or projected array
|
||||||
|
% ** deformation_fields 3x2 or 3x1 cell array if deformation vector fields for nonrigid deformation tomography
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% returns:
|
||||||
|
% ++ output resulting reconstruction, if output_array ~= [], result will
|
||||||
|
% be written to output_array directly to avoid memory allocation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function varargout = ASTRA_GPU_wrapper(direction, input_array, cfg, vectors,varargin)
|
||||||
|
varargout = cell(nargout,1);
|
||||||
|
assert(ismember(direction, {'fp', 'bp'}), 'Wrong option')
|
||||||
|
|
||||||
|
try
|
||||||
|
% call mex function
|
||||||
|
[varargout{:}] = ASTRA_GPU_wrapper(direction, input_array, cfg, vectors,varargin{:});
|
||||||
|
catch err
|
||||||
|
warning(err.identifier, 'ASTRA wrapper returned the following error: %s', err.message)
|
||||||
|
if any(strcmp(err.identifier, { 'MATLAB:UndefinedFunction','MATLAB:mex:ErrInvalidMEXFile'}))
|
||||||
|
path = replace(mfilename('fullpath'), mfilename, '');
|
||||||
|
utils.verbose(0, 'Trying to recompile the MEX function ... ')
|
||||||
|
|
||||||
|
mexcuda('-outdir',fullfile(path, 'private'), ...
|
||||||
|
fullfile(path, 'ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu'), ...
|
||||||
|
fullfile(path, 'ASTRA_GPU_wrapper/util3d.cu'), ...
|
||||||
|
fullfile(path, 'ASTRA_GPU_wrapper/par3d_fp.cu'), ...
|
||||||
|
fullfile(path, 'ASTRA_GPU_wrapper/par3d_bp.cu'));
|
||||||
|
|
||||||
|
[varargout{:}] = ASTRA_GPU_wrapper(direction, input_array, cfg, vectors,varargin{:});
|
||||||
|
else
|
||||||
|
utils.report_GPU_usage
|
||||||
|
rethrow(err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
| |
|
||||||
|
| Except where otherwise noted, this work is licensed under a |
|
||||||
|
| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
| |
|
||||||
|
| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
| |
|
||||||
|
| Author: CXS group, PSI |
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
You may use this code with the following provisions:
|
||||||
|
|
||||||
|
If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
computing language this notice should be included in the redistribution.
|
||||||
|
|
||||||
|
If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
publication or if it is fully or partially rewritten for another
|
||||||
|
computing language the authors and institution should be acknowledged
|
||||||
|
in written form in the publication: “Data processing was carried out
|
||||||
|
using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
Paul Scherrer Institut, Switzerland.”
|
||||||
|
Variations on the latter text can be incorporated upon discussion with
|
||||||
|
the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
for the published work.
|
||||||
|
|
||||||
|
A publication that focuses on describing features, or parameters, that
|
||||||
|
are already existing in the code should be first discussed with the
|
||||||
|
authors.
|
||||||
|
|
||||||
|
This code and subroutines are part of a continuous development, they
|
||||||
|
are provided “as they are” without guarantees or liability on part
|
||||||
|
of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Defines the exported functions for the DLL application.
|
||||||
|
//
|
||||||
|
// recompile commands
|
||||||
|
// (Linux, GCC 4.8.5) mexcuda -outdir private ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper/util3d.cu ASTRA_GPU_wrapper/par3d_fp.cu ASTRA_GPU_wrapper/par3d_bp.cu
|
||||||
|
// (Windows) mexcuda -outdir private ASTRA_GPU_wrapper\ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper\util3d.cu ASTRA_GPU_wrapper\par3d_fp.cu ASTRA_GPU_wrapper\par3d_bp.cu
|
||||||
|
|
||||||
|
/************* INPUTS *****************************/
|
||||||
|
/*
|
||||||
|
string 'fp' or 'bp' - forward / backward projection
|
||||||
|
single gpuArray volume or data object
|
||||||
|
struct cfg - contain configuration for astra, created by ASTRA_initialize.m
|
||||||
|
double array vec - contain projection geometry for astra, created by ASTRA_initialize.m
|
||||||
|
(optional)
|
||||||
|
single gpuArray - volume or data object to write the results to
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "cuda_runtime.h"
|
||||||
|
#include "device_launch_parameters.h"
|
||||||
|
#include <cuda.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "mex.h"
|
||||||
|
#include "gpu/mxGPUArray.h"
|
||||||
|
|
||||||
|
#include "util3d.h"
|
||||||
|
#include "dims3d.h"
|
||||||
|
#include "par3d_bp.h"
|
||||||
|
#include "par3d_fp.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mexFunction(int nlhs, mxArray *plhs[],
|
||||||
|
int nrhs, mxArray const *prhs[])
|
||||||
|
{
|
||||||
|
|
||||||
|
//mexPrintf("Warning: loading development version of ASTRA\n");
|
||||||
|
//mexPrintf("Ninputs:%i\n", nrhs);
|
||||||
|
|
||||||
|
if (!((nrhs == 4) || (nrhs == 5) || (nrhs == 8 ) || (nrhs == 11 ) ))
|
||||||
|
mexErrMsgTxt("4,5, 8, or 11 input arguments required");
|
||||||
|
|
||||||
|
|
||||||
|
using namespace astraCUDA3d;
|
||||||
|
char const * const errId = "parallel:gpu:mexGPUExample:InvalidInput";
|
||||||
|
char const * const errMsg = "Invalid input to MEX file.";
|
||||||
|
|
||||||
|
|
||||||
|
/* Throw an error if the input is not a GPU array. */
|
||||||
|
if (!mxIsGPUArray(prhs[1])) {
|
||||||
|
mexErrMsgIdAndTxt(errId, "The second input must be GPU array");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Load configuration */
|
||||||
|
SDimensions3D dims;
|
||||||
|
mxArray * tmp;
|
||||||
|
double * val;
|
||||||
|
#define SETVAR(name) do {tmp = mxGetField(prhs[2], 0, ""#name""); if (tmp!=NULL) { val = mxGetPr(tmp); dims.name = (unsigned int)val[0]; }} while (0);
|
||||||
|
SETVAR(iVolX);
|
||||||
|
SETVAR(iVolY);
|
||||||
|
SETVAR(iVolZ);
|
||||||
|
SETVAR(iProjAngles);
|
||||||
|
SETVAR(iProjU);
|
||||||
|
SETVAR(iProjV);
|
||||||
|
SETVAR(iRaysPerDetDim);
|
||||||
|
SETVAR(iRaysPerVoxelDim);
|
||||||
|
#undef SETVAR
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize the MathWorks GPU API. */
|
||||||
|
mxInitGPU();
|
||||||
|
|
||||||
|
|
||||||
|
/* load confuguration of angles */
|
||||||
|
double * my_angles = mxGetPr(prhs[3]);
|
||||||
|
int Nangles = (int)mxGetM(prhs[3]);
|
||||||
|
SPar3DProjection* angle = new SPar3DProjection[Nangles];
|
||||||
|
|
||||||
|
#define SETVAR(name,i,j) do { angle[i].name = my_angles[i+j*Nangles]; } while (0);
|
||||||
|
for (int i = 0; i < Nangles; i++)
|
||||||
|
{
|
||||||
|
SETVAR(fRayX, i, 0);
|
||||||
|
SETVAR(fRayY, i, 1);
|
||||||
|
SETVAR(fRayZ, i, 2);
|
||||||
|
SETVAR(fDetSX, i, 3);
|
||||||
|
SETVAR(fDetSY, i, 4);
|
||||||
|
SETVAR(fDetSZ, i, 5);
|
||||||
|
SETVAR(fDetUX, i, 6);
|
||||||
|
SETVAR(fDetUY, i, 7);
|
||||||
|
SETVAR(fDetUZ, i, 8);
|
||||||
|
SETVAR(fDetVX, i, 9);
|
||||||
|
SETVAR(fDetVY, i, 10);
|
||||||
|
SETVAR(fDetVZ, i, 11);
|
||||||
|
// mexPrintf("---------------------- \n");
|
||||||
|
}
|
||||||
|
#undef SETVAR
|
||||||
|
|
||||||
|
|
||||||
|
char * task = mxArrayToString(prhs[0]);
|
||||||
|
|
||||||
|
//mexPrintf("--------- Task %s \n ", task);
|
||||||
|
|
||||||
|
|
||||||
|
/* Load input data */
|
||||||
|
mxGPUArray const * m_data = mxGPUCreateFromMxArray(prhs[1]);
|
||||||
|
if ((mxGPUGetClassID(m_data) != mxSINGLE_CLASS)) {
|
||||||
|
mexErrMsgIdAndTxt(errId, errMsg);
|
||||||
|
}
|
||||||
|
float * p_data = (float *)mxGPUGetDataReadOnly(m_data);
|
||||||
|
|
||||||
|
DeformField DF;
|
||||||
|
if (nrhs == 8 || nrhs == 11 ) {
|
||||||
|
/* load deformation field */
|
||||||
|
DF.use_deform = true;
|
||||||
|
DF.use_linear_model = false; // assume contant deformation
|
||||||
|
DF.X0 = mxGPUCreateFromMxArray(prhs[5]);
|
||||||
|
DF.Y0 = mxGPUCreateFromMxArray(prhs[6]);
|
||||||
|
DF.Z0 = mxGPUCreateFromMxArray(prhs[7]);
|
||||||
|
if ((mxGPUGetClassID(DF.X0) != mxSINGLE_CLASS) |
|
||||||
|
(mxGPUGetClassID(DF.Y0) != mxSINGLE_CLASS) |
|
||||||
|
(mxGPUGetClassID(DF.Z0) != mxSINGLE_CLASS)) {
|
||||||
|
mexPrintf("wrong input type: deformation fields has to be single\n");
|
||||||
|
mexErrMsgIdAndTxt(errId, errMsg);
|
||||||
|
}
|
||||||
|
if (nrhs == 11 ) {
|
||||||
|
DF.use_linear_model = true; // assume linear deformation
|
||||||
|
DF.X1 = mxGPUCreateFromMxArray(prhs[8]);
|
||||||
|
DF.Y1 = mxGPUCreateFromMxArray(prhs[9]);
|
||||||
|
DF.Z1 = mxGPUCreateFromMxArray(prhs[10]);
|
||||||
|
if ((mxGPUGetClassID(DF.X1) != mxSINGLE_CLASS) |
|
||||||
|
(mxGPUGetClassID(DF.Y1) != mxSINGLE_CLASS) |
|
||||||
|
(mxGPUGetClassID(DF.Z1) != mxSINGLE_CLASS)) {
|
||||||
|
mexPrintf("wrong input type: deformation fields has to be single\n");
|
||||||
|
mexErrMsgIdAndTxt(errId, errMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DF.use_deform = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (strcmp(task, "fp")==0)
|
||||||
|
{
|
||||||
|
//mexPrintf(" forward projection \n ");
|
||||||
|
|
||||||
|
/* make volume array (no copying) */
|
||||||
|
cudaPitchedPtr volData;
|
||||||
|
volData.ptr = p_data;
|
||||||
|
volData.pitch = dims.iVolX * sizeof(float);
|
||||||
|
volData.xsize = dims.iVolX;
|
||||||
|
volData.ysize = dims.iVolY;
|
||||||
|
|
||||||
|
|
||||||
|
mxGPUArray * m_projData;
|
||||||
|
if(nrhs >= 5 && !mxIsEmpty(prhs[4]) )
|
||||||
|
{
|
||||||
|
/**** copy of the array is the slow operation and also GPU memory is limited *****/
|
||||||
|
// m_projData = mxGPUCopyFromMxArray(prhs[4]);
|
||||||
|
|
||||||
|
/* Use ugly trick to write directly to the provided GPU array ...
|
||||||
|
=> Now it is writting directly into the input field !!! DANGEROUS */
|
||||||
|
|
||||||
|
m_projData = const_cast<mxGPUArray*>(mxGPUCreateFromMxArray(prhs[4]));
|
||||||
|
if ((mxGPUGetClassID(m_projData) != mxSINGLE_CLASS)) {
|
||||||
|
mexPrintf("m_projData\n");
|
||||||
|
mexErrMsgIdAndTxt(errId, errMsg);
|
||||||
|
}
|
||||||
|
const mwSize * projSize = mxGPUGetDimensions(m_projData);
|
||||||
|
|
||||||
|
if (dims.iProjU != projSize[0] ||
|
||||||
|
dims.iProjV != projSize[1] ||
|
||||||
|
dims.iProjAngles != projSize[2])
|
||||||
|
mexErrMsgIdAndTxt(errId, "Wrong size of the inputs array");
|
||||||
|
|
||||||
|
//mexPrintf("Writting directly to the input array\n\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* allocate projection field */
|
||||||
|
int const Ndim = 3;
|
||||||
|
mwSize projSize[3];
|
||||||
|
projSize[0] = (mwSize)dims.iProjU;
|
||||||
|
projSize[1] = (mwSize)dims.iProjV;
|
||||||
|
projSize[2] = (mwSize)dims.iProjAngles;
|
||||||
|
m_projData = mxGPUCreateGPUArray(Ndim,
|
||||||
|
projSize,
|
||||||
|
mxSINGLE_CLASS,
|
||||||
|
mxREAL,
|
||||||
|
MX_GPU_INITIALIZE_VALUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make cudaPitchedPtr for projection field */
|
||||||
|
cudaPitchedPtr projData;
|
||||||
|
projData.ptr = (float *)mxGPUGetData(m_projData);
|
||||||
|
projData.pitch = dims.iProjU * sizeof(float);
|
||||||
|
projData.xsize = dims.iProjU;
|
||||||
|
projData.ysize = dims.iProjV;
|
||||||
|
|
||||||
|
//mexPrintf("astraCUDA3d::Par3DFP \n ") ;
|
||||||
|
astraCUDA3d::Par3DFP(volData, projData, dims, angle, 1.0f, DF);
|
||||||
|
checkLastError("After Projector");
|
||||||
|
|
||||||
|
|
||||||
|
/* Wrap the result up as a MATLAB gpuArray for return. */
|
||||||
|
if (nlhs > 0)
|
||||||
|
plhs[0] = mxGPUCreateMxArrayOnGPU(m_projData);
|
||||||
|
mxGPUDestroyGPUArray(m_projData);
|
||||||
|
mxGPUDestroyGPUArray(m_data);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(task, "bp")==0)
|
||||||
|
{
|
||||||
|
//mexPrintf(" backward projection \n ");
|
||||||
|
|
||||||
|
|
||||||
|
/* make projection field (no copying) */
|
||||||
|
cudaPitchedPtr projData;
|
||||||
|
projData.ptr = p_data;
|
||||||
|
projData.pitch = dims.iProjU * sizeof(float);
|
||||||
|
projData.xsize = dims.iProjU;
|
||||||
|
projData.ysize = dims.iProjAngles;
|
||||||
|
mxGPUArray* m_volData;
|
||||||
|
if(nrhs >= 5 && !mxIsEmpty(prhs[4]) )
|
||||||
|
{
|
||||||
|
/**** copy of the array is the slow operation and also GPU memory is limited *****/
|
||||||
|
// m_volData = mxGPUCopyFromMxArray(prhs[4]);
|
||||||
|
|
||||||
|
/* Use ugly trick to write directly to the provided GPU array ...
|
||||||
|
=> Now it is writting directly into the input field !!! DANGEROUS */
|
||||||
|
|
||||||
|
m_volData = const_cast<mxGPUArray*>(mxGPUCreateFromMxArray(prhs[4]));
|
||||||
|
if ((mxGPUGetClassID(m_volData) != mxSINGLE_CLASS)) {
|
||||||
|
mexPrintf("m_volData\n");
|
||||||
|
mexErrMsgIdAndTxt(errId, errMsg);
|
||||||
|
}
|
||||||
|
mwSize volSize[3];
|
||||||
|
const mwSize * volSize0 = mxGPUGetDimensions(m_volData);
|
||||||
|
if (mxGPUGetNumberOfDimensions(m_volData)==3) {
|
||||||
|
volSize[0]=volSize0[0];
|
||||||
|
volSize[1]=volSize0[1];
|
||||||
|
volSize[2]=volSize0[2];
|
||||||
|
} else {
|
||||||
|
volSize[0]=volSize0[0];
|
||||||
|
volSize[1]=volSize0[1];
|
||||||
|
volSize[2]=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (dims.iVolX != volSize[0] ||
|
||||||
|
dims.iVolY != volSize[1] ||
|
||||||
|
dims.iVolZ != volSize[2])
|
||||||
|
mexErrMsgIdAndTxt(errId, "Wrong size of the inputs array");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* allocate volume data */
|
||||||
|
int const Ndim = 3;
|
||||||
|
mwSize volSize[3];
|
||||||
|
volSize[0] = (mwSize)dims.iVolX;
|
||||||
|
volSize[1] = (mwSize)dims.iVolY;
|
||||||
|
volSize[2] = (mwSize)dims.iVolZ;
|
||||||
|
m_volData = mxGPUCreateGPUArray(Ndim,
|
||||||
|
volSize,
|
||||||
|
mxSINGLE_CLASS,
|
||||||
|
mxREAL,
|
||||||
|
MX_GPU_INITIALIZE_VALUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make volume array pointer*/
|
||||||
|
cudaPitchedPtr volData;
|
||||||
|
volData.ptr = (float *)mxGPUGetData(m_volData);
|
||||||
|
volData.pitch = dims.iVolX * sizeof(float);
|
||||||
|
volData.xsize = dims.iVolX;
|
||||||
|
volData.ysize = dims.iVolY;
|
||||||
|
|
||||||
|
astraCUDA3d::Par3DBP(volData, projData, dims, angle, 1.0f, DF);
|
||||||
|
checkLastError("After Projector");
|
||||||
|
|
||||||
|
|
||||||
|
/* Wrap the result up as a MATLAB gpuArray for return. */
|
||||||
|
if (nlhs > 0)
|
||||||
|
plhs[0] = mxGPUCreateMxArrayOnGPU(m_volData);
|
||||||
|
mxGPUDestroyGPUArray(m_volData);
|
||||||
|
mxGPUDestroyGPUArray(m_data);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mexPrintf("No such option");
|
||||||
|
|
||||||
|
if (DF.use_deform) {
|
||||||
|
//mexPrintf("Deleted DF");
|
||||||
|
mxGPUDestroyGPUArray(DF.X0);
|
||||||
|
mxGPUDestroyGPUArray(DF.Y0);
|
||||||
|
mxGPUDestroyGPUArray(DF.Z0);
|
||||||
|
if (DF.use_linear_model) {
|
||||||
|
mxGPUDestroyGPUArray(DF.X1);
|
||||||
|
mxGPUDestroyGPUArray(DF.Y1);
|
||||||
|
mxGPUDestroyGPUArray(DF.Z1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INC_ASTRA_GEOMETRYUTIL3D
|
||||||
|
#define _INC_ASTRA_GEOMETRYUTIL3D
|
||||||
|
|
||||||
|
namespace astra {
|
||||||
|
|
||||||
|
struct SConeProjection {
|
||||||
|
// the source
|
||||||
|
double fSrcX, fSrcY, fSrcZ;
|
||||||
|
|
||||||
|
// the origin ("bottom left") of the (flat-panel) detector
|
||||||
|
double fDetSX, fDetSY, fDetSZ;
|
||||||
|
|
||||||
|
// the U-edge of a detector pixel
|
||||||
|
double fDetUX, fDetUY, fDetUZ;
|
||||||
|
|
||||||
|
// the V-edge of a detector pixel
|
||||||
|
double fDetVX, fDetVY, fDetVZ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void translate(double dx, double dy, double dz) {
|
||||||
|
fSrcX += dx;
|
||||||
|
fSrcY += dy;
|
||||||
|
fSrcZ += dz;
|
||||||
|
fDetSX += dx;
|
||||||
|
fDetSY += dy;
|
||||||
|
fDetSZ += dz;
|
||||||
|
|
||||||
|
}
|
||||||
|
void scale(double factor) {
|
||||||
|
fSrcX *= factor;
|
||||||
|
fSrcY *= factor;
|
||||||
|
fSrcZ *= factor;
|
||||||
|
fDetSX *= factor;
|
||||||
|
fDetSY *= factor;
|
||||||
|
fDetSZ *= factor;
|
||||||
|
fDetUX *= factor;
|
||||||
|
fDetUY *= factor;
|
||||||
|
fDetUZ *= factor;
|
||||||
|
fDetVX *= factor;
|
||||||
|
fDetVY *= factor;
|
||||||
|
fDetVZ *= factor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SPar3DProjection {
|
||||||
|
// the ray direction
|
||||||
|
double fRayX, fRayY, fRayZ;
|
||||||
|
|
||||||
|
// the origin ("bottom left") of the (flat-panel) detector
|
||||||
|
double fDetSX, fDetSY, fDetSZ;
|
||||||
|
|
||||||
|
// the U-edge of a detector pixel
|
||||||
|
double fDetUX, fDetUY, fDetUZ;
|
||||||
|
|
||||||
|
// the V-edge of a detector pixel
|
||||||
|
double fDetVX, fDetVY, fDetVZ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void translate(double dx, double dy, double dz) {
|
||||||
|
fDetSX += dx;
|
||||||
|
fDetSY += dy;
|
||||||
|
fDetSZ += dz;
|
||||||
|
}
|
||||||
|
void scale(double factor) {
|
||||||
|
fRayX *= factor;
|
||||||
|
fRayY *= factor;
|
||||||
|
fRayZ *= factor;
|
||||||
|
fDetSX *= factor;
|
||||||
|
fDetSY *= factor;
|
||||||
|
fDetSZ *= factor;
|
||||||
|
fDetUX *= factor;
|
||||||
|
fDetUY *= factor;
|
||||||
|
fDetUZ *= factor;
|
||||||
|
fDetVX *= factor;
|
||||||
|
fDetVY *= factor;
|
||||||
|
fDetVZ *= factor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void computeBP_UV_Coeffs(const SPar3DProjection& proj,
|
||||||
|
double &fUX, double &fUY, double &fUZ, double &fUC,
|
||||||
|
double &fVX, double &fVY, double &fVZ, double &fVC);
|
||||||
|
|
||||||
|
void computeBP_UV_Coeffs(const SConeProjection& proj,
|
||||||
|
double &fUX, double &fUY, double &fUZ, double &fUC,
|
||||||
|
double &fVX, double &fVY, double &fVZ, double &fVC,
|
||||||
|
double &fDX, double &fDY, double &fDZ, double &fDC);
|
||||||
|
|
||||||
|
|
||||||
|
SConeProjection* genConeProjections(unsigned int iProjAngles,
|
||||||
|
unsigned int iProjU,
|
||||||
|
unsigned int iProjV,
|
||||||
|
double fOriginSourceDistance,
|
||||||
|
double fOriginDetectorDistance,
|
||||||
|
double fDetUSize,
|
||||||
|
double fDetVSize,
|
||||||
|
const float *pfAngles);
|
||||||
|
|
||||||
|
SPar3DProjection* genPar3DProjections(unsigned int iProjAngles,
|
||||||
|
unsigned int iProjU,
|
||||||
|
unsigned int iProjV,
|
||||||
|
double fDetUSize,
|
||||||
|
double fDetVSize,
|
||||||
|
const float *pfAngles);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INC_ASTRA_GLOBALS
|
||||||
|
#define _INC_ASTRA_GLOBALS
|
||||||
|
|
||||||
|
/*! \mainpage The ASTRA-toolbox
|
||||||
|
*
|
||||||
|
* <img src="../images/logo_big.png"/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
// disable warning: 'fopen' was declared deprecated
|
||||||
|
#pragma warning (disable : 4996)
|
||||||
|
// disable warning: C++ exception handler used, but unwind semantics are not enables
|
||||||
|
#pragma warning (disable : 4530)
|
||||||
|
// disable warning: no suitable definition provided for explicit template instantiation request
|
||||||
|
#pragma warning (disable : 4661)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// standard includes
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <math.h>
|
||||||
|
//#include <boost/static_assert.hpp>
|
||||||
|
//#include <boost/throw_exception.hpp>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// macro's
|
||||||
|
|
||||||
|
#define ASTRA_TOOLBOXVERSION_MAJOR 1
|
||||||
|
#define ASTRA_TOOLBOXVERSION_MINOR 7
|
||||||
|
#define ASTRA_TOOLBOXVERSION ((ASTRA_TOOLBOXVERSION_MAJOR)*100 + (ASTRA_TOOLBOXVERSION_MINOR))
|
||||||
|
#define ASTRA_TOOLBOXVERSION_STRING "1.7.1"
|
||||||
|
|
||||||
|
|
||||||
|
#define ASTRA_ASSERT(a) assert(a)
|
||||||
|
|
||||||
|
#define ASTRA_CONFIG_CHECK(value, type, msg) if (!(value)) { cout << "Configuration Error in " << type << ": " << msg << endl; return false; }
|
||||||
|
|
||||||
|
#define ASTRA_CONFIG_WARNING(type, msg) { cout << "Warning in " << type << ": " << msg << endl; }
|
||||||
|
|
||||||
|
|
||||||
|
#define ASTRA_DELETE(a) if (a) { delete a; a = NULL; }
|
||||||
|
#define ASTRA_DELETE_ARRAY(a) if (a) { delete[] a; a = NULL; }
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#ifdef DLL_EXPORTS
|
||||||
|
#define _AstraExport __declspec(dllexport)
|
||||||
|
#define EXPIMP_TEMPLATE
|
||||||
|
#else
|
||||||
|
#define _AstraExport __declspec(dllimport)
|
||||||
|
#define EXPIMP_TEMPLATE extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define _AstraExport
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// typedefs
|
||||||
|
namespace astra {
|
||||||
|
typedef float float32;
|
||||||
|
typedef double float64;
|
||||||
|
typedef unsigned short int uint16;
|
||||||
|
typedef signed short int sint16;
|
||||||
|
typedef unsigned char uchar8;
|
||||||
|
typedef signed char schar8;
|
||||||
|
|
||||||
|
typedef int int32;
|
||||||
|
typedef short int int16;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// globals vars & functions
|
||||||
|
//namespace astra {
|
||||||
|
//#define ToolboxVersion 0.1f;
|
||||||
|
|
||||||
|
//float32 getVersion() { return ToolboxVersion; }
|
||||||
|
|
||||||
|
//_AstraExport bool cudaEnabled() {
|
||||||
|
//#ifdef ASTRA_CUDA
|
||||||
|
// return true;
|
||||||
|
//#else
|
||||||
|
// return false;
|
||||||
|
//#endif
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// errors
|
||||||
|
namespace astra {
|
||||||
|
|
||||||
|
typedef enum {ASTRA_SUCCESS,
|
||||||
|
ASTRA_ERROR_NOT_INITIALIZED,
|
||||||
|
ASTRA_ERROR_INVALID_FILE,
|
||||||
|
ASTRA_ERROR_OUT_OF_RANGE,
|
||||||
|
ASTRA_ERROR_DIMENSION_MISMATCH,
|
||||||
|
ASTRA_ERROR_EXTERNAL_LIBRARY,
|
||||||
|
ASTRA_ERROR_ALLOCATION,
|
||||||
|
ASTRA_ERROR_NOT_IMPLEMENTED} AstraError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// variables
|
||||||
|
namespace astra {
|
||||||
|
const float32 PI = 3.14159265358979323846264338328f;
|
||||||
|
const float32 PI32 = 3.14159265358979323846264338328f;
|
||||||
|
const float32 PIdiv2 = PI / 2;
|
||||||
|
const float32 PIdiv4 = PI / 4;
|
||||||
|
const float32 eps = 1e-7f;
|
||||||
|
|
||||||
|
extern _AstraExport bool running_in_matlab;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// math
|
||||||
|
namespace astra {
|
||||||
|
|
||||||
|
inline float32 cos_73s(float32 x)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
const float32 c1 = 0.999999953464f;
|
||||||
|
const float32 c2 = -0.4999999053455f;
|
||||||
|
const float32 c3 = 0.0416635846769f;
|
||||||
|
const float32 c4 = -0.0013853704264f;
|
||||||
|
const float32 c5 = 0.000023233f;
|
||||||
|
*/
|
||||||
|
const float c1= (float)0.99940307;
|
||||||
|
const float c2= (float)-0.49558072;
|
||||||
|
const float c3= (float)0.03679168;
|
||||||
|
|
||||||
|
float32 x2;
|
||||||
|
x2 = x * x;
|
||||||
|
//return (c1 + x2*(c2 + x2*(c3 + x2*(c4 + c5*x2))));
|
||||||
|
return (c1 + x2*(c2 + c3 * x2));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float32 fast_cos(float32 x)
|
||||||
|
{
|
||||||
|
int quad;
|
||||||
|
|
||||||
|
//x = fmod(x, 2*PI); // Get rid of values > 2* pi
|
||||||
|
if (x < 0) x = -x; // cos(-x) = cos(x)
|
||||||
|
quad = int(x/PIdiv2); // Get quadrant # (0 to 3)
|
||||||
|
switch (quad) {
|
||||||
|
case 0: return cos_73s(x);
|
||||||
|
case 1: return -cos_73s(PI-x);
|
||||||
|
case 2: return -cos_73s(x-PI);
|
||||||
|
case 3: return cos_73s(2*PI-x);
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float32 fast_sin(float32 x){
|
||||||
|
return fast_cos(PIdiv2-x);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// structs
|
||||||
|
namespace astra {
|
||||||
|
/**
|
||||||
|
* Struct for storing pixel weigths
|
||||||
|
**/
|
||||||
|
struct SPixelWeight
|
||||||
|
{
|
||||||
|
int m_iIndex;
|
||||||
|
float32 m_fWeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct combining some properties of a detector in 1D detector row
|
||||||
|
**/
|
||||||
|
struct SDetector2D
|
||||||
|
{
|
||||||
|
int m_iIndex;
|
||||||
|
int m_iAngleIndex;
|
||||||
|
int m_iDetectorIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct combining some properties of a detector in 2D detector array
|
||||||
|
**/
|
||||||
|
struct SDetector3D
|
||||||
|
{
|
||||||
|
int m_iIndex;
|
||||||
|
int m_iAngleIndex;
|
||||||
|
int m_iDetectorIndex;
|
||||||
|
int m_iSliceIndex;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// some toys
|
||||||
|
|
||||||
|
// safe reinterpret cast
|
||||||
|
// template <class To, class From>
|
||||||
|
// To safe_reinterpret_cast(From from)
|
||||||
|
// {
|
||||||
|
// BOOST_STATIC_ASSERT(sizeof(From) <= sizeof(To));
|
||||||
|
// return reinterpret_cast<To>(from);
|
||||||
|
// }
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// functions for testing
|
||||||
|
template<typename T>
|
||||||
|
inline void writeArray(T*** arr, int dim1, int dim2, int dim3, const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ofstream out(filename.c_str());
|
||||||
|
int i1, i2, i3;
|
||||||
|
for (i1 = 0; i1 < dim1; ++i1) {
|
||||||
|
for (i2 = 0; i2 < dim2; ++i2) {
|
||||||
|
for (i3 = 0; i3 < dim3; ++i3) {
|
||||||
|
out << arr[i1][i2][i3] << " ";
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void writeArray(T** arr, int dim1, int dim2, const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ofstream out(filename.c_str());
|
||||||
|
for (int i1 = 0; i1 < dim1; i1++) {
|
||||||
|
for (int i2 = 0; i2 < dim2; i2++) {
|
||||||
|
out << arr[i1][i2] << " ";
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void writeArray(T* arr, int dim1, const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ofstream out(filename.c_str());
|
||||||
|
for (int i1 = 0; i1 < dim1; i1++) {
|
||||||
|
out << arr[i1] << " ";
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
namespace astra {
|
||||||
|
_AstraExport inline int getVersion() { return ASTRA_TOOLBOXVERSION; }
|
||||||
|
_AstraExport inline const char* getVersionString() { return ASTRA_TOOLBOXVERSION_STRING; }
|
||||||
|
#ifdef ASTRA_CUDA
|
||||||
|
_AstraExport inline bool cudaEnabled() { return true; }
|
||||||
|
#else
|
||||||
|
_AstraExport inline bool cudaEnabled() { return false; }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// portability between MSVC and Linux/gcc
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
// #include "swrap.h"
|
||||||
|
#define EXPIMP_TEMPLATE
|
||||||
|
|
||||||
|
#if !defined(FORCEINLINE) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||||
|
#define FORCEINLINE inline __attribute__((__always_inline__))
|
||||||
|
#else
|
||||||
|
#define FORCEINLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define FORCEINLINE __forceinline
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// use pthreads on Linux and OSX
|
||||||
|
#if defined(__linux__) || defined(__MACH__)
|
||||||
|
#define USE_PTHREADS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CLOG_MAIN
|
||||||
|
#include "clog.h"
|
||||||
|
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
using namespace astra;
|
||||||
|
|
||||||
|
void CLogger::enableScreen()
|
||||||
|
{
|
||||||
|
m_bEnabledScreen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::enableFile()
|
||||||
|
{
|
||||||
|
m_bEnabledFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::enable()
|
||||||
|
{
|
||||||
|
enableScreen();
|
||||||
|
enableFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::disableScreen()
|
||||||
|
{
|
||||||
|
m_bEnabledScreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::disableFile()
|
||||||
|
{
|
||||||
|
m_bEnabledFile = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::disable()
|
||||||
|
{
|
||||||
|
disableScreen();
|
||||||
|
disableFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::debug(const char *sfile, int sline, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
_assureIsInitialized();
|
||||||
|
va_list ap, apf;
|
||||||
|
if(m_bEnabledScreen){
|
||||||
|
va_start(ap, fmt);
|
||||||
|
clog_debug(sfile,sline,0,fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
if(m_bEnabledFile && m_bFileProvided){
|
||||||
|
va_start(apf, fmt);
|
||||||
|
clog_debug(sfile,sline,1,fmt,apf);
|
||||||
|
va_end(apf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::info(const char *sfile, int sline, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
_assureIsInitialized();
|
||||||
|
va_list ap, apf;
|
||||||
|
if(m_bEnabledScreen){
|
||||||
|
va_start(ap, fmt);
|
||||||
|
clog_info(sfile,sline,0,fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
if(m_bEnabledFile && m_bFileProvided){
|
||||||
|
va_start(apf, fmt);
|
||||||
|
clog_info(sfile,sline,1,fmt,apf);
|
||||||
|
va_end(apf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::warn(const char *sfile, int sline, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
_assureIsInitialized();
|
||||||
|
va_list ap, apf;
|
||||||
|
if(m_bEnabledScreen){
|
||||||
|
va_start(ap, fmt);
|
||||||
|
clog_warn(sfile,sline,0,fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
if(m_bEnabledFile && m_bFileProvided){
|
||||||
|
va_start(apf, fmt);
|
||||||
|
clog_warn(sfile,sline,1,fmt,apf);
|
||||||
|
va_end(apf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::error(const char *sfile, int sline, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
_assureIsInitialized();
|
||||||
|
va_list ap, apf;
|
||||||
|
if(m_bEnabledScreen){
|
||||||
|
va_start(ap, fmt);
|
||||||
|
clog_error(sfile,sline,0,fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
if(m_bEnabledFile && m_bFileProvided){
|
||||||
|
va_start(apf, fmt);
|
||||||
|
clog_error(sfile,sline,1,fmt,apf);
|
||||||
|
va_end(apf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::_setLevel(int id, log_level m_eLevel)
|
||||||
|
{
|
||||||
|
switch(m_eLevel){
|
||||||
|
case LOG_DEBUG:
|
||||||
|
clog_set_level(id,CLOG_DEBUG);
|
||||||
|
break;
|
||||||
|
case LOG_INFO:
|
||||||
|
clog_set_level(id,CLOG_INFO);
|
||||||
|
break;
|
||||||
|
case LOG_WARN:
|
||||||
|
clog_set_level(id,CLOG_WARN);
|
||||||
|
break;
|
||||||
|
case LOG_ERROR:
|
||||||
|
clog_set_level(id,CLOG_ERROR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::setOutputScreen(int fd, log_level m_eLevel)
|
||||||
|
{
|
||||||
|
_assureIsInitialized();
|
||||||
|
if(fd==1||fd==2){
|
||||||
|
clog_set_fd(0, fd);
|
||||||
|
}else{
|
||||||
|
error(__FILE__,__LINE__,"Invalid file descriptor");
|
||||||
|
}
|
||||||
|
_setLevel(0,m_eLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::setOutputFile(const char *filename, log_level m_eLevel)
|
||||||
|
{
|
||||||
|
if(m_bFileProvided){
|
||||||
|
clog_free(1);
|
||||||
|
m_bFileProvided=false;
|
||||||
|
}
|
||||||
|
if(!clog_init_path(1,filename)){
|
||||||
|
m_bFileProvided=true;
|
||||||
|
_setLevel(1,m_eLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::_assureIsInitialized()
|
||||||
|
{
|
||||||
|
if(!m_bInitialized)
|
||||||
|
{
|
||||||
|
clog_init_fd(0, 2);
|
||||||
|
clog_set_level(0, CLOG_INFO);
|
||||||
|
clog_set_fmt(0, "%l: %m\n");
|
||||||
|
m_bInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLogger::setFormatFile(const char *fmt)
|
||||||
|
{
|
||||||
|
if(m_bFileProvided){
|
||||||
|
clog_set_fmt(1,fmt);
|
||||||
|
}else{
|
||||||
|
error(__FILE__,__LINE__,"No log file specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CLogger::setFormatScreen(const char *fmt)
|
||||||
|
{
|
||||||
|
clog_set_fmt(0,fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLogger::CLogger()
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CLogger::setCallbackScreen(void (*cb)(const char *msg, size_t len)){
|
||||||
|
_assureIsInitialized();
|
||||||
|
return clog_set_cb(0,cb)==0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CLogger::m_bEnabledScreen = true;
|
||||||
|
bool CLogger::m_bEnabledFile = true;
|
||||||
|
bool CLogger::m_bFileProvided = false;
|
||||||
|
bool CLogger::m_bInitialized = false;
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INC_ASTRA_LOGGING
|
||||||
|
#define _INC_ASTRA_LOGGING
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
//#define ASTRA_DEBUG(...) astra::CLogger::debug(__FILE__,__LINE__, __VA_ARGS__)
|
||||||
|
//#define ASTRA_INFO(...) astra::CLogger::info(__FILE__,__LINE__, __VA_ARGS__)
|
||||||
|
//#define ASTRA_WARN(...) astra::CLogger::warn(__FILE__,__LINE__, __VA_ARGS__)
|
||||||
|
//#define ASTRA_ERROR(...) astra::CLogger::error(__FILE__,__LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
// FIXME !!!!!!
|
||||||
|
#define ASTRA_DEBUG(...)
|
||||||
|
#define ASTRA_INFO(...)
|
||||||
|
#define ASTRA_WARN(...)
|
||||||
|
#define ASTRA_ERROR(...)
|
||||||
|
|
||||||
|
namespace astra
|
||||||
|
{
|
||||||
|
|
||||||
|
enum log_level {
|
||||||
|
LOG_DEBUG,
|
||||||
|
LOG_INFO,
|
||||||
|
LOG_WARN,
|
||||||
|
LOG_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
class _AstraExport CLogger
|
||||||
|
{
|
||||||
|
CLogger();
|
||||||
|
~CLogger();
|
||||||
|
static bool m_bEnabledFile;
|
||||||
|
static bool m_bEnabledScreen;
|
||||||
|
static bool m_bFileProvided;
|
||||||
|
static bool m_bInitialized;
|
||||||
|
static void _assureIsInitialized();
|
||||||
|
static void _setLevel(int id, log_level m_eLevel);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a line to the log file (newline is added). Ignored if logging is turned off.
|
||||||
|
*
|
||||||
|
* @param sfile
|
||||||
|
* The name of the source file making this log call (e.g. __FILE__).
|
||||||
|
*
|
||||||
|
* @param sline
|
||||||
|
* The line number of the call in the source code (e.g. __LINE__).
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* The id of the logger to write to.
|
||||||
|
*
|
||||||
|
* @param fmt
|
||||||
|
* The format string for the message (printf formatting).
|
||||||
|
*
|
||||||
|
* @param ...
|
||||||
|
* Any additional format arguments.
|
||||||
|
*/
|
||||||
|
static void debug(const char *sfile, int sline, const char *fmt, ...);
|
||||||
|
static void info(const char *sfile, int sline, const char *fmt, ...);
|
||||||
|
static void warn(const char *sfile, int sline, const char *fmt, ...);
|
||||||
|
static void error(const char *sfile, int sline, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the file to log to, with logging level.
|
||||||
|
*
|
||||||
|
* @param filename
|
||||||
|
* File to log to.
|
||||||
|
*
|
||||||
|
* @param m_eLevel
|
||||||
|
* Logging level (LOG_DEBUG, LOG_WARN, LOG_INFO, LOG_ERROR).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void setOutputFile(const char *filename, log_level m_eLevel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the screen to log to, with logging level.
|
||||||
|
*
|
||||||
|
* @param screen_fd
|
||||||
|
* Screen file descriptor (1 for stdout, 2 for stderr)
|
||||||
|
*
|
||||||
|
* @param m_eLevel
|
||||||
|
* Logging level (LOG_DEBUG, LOG_WARN, LOG_INFO, LOG_ERROR).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void setOutputScreen(int fd, log_level m_eLevel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the format string for log messages. Here are the substitutions you may
|
||||||
|
* use:
|
||||||
|
*
|
||||||
|
* %f: Source file name generating the log call.
|
||||||
|
* %n: Source line number where the log call was made.
|
||||||
|
* %m: The message text sent to the logger (after printf formatting).
|
||||||
|
* %d: The current date, formatted using the logger's date format.
|
||||||
|
* %t: The current time, formatted using the logger's time format.
|
||||||
|
* %l: The log level (one of "DEBUG", "INFO", "WARN", or "ERROR").
|
||||||
|
* %%: A literal percent sign.
|
||||||
|
*
|
||||||
|
* The default format string is "%d %t %f(%n): %l: %m\n".
|
||||||
|
*
|
||||||
|
* @param fmt
|
||||||
|
* The new format string, which must be less than 256 bytes.
|
||||||
|
* You probably will want to end this with a newline (\n).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void setFormatFile(const char *fmt);
|
||||||
|
static void setFormatScreen(const char *fmt);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable logging.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void enable();
|
||||||
|
static void enableScreen();
|
||||||
|
static void enableFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable logging.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void disable();
|
||||||
|
static void disableScreen();
|
||||||
|
static void disableFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set callback function for logging to screen.
|
||||||
|
* @return whether callback was set succesfully.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static bool setCallbackScreen(void (*cb)(const char *msg, size_t len));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _INC_ASTRA_LOGGING */
|
||||||
@@ -0,0 +1,693 @@
|
|||||||
|
/* clog: Extremely simple logger for C.
|
||||||
|
*
|
||||||
|
* Features:
|
||||||
|
* - Implemented purely as a single header file.
|
||||||
|
* - Create multiple loggers.
|
||||||
|
* - Four log levels (debug, info, warn, error).
|
||||||
|
* - Custom formats.
|
||||||
|
* - Fast.
|
||||||
|
*
|
||||||
|
* Dependencies:
|
||||||
|
* - Should conform to C89, C++98 (but requires vsnprintf, unfortunately).
|
||||||
|
* - POSIX environment.
|
||||||
|
*
|
||||||
|
* USAGE:
|
||||||
|
*
|
||||||
|
* Include this header in any file that wishes to write to logger(s). In
|
||||||
|
* exactly one file (per executable), define CLOG_MAIN first (e.g. in your
|
||||||
|
* main .c file).
|
||||||
|
*
|
||||||
|
* #define CLOG_MAIN
|
||||||
|
* #include "clog.h"
|
||||||
|
*
|
||||||
|
* This will define the actual objects that all the other units will use.
|
||||||
|
*
|
||||||
|
* Loggers are identified by integers (0 - 15). It's expected that you'll
|
||||||
|
* create meaningful constants and then refer to the loggers as such.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* const int MY_LOGGER = 0;
|
||||||
|
*
|
||||||
|
* int main() {
|
||||||
|
* int r;
|
||||||
|
* r = clog_init_path(MY_LOGGER, "my_log.txt");
|
||||||
|
* if (r != 0) {
|
||||||
|
* fprintf(stderr, "Logger initialization failed.\n");
|
||||||
|
* return 1;
|
||||||
|
* }
|
||||||
|
* clog_info(CLOG(MY_LOGGER), "Hello, world!");
|
||||||
|
* clog_free(MY_LOGGER);
|
||||||
|
* return 0;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* The CLOG macro used in the call to clog_info is a helper that passes the
|
||||||
|
* __FILE__ and __LINE__ parameters for you, so you don't have to type them
|
||||||
|
* every time. (It could be prettier with variadic macros, but that requires
|
||||||
|
* C99 or C++11 to be standards compliant.)
|
||||||
|
*
|
||||||
|
* Errors encountered by clog will be printed to stderr. You can suppress
|
||||||
|
* these by defining a macro called CLOG_SILENT before including clog.h.
|
||||||
|
*
|
||||||
|
* License: Do whatever you want. It would be nice if you contribute
|
||||||
|
* improvements as pull requests here:
|
||||||
|
*
|
||||||
|
* https://github.com/mmueller/clog
|
||||||
|
*
|
||||||
|
* Copyright 2013 Mike Mueller <mike@subfocal.net>.
|
||||||
|
*
|
||||||
|
* As is; no warranty is provided; use at your own risk.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CLOG_H__
|
||||||
|
#define __CLOG_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <io.h>
|
||||||
|
#define open _open
|
||||||
|
#define close _close
|
||||||
|
#define write _write
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Number of loggers that can be defined. */
|
||||||
|
#define CLOG_MAX_LOGGERS 16
|
||||||
|
|
||||||
|
/* Format strings cannot be longer than this. */
|
||||||
|
#define CLOG_FORMAT_LENGTH 256
|
||||||
|
|
||||||
|
/* Formatted times and dates should be less than this length. If they are not,
|
||||||
|
* they will not appear in the log. */
|
||||||
|
#define CLOG_DATETIME_LENGTH 256
|
||||||
|
|
||||||
|
/* Default format strings. */
|
||||||
|
#define CLOG_DEFAULT_FORMAT "%d %t %f(%n): %l: %m\n"
|
||||||
|
#define CLOG_DEFAULT_DATE_FORMAT "%Y-%m-%d"
|
||||||
|
#define CLOG_DEFAULT_TIME_FORMAT "%H:%M:%S"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum clog_level {
|
||||||
|
CLOG_DEBUG,
|
||||||
|
CLOG_INFO,
|
||||||
|
CLOG_WARN,
|
||||||
|
CLOG_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new logger writing to the given file path. The file will always
|
||||||
|
* be opened in append mode.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* A constant integer between 0 and 15 that uniquely identifies this logger.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* Path to the file where log messages will be written.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_init_path(int id, const char *const path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new logger writing to a file descriptor.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* A constant integer between 0 and 15 that uniquely identifies this logger.
|
||||||
|
*
|
||||||
|
* @param fd
|
||||||
|
* The file descriptor where log messages will be written.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_init_fd(int id, int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy (clean up) a logger. You should do this at the end of execution,
|
||||||
|
* or when you are done using the logger.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* The id of the logger to destroy.
|
||||||
|
*/
|
||||||
|
void clog_free(int id);
|
||||||
|
|
||||||
|
#define CLOG(id) __FILE__, __LINE__, id
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log functions (one per level). Call these to write messages to the log
|
||||||
|
* file. The first three arguments can be replaced with a call to the CLOG
|
||||||
|
* macro defined above, e.g.:
|
||||||
|
*
|
||||||
|
* clog_debug(CLOG(MY_LOGGER_ID), "This is a log message.");
|
||||||
|
*
|
||||||
|
* @param sfile
|
||||||
|
* The name of the source file making this log call (e.g. __FILE__).
|
||||||
|
*
|
||||||
|
* @param sline
|
||||||
|
* The line number of the call in the source code (e.g. __LINE__).
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* The id of the logger to write to.
|
||||||
|
*
|
||||||
|
* @param fmt
|
||||||
|
* The format string for the message (printf formatting).
|
||||||
|
*
|
||||||
|
* @param ...
|
||||||
|
* Any additional format arguments.
|
||||||
|
*/
|
||||||
|
void clog_debug(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||||
|
void clog_info(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||||
|
void clog_warn(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||||
|
void clog_error(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the minimum level of messages that should be written to the log.
|
||||||
|
* Messages below this level will not be written. By default, loggers are
|
||||||
|
* created with level == CLOG_DEBUG.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* The identifier of the logger.
|
||||||
|
*
|
||||||
|
* @param level
|
||||||
|
* The new minimum log level.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_set_level(int id, enum clog_level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the format string used for times. See strftime(3) for how this string
|
||||||
|
* should be defined. The default format string is CLOG_DEFAULT_TIME_FORMAT.
|
||||||
|
*
|
||||||
|
* @param fmt
|
||||||
|
* The new format string, which must be less than CLOG_FORMAT_LENGTH bytes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_set_time_fmt(int id, const char *fmt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the format string used for dates. See strftime(3) for how this string
|
||||||
|
* should be defined. The default format string is CLOG_DEFAULT_DATE_FORMAT.
|
||||||
|
*
|
||||||
|
* @param fmt
|
||||||
|
* The new format string, which must be less than CLOG_FORMAT_LENGTH bytes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_set_date_fmt(int id, const char *fmt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the format string for log messages. Here are the substitutions you may
|
||||||
|
* use:
|
||||||
|
*
|
||||||
|
* %f: Source file name generating the log call.
|
||||||
|
* %n: Source line number where the log call was made.
|
||||||
|
* %m: The message text sent to the logger (after printf formatting).
|
||||||
|
* %d: The current date, formatted using the logger's date format.
|
||||||
|
* %t: The current time, formatted using the logger's time format.
|
||||||
|
* %l: The log level (one of "DEBUG", "INFO", "WARN", or "ERROR").
|
||||||
|
* %%: A literal percent sign.
|
||||||
|
*
|
||||||
|
* The default format string is CLOG_DEFAULT_FORMAT.
|
||||||
|
*
|
||||||
|
* @param fmt
|
||||||
|
* The new format string, which must be less than CLOG_FORMAT_LENGTH bytes.
|
||||||
|
* You probably will want to end this with a newline (\n).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_set_fmt(int id, const char *fmt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callback function.
|
||||||
|
*
|
||||||
|
* @param cb
|
||||||
|
* The new callback function.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_set_cb(int id, void (*cb)(const char *msg, size_t len));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file descriptor.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* The identifier of the logger.
|
||||||
|
*
|
||||||
|
* @param fd
|
||||||
|
* The new file descriptor.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int clog_set_fd(int id, int fd);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No need to read below this point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The C logger structure.
|
||||||
|
*/
|
||||||
|
struct clog {
|
||||||
|
|
||||||
|
/* The current level of this logger. Messages below it will be dropped. */
|
||||||
|
enum clog_level level;
|
||||||
|
|
||||||
|
/* The file being written. */
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* The format specifier. */
|
||||||
|
char fmt[CLOG_FORMAT_LENGTH];
|
||||||
|
|
||||||
|
/* Date format */
|
||||||
|
char date_fmt[CLOG_FORMAT_LENGTH];
|
||||||
|
|
||||||
|
/* Time format */
|
||||||
|
char time_fmt[CLOG_FORMAT_LENGTH];
|
||||||
|
|
||||||
|
/* Tracks whether the fd needs to be closed eventually. */
|
||||||
|
int opened;
|
||||||
|
|
||||||
|
/* Callback function for each log message. */
|
||||||
|
void (*cb)(const char *msg, size_t len);
|
||||||
|
};
|
||||||
|
|
||||||
|
void _clog_err(const char *fmt, ...);
|
||||||
|
|
||||||
|
#ifdef CLOG_MAIN
|
||||||
|
struct clog *_clog_loggers[CLOG_MAX_LOGGERS] = { 0 };
|
||||||
|
#else
|
||||||
|
extern struct clog *_clog_loggers[CLOG_MAX_LOGGERS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CLOG_MAIN
|
||||||
|
|
||||||
|
const char *const CLOG_LEVEL_NAMES[] = {
|
||||||
|
"Debug",
|
||||||
|
"Info",
|
||||||
|
"Warning",
|
||||||
|
"Error",
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_init_path(int id, const char *const path)
|
||||||
|
{
|
||||||
|
int fd = open(path, O_CREAT | O_WRONLY | O_APPEND, 0666);
|
||||||
|
if (fd == -1) {
|
||||||
|
_clog_err("Unable to open %s: %s\n", path, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (clog_init_fd(id, fd)) {
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
_clog_loggers[id]->opened = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_init_fd(int id, int fd)
|
||||||
|
{
|
||||||
|
struct clog *logger;
|
||||||
|
|
||||||
|
if (_clog_loggers[id] != NULL) {
|
||||||
|
_clog_err("Logger %d already initialized.\n", id);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = (struct clog *) malloc(sizeof(struct clog));
|
||||||
|
if (logger == NULL) {
|
||||||
|
_clog_err("Failed to allocate logger: %s\n", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger->level = CLOG_DEBUG;
|
||||||
|
logger->fd = fd;
|
||||||
|
logger->opened = 0;
|
||||||
|
strcpy(logger->fmt, CLOG_DEFAULT_FORMAT);
|
||||||
|
strcpy(logger->date_fmt, CLOG_DEFAULT_DATE_FORMAT);
|
||||||
|
strcpy(logger->time_fmt, CLOG_DEFAULT_TIME_FORMAT);
|
||||||
|
logger->cb = NULL;
|
||||||
|
|
||||||
|
_clog_loggers[id] = logger;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clog_free(int id)
|
||||||
|
{
|
||||||
|
if (_clog_loggers[id]) {
|
||||||
|
if (_clog_loggers[id]->opened) {
|
||||||
|
close(_clog_loggers[id]->fd);
|
||||||
|
}
|
||||||
|
free(_clog_loggers[id]);
|
||||||
|
_clog_loggers[id]=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_set_level(int id, enum clog_level level)
|
||||||
|
{
|
||||||
|
if (_clog_loggers[id] == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((unsigned) level > CLOG_ERROR) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
_clog_loggers[id]->level = level;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_set_fd(int id, int fd)
|
||||||
|
{
|
||||||
|
if (_clog_loggers[id] == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
_clog_loggers[id]->fd = fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_set_time_fmt(int id, const char *fmt)
|
||||||
|
{
|
||||||
|
struct clog *logger = _clog_loggers[id];
|
||||||
|
if (logger == NULL) {
|
||||||
|
_clog_err("clog_set_time_fmt: No such logger: %d\n", id);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strlen(fmt) >= CLOG_FORMAT_LENGTH) {
|
||||||
|
_clog_err("clog_set_time_fmt: Format specifier too long.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
strcpy(logger->time_fmt, fmt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_set_date_fmt(int id, const char *fmt)
|
||||||
|
{
|
||||||
|
struct clog *logger = _clog_loggers[id];
|
||||||
|
if (logger == NULL) {
|
||||||
|
_clog_err("clog_set_date_fmt: No such logger: %d\n", id);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strlen(fmt) >= CLOG_FORMAT_LENGTH) {
|
||||||
|
_clog_err("clog_set_date_fmt: Format specifier too long.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
strcpy(logger->date_fmt, fmt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_set_fmt(int id, const char *fmt)
|
||||||
|
{
|
||||||
|
struct clog *logger = _clog_loggers[id];
|
||||||
|
if (logger == NULL) {
|
||||||
|
_clog_err("clog_set_fmt: No such logger: %d\n", id);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strlen(fmt) >= CLOG_FORMAT_LENGTH) {
|
||||||
|
_clog_err("clog_set_fmt: Format specifier too long.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
strcpy(logger->fmt, fmt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clog_set_cb(int id, void (*cb)(const char *msg, size_t len))
|
||||||
|
{
|
||||||
|
struct clog *logger = _clog_loggers[id];
|
||||||
|
if (logger == NULL) {
|
||||||
|
_clog_err("clog_set_cb: No such logger: %d\n", id);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
logger->cb = cb;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal functions */
|
||||||
|
|
||||||
|
size_t
|
||||||
|
_clog_append_str(char **dst, char *orig_buf, const char *src, size_t cur_size)
|
||||||
|
{
|
||||||
|
size_t new_size = cur_size;
|
||||||
|
|
||||||
|
while (strlen(*dst) + strlen(src) >= new_size) {
|
||||||
|
new_size *= 2;
|
||||||
|
}
|
||||||
|
if (new_size != cur_size) {
|
||||||
|
if (*dst == orig_buf) {
|
||||||
|
*dst = (char *) malloc(new_size);
|
||||||
|
strcpy(*dst, orig_buf);
|
||||||
|
} else {
|
||||||
|
*dst = (char *) realloc(*dst, new_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(*dst, src);
|
||||||
|
return new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
_clog_append_int(char **dst, char *orig_buf, long int d, size_t cur_size)
|
||||||
|
{
|
||||||
|
char buf[40]; /* Enough for 128-bit decimal */
|
||||||
|
if (snprintf(buf, 40, "%ld", d) >= 40) {
|
||||||
|
return cur_size;
|
||||||
|
}
|
||||||
|
return _clog_append_str(dst, orig_buf, buf, cur_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
_clog_append_time(char **dst, char *orig_buf, struct tm *lt,
|
||||||
|
const char *fmt, size_t cur_size)
|
||||||
|
{
|
||||||
|
char buf[CLOG_DATETIME_LENGTH];
|
||||||
|
size_t result = strftime(buf, CLOG_DATETIME_LENGTH, fmt, lt);
|
||||||
|
|
||||||
|
if (result > 0) {
|
||||||
|
return _clog_append_str(dst, orig_buf, buf, cur_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cur_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
_clog_basename(const char *path)
|
||||||
|
{
|
||||||
|
const char *slash = strrchr(path, '/');
|
||||||
|
if (slash) {
|
||||||
|
path = slash + 1;
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
slash = strrchr(path, '\\');
|
||||||
|
if (slash) {
|
||||||
|
path = slash + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
_clog_format(const struct clog *logger, char buf[], size_t buf_size,
|
||||||
|
const char *sfile, int sline, const char *level,
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
size_t cur_size = buf_size;
|
||||||
|
char *result = buf;
|
||||||
|
enum { NORMAL, SUBST } state = NORMAL;
|
||||||
|
size_t fmtlen = strlen(logger->fmt);
|
||||||
|
size_t i;
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm *lt = localtime(&t);
|
||||||
|
|
||||||
|
sfile = _clog_basename(sfile);
|
||||||
|
result[0] = 0;
|
||||||
|
for (i = 0; i < fmtlen; ++i) {
|
||||||
|
if (state == NORMAL) {
|
||||||
|
if (logger->fmt[i] == '%') {
|
||||||
|
state = SUBST;
|
||||||
|
} else {
|
||||||
|
char str[2] = { 0 };
|
||||||
|
str[0] = logger->fmt[i];
|
||||||
|
cur_size = _clog_append_str(&result, buf, str, cur_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (logger->fmt[i]) {
|
||||||
|
case '%':
|
||||||
|
cur_size = _clog_append_str(&result, buf, "%", cur_size);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
cur_size = _clog_append_time(&result, buf, lt,
|
||||||
|
logger->time_fmt, cur_size);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
cur_size = _clog_append_time(&result, buf, lt,
|
||||||
|
logger->date_fmt, cur_size);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
cur_size = _clog_append_str(&result, buf, level, cur_size);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
cur_size = _clog_append_int(&result, buf, sline, cur_size);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
cur_size = _clog_append_str(&result, buf, sfile, cur_size);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
cur_size = _clog_append_str(&result, buf, message,
|
||||||
|
cur_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state = NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_clog_log(const char *sfile, int sline, enum clog_level level,
|
||||||
|
int id, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
/* For speed: Use a stack buffer until message exceeds 4096, then switch
|
||||||
|
* to dynamically allocated. This should greatly reduce the number of
|
||||||
|
* memory allocations (and subsequent fragmentation). */
|
||||||
|
char buf[4096];
|
||||||
|
size_t buf_size = 4096;
|
||||||
|
char *dynbuf = buf;
|
||||||
|
char *message;
|
||||||
|
int result;
|
||||||
|
struct clog *logger = _clog_loggers[id];
|
||||||
|
|
||||||
|
if (!logger) {
|
||||||
|
_clog_err("No such logger: %d\n", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level < logger->level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format the message text with the argument list. */
|
||||||
|
result = vsnprintf(dynbuf, buf_size, fmt, ap);
|
||||||
|
if ((size_t) result >= buf_size) {
|
||||||
|
buf_size = result + 1;
|
||||||
|
dynbuf = (char *) malloc(buf_size);
|
||||||
|
result = vsnprintf(dynbuf, buf_size, fmt, ap);
|
||||||
|
if ((size_t) result >= buf_size) {
|
||||||
|
/* Formatting failed -- too large */
|
||||||
|
_clog_err("Formatting failed (1).\n");
|
||||||
|
free(dynbuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format according to log format and write to log */
|
||||||
|
{
|
||||||
|
char message_buf[4096];
|
||||||
|
message = _clog_format(logger, message_buf, 4096, sfile, sline,
|
||||||
|
CLOG_LEVEL_NAMES[level], dynbuf);
|
||||||
|
if (!message) {
|
||||||
|
_clog_err("Formatting failed (2).\n");
|
||||||
|
if (dynbuf != buf) {
|
||||||
|
free(dynbuf);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = write(logger->fd, message, strlen(message));
|
||||||
|
if (logger->cb) logger->cb(message,strlen(message));
|
||||||
|
if (result == -1) {
|
||||||
|
_clog_err("Unable to write to log file: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
if (message != message_buf) {
|
||||||
|
free(message);
|
||||||
|
}
|
||||||
|
if (dynbuf != buf) {
|
||||||
|
free(dynbuf);
|
||||||
|
}
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
fsync(logger->fd);
|
||||||
|
#else
|
||||||
|
HANDLE h = (HANDLE) _get_osfhandle(logger->fd);
|
||||||
|
if (h != INVALID_HANDLE_VALUE) {
|
||||||
|
// This call will fail on a console fd, but that's ok.
|
||||||
|
FlushFileBuffers(h);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clog_debug(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
_clog_log(sfile, sline, CLOG_DEBUG, id, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clog_info(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
_clog_log(sfile, sline, CLOG_INFO, id, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clog_warn(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
_clog_log(sfile, sline, CLOG_WARN, id, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clog_error(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
_clog_log(sfile, sline, CLOG_ERROR, id, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_clog_err(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
#ifdef CLOG_SILENT
|
||||||
|
(void) fmt;
|
||||||
|
#else
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CLOG_MAIN */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __CLOG_H__ */
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CUDA_CONE_DIMS_H
|
||||||
|
#define _CUDA_CONE_DIMS_H
|
||||||
|
|
||||||
|
#include "astra/GeometryUtil3D.h"
|
||||||
|
#include "mex.h"
|
||||||
|
#include "gpu/mxGPUArray.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace astraCUDA3d {
|
||||||
|
|
||||||
|
using astra::SConeProjection;
|
||||||
|
using astra::SPar3DProjection;
|
||||||
|
|
||||||
|
struct SDimensions3D {
|
||||||
|
unsigned int iVolX;
|
||||||
|
unsigned int iVolY;
|
||||||
|
unsigned int iVolZ;
|
||||||
|
unsigned int iProjAngles;
|
||||||
|
unsigned int iProjU; // number of detectors in the U direction
|
||||||
|
unsigned int iProjV; // number of detectors in the V direction
|
||||||
|
unsigned int iRaysPerDetDim;
|
||||||
|
unsigned int iRaysPerVoxelDim;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeformField {
|
||||||
|
const mxGPUArray * X0;
|
||||||
|
const mxGPUArray * Y0;
|
||||||
|
const mxGPUArray * Z0;
|
||||||
|
const mxGPUArray * X1;
|
||||||
|
const mxGPUArray * Y1;
|
||||||
|
const mxGPUArray * Z1;
|
||||||
|
bool use_deform;
|
||||||
|
bool use_linear_model;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||||
|
DWORD ul_reason_for_call,
|
||||||
|
LPVOID lpReserved
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (ul_reason_for_call)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,483 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
| |
|
||||||
|
| Except where otherwise noted, this work is licensed under a |
|
||||||
|
| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
| |
|
||||||
|
| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
| |
|
||||||
|
| Author: CXS group, PSI |
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
You may use this code with the following provisions:
|
||||||
|
|
||||||
|
If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
computing language this notice should be included in the redistribution.
|
||||||
|
|
||||||
|
If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
publication or if it is fully or partially rewritten for another
|
||||||
|
computing language the authors and institution should be acknowledged
|
||||||
|
in written form in the publication: “Data processing was carried out
|
||||||
|
using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
Paul Scherrer Institut, Switzerland.”
|
||||||
|
Variations on the latter text can be incorporated upon discussion with
|
||||||
|
the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
for the published work.
|
||||||
|
|
||||||
|
A publication that focuses on describing features, or parameters, that
|
||||||
|
are already existing in the code should be first discussed with the
|
||||||
|
authors.
|
||||||
|
|
||||||
|
This code and subroutines are part of a continuous development, they
|
||||||
|
are provided “as they are” without guarantees or liability on part
|
||||||
|
of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <cuda.h>
|
||||||
|
#include "util3d.h"
|
||||||
|
|
||||||
|
#ifdef STANDALONE
|
||||||
|
#include "par3d_fp.h"
|
||||||
|
#include "testutil.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dims3d.h"
|
||||||
|
|
||||||
|
typedef texture<float, 3, cudaReadModeElementType> texture3D;
|
||||||
|
|
||||||
|
static texture3D gT_par3DProjTexture, Xdef0_tex, Ydef0_tex, Zdef0_tex, Xdef1_tex, Ydef1_tex, Zdef1_tex;
|
||||||
|
|
||||||
|
namespace astraCUDA3d {
|
||||||
|
|
||||||
|
#define ZSIZE 6
|
||||||
|
static const unsigned int g_volBlockZ = ZSIZE;
|
||||||
|
|
||||||
|
static const unsigned int g_anglesPerBlock = 32;
|
||||||
|
static const unsigned int g_volBlockX = 16;
|
||||||
|
static const unsigned int g_volBlockY = 32;
|
||||||
|
|
||||||
|
static const unsigned g_MaxAngles = 1024;
|
||||||
|
|
||||||
|
__constant__ float gC_C[8*g_MaxAngles];
|
||||||
|
|
||||||
|
#define MAX(x,y) (x>y?x:y);
|
||||||
|
#define MIN(x,y) (x<y?x:y);
|
||||||
|
#define ABS(x) (x>0?x:-x);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
__global__ void dev_par3D_BP(void* D_volData, unsigned int volPitch,
|
||||||
|
int startAngle, int angleOffset, const SDimensions3D dims,
|
||||||
|
float fOutputScale, bool use_deform, bool linear_deform_model)
|
||||||
|
{
|
||||||
|
float* volData = (float*)D_volData;
|
||||||
|
|
||||||
|
int endAngle = startAngle + g_anglesPerBlock;
|
||||||
|
if (endAngle > dims.iProjAngles - angleOffset)
|
||||||
|
endAngle = dims.iProjAngles - angleOffset;
|
||||||
|
|
||||||
|
// threadIdx: x = rel x
|
||||||
|
// y = rel y
|
||||||
|
|
||||||
|
// blockIdx: x = x + y
|
||||||
|
// y = z
|
||||||
|
|
||||||
|
|
||||||
|
const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x;
|
||||||
|
const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y;
|
||||||
|
|
||||||
|
if (X >= dims.iVolX)
|
||||||
|
return;
|
||||||
|
if (Y >= dims.iVolY)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int startZ = blockIdx.y * g_volBlockZ;
|
||||||
|
|
||||||
|
const float limX = dims.iVolX;
|
||||||
|
const float limY = dims.iVolY;
|
||||||
|
const float limZ = dims.iVolZ;
|
||||||
|
|
||||||
|
float fX = X - 0.5f*limX + 0.5f;
|
||||||
|
float fY = Y - 0.5f*limY + 0.5f;
|
||||||
|
float fZ = startZ - 0.5f*limZ + 0.5f;
|
||||||
|
|
||||||
|
// solve by small blocks over all angles
|
||||||
|
float Z[ZSIZE];
|
||||||
|
for(int i=0; i < ZSIZE; i++)
|
||||||
|
Z[i] = 0.0f;
|
||||||
|
|
||||||
|
|
||||||
|
float fAngle = startAngle + angleOffset + 0.5f;
|
||||||
|
float4 fCu, fCv;
|
||||||
|
float fU, fV;
|
||||||
|
float fXn, fYn, fZn; // normalized coordinates
|
||||||
|
float fXs, fYs, fZs; // shifted coordinates
|
||||||
|
float angle_ratio ; // ratio from angle / iProjAngles
|
||||||
|
|
||||||
|
for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f)
|
||||||
|
{
|
||||||
|
|
||||||
|
fCu = make_float4(gC_C[8*angle+0], gC_C[8*angle+1], gC_C[8*angle+2], gC_C[8*angle+3]);
|
||||||
|
fCv = make_float4(gC_C[8*angle+4], gC_C[8*angle+5], gC_C[8*angle+6], gC_C[8*angle+7]);
|
||||||
|
|
||||||
|
angle_ratio = (float)angle / (float)dims.iProjAngles ;
|
||||||
|
|
||||||
|
|
||||||
|
if (use_deform)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
// FASTER APPROXIMATION FOR SMALL DEFORMATIONS
|
||||||
|
fXn = X/limX; // normalized coordinates
|
||||||
|
fYn = Y/limY;
|
||||||
|
fZn = startZ/limZ;
|
||||||
|
|
||||||
|
|
||||||
|
// load deformed coordinates
|
||||||
|
fXs = fX + tex3D(Xdef0_tex,fXn, fYn, fZn);
|
||||||
|
fYs = fY + tex3D(Ydef0_tex,fXn, fYn, fZn);
|
||||||
|
fZs = fZ + tex3D(Zdef0_tex,fXn, fYn, fZn);
|
||||||
|
|
||||||
|
// find location on the detector
|
||||||
|
fU = fCu.w + fXs * fCu.x + fYs * fCu.y + fZs * fCu.z;
|
||||||
|
fV = fCv.w + fXs * fCv.x + fYs * fCv.y + fZs * fCv.z;
|
||||||
|
|
||||||
|
for (int idx = 0; idx < ZSIZE; ++idx) {
|
||||||
|
// get bilinear interpolation back to non-shifted coordinates
|
||||||
|
Z[idx] += tex3D(gT_par3DProjTexture, fU, fAngle, fV);
|
||||||
|
|
||||||
|
// TODO: check if approximation that deformation is constant for Z block is valid !!
|
||||||
|
fU += fCu.z;
|
||||||
|
fV += fCv.z;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ARBITRARY DEFORMATIONS APPROXIMATION
|
||||||
|
|
||||||
|
fXn = X/limX; // normalized coordinates
|
||||||
|
fYn = Y/limY;
|
||||||
|
for (int idx = 0; idx < ZSIZE; ++idx) {
|
||||||
|
fZs = fZ + idx; // Z coordinate
|
||||||
|
fZn = (startZ+idx)/limZ; // normalized Z coordinate
|
||||||
|
|
||||||
|
// load deformed coordinates
|
||||||
|
if (!linear_deform_model){
|
||||||
|
fXs = fX + tex3D(Xdef0_tex,fXn, fYn, fZn);
|
||||||
|
fYs = fY + tex3D(Ydef0_tex,fXn, fYn, fZn);
|
||||||
|
fZs = fZs +tex3D(Zdef0_tex,fXn, fYn, fZn);
|
||||||
|
} else {
|
||||||
|
// deformated coordinates with linear interpolation
|
||||||
|
fXs = fX + (tex3D(Xdef0_tex,fXn, fYn, fZn) * (1-angle_ratio) + angle_ratio*tex3D(Xdef1_tex,fXn, fYn, fZn));
|
||||||
|
fYs = fY + (tex3D(Ydef0_tex,fXn, fYn, fZn) * (1-angle_ratio) + angle_ratio*tex3D(Ydef1_tex,fXn, fYn, fZn));
|
||||||
|
fZs = fZs +(tex3D(Zdef0_tex,fXn, fYn, fZn) * (1-angle_ratio) + angle_ratio*tex3D(Zdef1_tex,fXn, fYn, fZn));
|
||||||
|
}
|
||||||
|
|
||||||
|
// find location on the detector
|
||||||
|
fU = fCu.w + fXs * fCu.x + fYs * fCu.y + fZs * fCu.z;
|
||||||
|
fV = fCv.w + fXs * fCv.x + fYs * fCv.y + fZs * fCv.z;
|
||||||
|
|
||||||
|
// get bilinear interpolation back to non-shifted coordinates
|
||||||
|
Z[idx] += tex3D(gT_par3DProjTexture, fU, fAngle, fV);
|
||||||
|
|
||||||
|
// TODO: check if approximation that deformation is constant for Z block is valid !!
|
||||||
|
fU += fCu.z;
|
||||||
|
fV += fCv.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
|
fU = fCu.w + fX * fCu.x + fY * fCu.y + fZ * fCu.z;
|
||||||
|
fV = fCv.w + fX * fCv.x + fY * fCv.y + fZ * fCv.z;
|
||||||
|
|
||||||
|
for (int idx = 0; idx < ZSIZE; ++idx) {
|
||||||
|
|
||||||
|
Z[idx] += tex3D(gT_par3DProjTexture, fU, fAngle, fV);
|
||||||
|
|
||||||
|
fU += fCu.z;
|
||||||
|
fV += fCv.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int endZ = ZSIZE;
|
||||||
|
if (endZ > dims.iVolZ - startZ)
|
||||||
|
endZ = dims.iVolZ - startZ;
|
||||||
|
|
||||||
|
for(int i=0; i < endZ; i++)
|
||||||
|
volData[((startZ+i)*dims.iVolY+Y)*volPitch+X] += Z[i] * fOutputScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// supersampling version
|
||||||
|
__global__ void dev_par3D_BP_SS(void* D_volData, unsigned int volPitch, int startAngle, int angleOffset, const SDimensions3D dims, float fOutputScale)
|
||||||
|
{
|
||||||
|
float* volData = (float*)D_volData;
|
||||||
|
|
||||||
|
int endAngle = startAngle + g_anglesPerBlock;
|
||||||
|
if (endAngle > dims.iProjAngles - angleOffset)
|
||||||
|
endAngle = dims.iProjAngles - angleOffset;
|
||||||
|
|
||||||
|
// threadIdx: x = rel x
|
||||||
|
// y = rel y
|
||||||
|
|
||||||
|
// blockIdx: x = x + y
|
||||||
|
// y = z
|
||||||
|
|
||||||
|
|
||||||
|
// TO TRY: precompute part of detector intersection formulas in shared mem?
|
||||||
|
// TO TRY: inner loop over z, gather ray values in shared mem
|
||||||
|
|
||||||
|
const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x;
|
||||||
|
const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y;
|
||||||
|
|
||||||
|
if (X >= dims.iVolX)
|
||||||
|
return;
|
||||||
|
if (Y >= dims.iVolY)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int startZ = blockIdx.y * g_volBlockZ;
|
||||||
|
int endZ = startZ + g_volBlockZ;
|
||||||
|
if (endZ > dims.iVolZ)
|
||||||
|
endZ = dims.iVolZ;
|
||||||
|
|
||||||
|
float fX = X - 0.5f*dims.iVolX + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
|
||||||
|
float fY = Y - 0.5f*dims.iVolY + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
|
||||||
|
float fZ = startZ - 0.5f*dims.iVolZ + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
|
||||||
|
|
||||||
|
const float fSubStep = 1.0f/dims.iRaysPerVoxelDim;
|
||||||
|
|
||||||
|
fOutputScale /= (dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim);
|
||||||
|
|
||||||
|
|
||||||
|
for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f)
|
||||||
|
{
|
||||||
|
|
||||||
|
float fVal = 0.0f;
|
||||||
|
float fAngle = startAngle + angleOffset + 0.5f;
|
||||||
|
|
||||||
|
for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f)
|
||||||
|
{
|
||||||
|
const float fCux = gC_C[8*angle+0];
|
||||||
|
const float fCuy = gC_C[8*angle+1];
|
||||||
|
const float fCuz = gC_C[8*angle+2];
|
||||||
|
const float fCuc = gC_C[8*angle+3];
|
||||||
|
const float fCvx = gC_C[8*angle+4];
|
||||||
|
const float fCvy = gC_C[8*angle+5];
|
||||||
|
const float fCvz = gC_C[8*angle+6];
|
||||||
|
const float fCvc = gC_C[8*angle+7];
|
||||||
|
|
||||||
|
float fXs = fX;
|
||||||
|
for (int iSubX = 0; iSubX < dims.iRaysPerVoxelDim; ++iSubX) {
|
||||||
|
float fYs = fY;
|
||||||
|
for (int iSubY = 0; iSubY < dims.iRaysPerVoxelDim; ++iSubY) {
|
||||||
|
float fZs = fZ;
|
||||||
|
for (int iSubZ = 0; iSubZ < dims.iRaysPerVoxelDim; ++iSubZ) {
|
||||||
|
|
||||||
|
const float fU = fCuc + fXs * fCux + fYs * fCuy + fZs * fCuz;
|
||||||
|
const float fV = fCvc + fXs * fCvx + fYs * fCvy + fZs * fCvz;
|
||||||
|
|
||||||
|
fVal += tex3D(gT_par3DProjTexture, fU, fAngle, fV);
|
||||||
|
fZs += fSubStep;
|
||||||
|
}
|
||||||
|
fYs += fSubStep;
|
||||||
|
}
|
||||||
|
fXs += fSubStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal * fOutputScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Par3DBP_Array(cudaPitchedPtr D_volumeData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale, bool use_deform, bool linear_deform_model)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (unsigned int th = 0; th < dims.iProjAngles; th += g_MaxAngles) {
|
||||||
|
unsigned int angleCount = g_MaxAngles;
|
||||||
|
if (th + angleCount > dims.iProjAngles)
|
||||||
|
angleCount = dims.iProjAngles - th;
|
||||||
|
|
||||||
|
// transfer angles to constant memory
|
||||||
|
float* tmp = new float[8*dims.iProjAngles];
|
||||||
|
|
||||||
|
// NB: We increment angles at the end of the loop body.
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Use functions from dims3d.cu for this:
|
||||||
|
|
||||||
|
#define TRANSFER_TO_CONSTANT(expr,name) do { for (unsigned int i = 0; i < angleCount; ++i) tmp[8*i + name] = (expr) ; } while (0)
|
||||||
|
|
||||||
|
#define DENOM (angles[i].fRayX*angles[i].fDetUY*angles[i].fDetVZ - angles[i].fRayX*angles[i].fDetUZ*angles[i].fDetVY - angles[i].fRayY*angles[i].fDetUX*angles[i].fDetVZ + angles[i].fRayY*angles[i].fDetUZ*angles[i].fDetVX + angles[i].fRayZ*angles[i].fDetUX*angles[i].fDetVY - angles[i].fRayZ*angles[i].fDetUY*angles[i].fDetVX)
|
||||||
|
|
||||||
|
TRANSFER_TO_CONSTANT( ( - (angles[i].fRayY*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVY)) / DENOM , 0 );
|
||||||
|
TRANSFER_TO_CONSTANT( ( (angles[i].fRayX*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVX)) / DENOM , 1 );
|
||||||
|
TRANSFER_TO_CONSTANT( (- (angles[i].fRayX*angles[i].fDetVY - angles[i].fRayY*angles[i].fDetVX) ) / DENOM , 2 );
|
||||||
|
TRANSFER_TO_CONSTANT( (-(angles[i].fDetSY*angles[i].fDetVZ - angles[i].fDetSZ*angles[i].fDetVY)*angles[i].fRayX + (angles[i].fRayY*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVY)*angles[i].fDetSX - (angles[i].fRayY*angles[i].fDetSZ - angles[i].fRayZ*angles[i].fDetSY)*angles[i].fDetVX) / DENOM , 3 );
|
||||||
|
|
||||||
|
TRANSFER_TO_CONSTANT( ((angles[i].fRayY*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUY) ) / DENOM , 4 );
|
||||||
|
TRANSFER_TO_CONSTANT( (- (angles[i].fRayX*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUX) ) / DENOM , 5 );
|
||||||
|
TRANSFER_TO_CONSTANT( ((angles[i].fRayX*angles[i].fDetUY - angles[i].fRayY*angles[i].fDetUX) ) / DENOM , 6 );
|
||||||
|
TRANSFER_TO_CONSTANT( ((angles[i].fDetSY*angles[i].fDetUZ - angles[i].fDetSZ*angles[i].fDetUY)*angles[i].fRayX - (angles[i].fRayY*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUY)*angles[i].fDetSX + (angles[i].fRayY*angles[i].fDetSZ - angles[i].fRayZ*angles[i].fDetSY)*angles[i].fDetUX ) / DENOM , 7 );
|
||||||
|
|
||||||
|
#undef TRANSFER_TO_CONSTANT
|
||||||
|
#undef DENOM
|
||||||
|
|
||||||
|
cudaMemcpyToSymbol(gC_C, tmp, angleCount*8*sizeof(float), 0, cudaMemcpyHostToDevice);
|
||||||
|
|
||||||
|
delete[] tmp;
|
||||||
|
|
||||||
|
checkLastError("after cudaMemcpyToSymbol");
|
||||||
|
|
||||||
|
|
||||||
|
dim3 dimBlock(g_volBlockX, g_volBlockY);
|
||||||
|
|
||||||
|
dim3 dimGrid(((dims.iVolX+g_volBlockX-1)/g_volBlockX)*((dims.iVolY+g_volBlockY-1)/g_volBlockY), (dims.iVolZ+g_volBlockZ-1)/g_volBlockZ);
|
||||||
|
|
||||||
|
// timeval t;
|
||||||
|
// tic(t);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < angleCount; i += g_anglesPerBlock) {
|
||||||
|
// printf("Calling BP: %d, %dx%d, %dx%d to %p\n", i, dimBlock.x, dimBlock.y, dimGrid.x, dimGrid.y, (void*)D_volumeData.ptr);
|
||||||
|
if (dims.iRaysPerVoxelDim == 1)
|
||||||
|
dev_par3D_BP<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, th, dims, fOutputScale, use_deform, linear_deform_model);
|
||||||
|
else
|
||||||
|
dev_par3D_BP_SS<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, th, dims, fOutputScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
cudaTextForceKernelsCompletion();
|
||||||
|
checkLastError("after cudaTextForceKernelsCompletion");
|
||||||
|
|
||||||
|
angles = angles + angleCount;
|
||||||
|
// printf("%f\n", toc(t));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Par3DBP(cudaPitchedPtr D_volumeData,
|
||||||
|
cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale, DeformField DF)
|
||||||
|
{
|
||||||
|
// transfer projections to array
|
||||||
|
|
||||||
|
checkLastError("before allocateVolumeArray");
|
||||||
|
|
||||||
|
cudaArray* cuArray = allocateProjectionArray(dims);
|
||||||
|
checkLastError("after allocateVolumeArray");
|
||||||
|
|
||||||
|
transferProjectionsToArray(D_projData, cuArray, dims);
|
||||||
|
|
||||||
|
checkLastError("after transferProjectionsToArray");
|
||||||
|
|
||||||
|
bindDataTexture(cuArray, gT_par3DProjTexture, cudaAddressModeBorder, false);
|
||||||
|
checkLastError("after bindProjDataTexture");
|
||||||
|
|
||||||
|
cudaArray * cuArrX0, *cuArrY0, *cuArrZ0, *cuArrX1, *cuArrY1, *cuArrZ1 ;
|
||||||
|
|
||||||
|
|
||||||
|
if (DF.use_deform) {
|
||||||
|
// mexPrintf("transferDeformationToArray\n");
|
||||||
|
|
||||||
|
cuArrX0 = transferDeformationToArray(DF.X0);
|
||||||
|
cuArrY0 = transferDeformationToArray(DF.Y0);
|
||||||
|
cuArrZ0 = transferDeformationToArray(DF.Z0);
|
||||||
|
bindDataTexture(cuArrX0, Xdef0_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrY0, Ydef0_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrZ0, Zdef0_tex,cudaAddressModeClamp, true);
|
||||||
|
if (DF.use_linear_model) {
|
||||||
|
cuArrX1 = transferDeformationToArray(DF.X1);
|
||||||
|
cuArrY1 = transferDeformationToArray(DF.Y1);
|
||||||
|
cuArrZ1 = transferDeformationToArray(DF.Z1);
|
||||||
|
bindDataTexture(cuArrX1, Xdef1_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrY1, Ydef1_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrZ1, Zdef1_tex,cudaAddressModeClamp, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = Par3DBP_Array(D_volumeData, dims, angles, fOutputScale, DF.use_deform, DF.use_linear_model);
|
||||||
|
|
||||||
|
checkLastError("after Par3DBP_Array");
|
||||||
|
|
||||||
|
cudaUnbindTexture(gT_par3DProjTexture);
|
||||||
|
checkLastError("after cudaUnbindTexture");
|
||||||
|
|
||||||
|
cudaFreeArray(cuArray);
|
||||||
|
|
||||||
|
checkLastError("after cudaFreeArray");
|
||||||
|
|
||||||
|
|
||||||
|
if (DF.use_deform) {
|
||||||
|
cudaFreeArray(cuArrX0);
|
||||||
|
cudaFreeArray(cuArrY0);
|
||||||
|
cudaFreeArray(cuArrZ0);
|
||||||
|
cudaUnbindTexture(Xdef0_tex);
|
||||||
|
cudaUnbindTexture(Ydef0_tex);
|
||||||
|
cudaUnbindTexture(Zdef0_tex);
|
||||||
|
if (DF.use_linear_model) {
|
||||||
|
cudaFreeArray(cuArrX1);
|
||||||
|
cudaFreeArray(cuArrY1);
|
||||||
|
cudaFreeArray(cuArrZ1);
|
||||||
|
cudaUnbindTexture(Xdef1_tex);
|
||||||
|
cudaUnbindTexture(Ydef1_tex);
|
||||||
|
cudaUnbindTexture(Zdef1_tex);
|
||||||
|
}
|
||||||
|
checkLastError("unbind deforms");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CUDA_PAR3D_BP_H
|
||||||
|
#define _CUDA_PAR3D_BP_H
|
||||||
|
|
||||||
|
namespace astraCUDA3d {
|
||||||
|
|
||||||
|
_AstraExport bool Par3DBP_Array(cudaPitchedPtr D_volumeData,
|
||||||
|
cudaArray *D_projArray,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale);
|
||||||
|
|
||||||
|
_AstraExport bool Par3DBP(cudaPitchedPtr D_volumeData,
|
||||||
|
cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale, DeformField DF);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,929 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
| |
|
||||||
|
| Except where otherwise noted, this work is licensed under a |
|
||||||
|
| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
| |
|
||||||
|
| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
| |
|
||||||
|
| Author: CXS group, PSI |
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
You may use this code with the following provisions:
|
||||||
|
|
||||||
|
If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
computing language this notice should be included in the redistribution.
|
||||||
|
|
||||||
|
If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
publication or if it is fully or partially rewritten for another
|
||||||
|
computing language the authors and institution should be acknowledged
|
||||||
|
in written form in the publication: “Data processing was carried out
|
||||||
|
using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
Paul Scherrer Institut, Switzerland.”
|
||||||
|
Variations on the latter text can be incorporated upon discussion with
|
||||||
|
the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
for the published work.
|
||||||
|
|
||||||
|
A publication that focuses on describing features, or parameters, that
|
||||||
|
are already existing in the code should be first discussed with the
|
||||||
|
authors.
|
||||||
|
|
||||||
|
This code and subroutines are part of a continuous development, they
|
||||||
|
are provided “as they are” without guarantees or liability on part
|
||||||
|
of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <cuda.h>
|
||||||
|
#include "util3d.h"
|
||||||
|
|
||||||
|
#include "mex.h"
|
||||||
|
#include "gpu/mxGPUArray.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef STANDALONE
|
||||||
|
#include "testutil.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dims3d.h"
|
||||||
|
|
||||||
|
typedef texture<float, 3, cudaReadModeElementType> texture3D;
|
||||||
|
|
||||||
|
static texture3D gT_par3DVolumeTexture, Xdef0_tex, Ydef0_tex, Zdef0_tex, Xdef1_tex, Ydef1_tex, Zdef1_tex;
|
||||||
|
|
||||||
|
#define MAX(x,y) (x>y?x:y);
|
||||||
|
#define MIN(x,y) (x<y?x:y);
|
||||||
|
|
||||||
|
|
||||||
|
namespace astraCUDA3d {
|
||||||
|
|
||||||
|
static const unsigned int g_anglesPerBlock = 4;
|
||||||
|
|
||||||
|
// thickness of the slices we're splitting the volume up into
|
||||||
|
static const unsigned int g_blockSlices = 32;
|
||||||
|
static const unsigned int g_detBlockU = 32;
|
||||||
|
static const unsigned int g_detBlockV = 32;
|
||||||
|
|
||||||
|
static const unsigned g_MaxAngles = 1024;
|
||||||
|
__constant__ float gC_RayX[g_MaxAngles];
|
||||||
|
__constant__ float gC_RayY[g_MaxAngles];
|
||||||
|
__constant__ float gC_RayZ[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetSX[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetSY[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetSZ[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetUX[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetUY[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetUZ[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetVX[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetVY[g_MaxAngles];
|
||||||
|
__constant__ float gC_DetVZ[g_MaxAngles];
|
||||||
|
//__constant__ uint8_T gC_use_deform[1];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void __global__ SetVal(float const * const A, float * const B, int const N)
|
||||||
|
{
|
||||||
|
/* Calculate the global linear index, assuming a 1-d grid. */
|
||||||
|
int const i = blockDim.x * blockIdx.x + threadIdx.x;
|
||||||
|
if (i < N) {
|
||||||
|
B[i] = A[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// x=0, y=1, z=2
|
||||||
|
struct DIR_X {
|
||||||
|
__device__ float nSlices(const SDimensions3D& dims) const { return dims.iVolX; }
|
||||||
|
__device__ float nDim1(const SDimensions3D& dims) const { return dims.iVolY; }
|
||||||
|
__device__ float nDim2(const SDimensions3D& dims) const { return dims.iVolZ; }
|
||||||
|
__device__ float c0(float x, float y, float z) const { return x; }
|
||||||
|
__device__ float c1(float x, float y, float z) const { return y; }
|
||||||
|
__device__ float c2(float x, float y, float z) const { return z; }
|
||||||
|
__device__ float tex(float f0, float f1, float f2) const { return tex3D(gT_par3DVolumeTexture, f0, f1, f2); }
|
||||||
|
__device__ float texD0x(float f0, float f1, float f2) const { return tex3D(Xdef0_tex, f0, f1, f2); }
|
||||||
|
__device__ float texD0y(float f0, float f1, float f2) const { return tex3D(Ydef0_tex, f0, f1, f2); }
|
||||||
|
__device__ float texD0z(float f0, float f1, float f2) const { return tex3D(Zdef0_tex, f0, f1, f2); }
|
||||||
|
__device__ float texD1x(float f0, float f1, float f2) const { return tex3D(Xdef1_tex, f0, f1, f2); }
|
||||||
|
__device__ float texD1y(float f0, float f1, float f2) const { return tex3D(Ydef1_tex, f0, f1, f2); }
|
||||||
|
__device__ float texD1z(float f0, float f1, float f2) const { return tex3D(Zdef1_tex, f0, f1, f2); }
|
||||||
|
__device__ float x(float f0, float f1, float f2) const { return f0; }
|
||||||
|
__device__ float y(float f0, float f1, float f2) const { return f1; }
|
||||||
|
__device__ float z(float f0, float f1, float f2) const { return f2; }
|
||||||
|
__device__ float offx(const SDimensions3D& dims) const { return dims.iProjU*0.5f; }
|
||||||
|
__device__ float offy(const SDimensions3D& dims) const { return dims.iProjV*0.5f; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// y=0, x=1, z=2
|
||||||
|
struct DIR_Y {
|
||||||
|
__device__ float nSlices(const SDimensions3D& dims) const { return dims.iVolY; }
|
||||||
|
__device__ float nDim1(const SDimensions3D& dims) const { return dims.iVolX; }
|
||||||
|
__device__ float nDim2(const SDimensions3D& dims) const { return dims.iVolZ; }
|
||||||
|
__device__ float c0(float x, float y, float z) const { return y; }
|
||||||
|
__device__ float c1(float x, float y, float z) const { return x; }
|
||||||
|
__device__ float c2(float x, float y, float z) const { return z; }
|
||||||
|
__device__ float tex(float f0, float f1, float f2) const { return tex3D(gT_par3DVolumeTexture, f1, f0, f2); }
|
||||||
|
__device__ float texD0x(float f0, float f1, float f2) const { return tex3D(Ydef0_tex, f1, f0, f2); }
|
||||||
|
__device__ float texD0y(float f0, float f1, float f2) const { return tex3D(Xdef0_tex, f1, f0, f2); }
|
||||||
|
__device__ float texD0z(float f0, float f1, float f2) const { return tex3D(Zdef0_tex, f1, f0, f2); }
|
||||||
|
__device__ float texD1x(float f0, float f1, float f2) const { return tex3D(Ydef1_tex, f1, f0, f2); }
|
||||||
|
__device__ float texD1y(float f0, float f1, float f2) const { return tex3D(Xdef1_tex, f1, f0, f2); }
|
||||||
|
__device__ float texD1z(float f0, float f1, float f2) const { return tex3D(Zdef1_tex, f1, f0, f2); }
|
||||||
|
__device__ float x(float f0, float f1, float f2) const { return f1; }
|
||||||
|
__device__ float y(float f0, float f1, float f2) const { return f0; }
|
||||||
|
__device__ float z(float f0, float f1, float f2) const { return f2; }
|
||||||
|
__device__ float offx(const SDimensions3D& dims) const { return dims.iProjU*0.5f; }
|
||||||
|
__device__ float offy(const SDimensions3D& dims) const { return dims.iProjV*0.5f; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// z=0, x=1, y=2
|
||||||
|
struct DIR_Z {
|
||||||
|
__device__ float nSlices(const SDimensions3D& dims) const { return dims.iVolZ; }
|
||||||
|
__device__ float nDim1(const SDimensions3D& dims) const { return dims.iVolX; }
|
||||||
|
__device__ float nDim2(const SDimensions3D& dims) const { return dims.iVolY; }
|
||||||
|
__device__ float c0(float x, float y, float z) const { return z; }
|
||||||
|
__device__ float c1(float x, float y, float z) const { return x; }
|
||||||
|
__device__ float c2(float x, float y, float z) const { return y; }
|
||||||
|
__device__ float tex(float f0, float f1, float f2) const { return tex3D(gT_par3DVolumeTexture, f1, f2, f0); }
|
||||||
|
__device__ float texD0x(float f0, float f1, float f2) const { return tex3D(Zdef0_tex, f1, f2, f0); }
|
||||||
|
__device__ float texD0y(float f0, float f1, float f2) const { return tex3D(Xdef0_tex, f1, f2, f0); }
|
||||||
|
__device__ float texD0z(float f0, float f1, float f2) const { return tex3D(Ydef0_tex, f1, f2, f0); }
|
||||||
|
__device__ float texD1x(float f0, float f1, float f2) const { return tex3D(Zdef1_tex, f1, f2, f0); }
|
||||||
|
__device__ float texD1y(float f0, float f1, float f2) const { return tex3D(Xdef1_tex, f1, f2, f0); }
|
||||||
|
__device__ float texD1z(float f0, float f1, float f2) const { return tex3D(Ydef1_tex, f1, f2, f0); }
|
||||||
|
__device__ float x(float f0, float f1, float f2) const { return f1; }
|
||||||
|
__device__ float y(float f0, float f1, float f2) const { return f2; }
|
||||||
|
__device__ float z(float f0, float f1, float f2) const { return f0; }
|
||||||
|
__device__ float offx(const SDimensions3D& dims) const { return dims.iProjU*0.5f; }
|
||||||
|
__device__ float offy(const SDimensions3D& dims) const { return dims.iProjV*0.5f; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// threadIdx: x = u detector
|
||||||
|
// y = relative angle
|
||||||
|
// blockIdx: x = u/v detector
|
||||||
|
// y = angle block
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<class COORD>
|
||||||
|
__global__ void par3D_FP_t(float* D_projData, unsigned int projPitch,
|
||||||
|
unsigned int startSlice,
|
||||||
|
unsigned int startAngle, unsigned int endAngle,
|
||||||
|
const SDimensions3D dims, float fOutputScale, const bool use_deform, const bool linear_deform_model)
|
||||||
|
{
|
||||||
|
COORD c;
|
||||||
|
|
||||||
|
|
||||||
|
int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y;
|
||||||
|
if (angle >= endAngle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const float fRayX = gC_RayX[angle];
|
||||||
|
const float fRayY = gC_RayY[angle];
|
||||||
|
const float fRayZ = gC_RayZ[angle];
|
||||||
|
const float fDetUX = gC_DetUX[angle];
|
||||||
|
const float fDetUY = gC_DetUY[angle];
|
||||||
|
const float fDetUZ = gC_DetUZ[angle];
|
||||||
|
const float fDetVX = gC_DetVX[angle];
|
||||||
|
const float fDetVY = gC_DetVY[angle];
|
||||||
|
const float fDetVZ = gC_DetVZ[angle];
|
||||||
|
const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX;
|
||||||
|
const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY;
|
||||||
|
const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (c.c0(fRayX, fRayY, fRayZ) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x;
|
||||||
|
|
||||||
|
if (detectorU >= dims.iProjU)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV;
|
||||||
|
int endDetectorV = startDetectorV + g_detBlockV;
|
||||||
|
if (endDetectorV > dims.iProjV)
|
||||||
|
endDetectorV = dims.iProjV;
|
||||||
|
|
||||||
|
int endSlice = startSlice + g_blockSlices;
|
||||||
|
if (endSlice > c.nSlices(dims))
|
||||||
|
endSlice = c.nSlices(dims);
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
/*if (endSlice < startSlice - 1)
|
||||||
|
return;*/
|
||||||
|
|
||||||
|
float angle_ratio = (float)angle / (float)dims.iProjAngles ;
|
||||||
|
|
||||||
|
|
||||||
|
for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV)
|
||||||
|
{
|
||||||
|
/* Trace ray in direction Ray to (detectorU,detectorV) from */
|
||||||
|
/* X = startSlice to X = endSlice */
|
||||||
|
|
||||||
|
const float fDetX = fDetSX + (detectorU*fDetUX + detectorV*fDetVX);
|
||||||
|
const float fDetY = fDetSY + (detectorU*fDetUY + detectorV*fDetVY);
|
||||||
|
const float fDetZ = fDetSZ + (detectorU*fDetUZ + detectorV*fDetVZ);
|
||||||
|
|
||||||
|
/* (x) ( 1) ( 0) */
|
||||||
|
/* ray: (y) = (ay) * x + (by) */
|
||||||
|
/* (z) (az) (bz) */
|
||||||
|
|
||||||
|
const float a1 = c.c1(fRayX,fRayY,fRayZ) / c.c0(fRayX,fRayY,fRayZ);
|
||||||
|
const float a2 = c.c2(fRayX,fRayY,fRayZ) / c.c0(fRayX,fRayY,fRayZ);
|
||||||
|
const float b1 = c.c1(fDetX,fDetY,fDetZ) - a1 * c.c0(fDetX,fDetY,fDetZ);
|
||||||
|
const float b2 = c.c2(fDetX,fDetY,fDetZ) - a2 * c.c0(fDetX,fDetY,fDetZ);
|
||||||
|
|
||||||
|
const float fDistCorr = sqrt(a1*a1+a2*a2+1.0f) * fOutputScale;
|
||||||
|
|
||||||
|
float fVal = 0.0f;
|
||||||
|
|
||||||
|
//float f0 = startSlice + 0.5f;
|
||||||
|
//float f1 = a1 * (startSlice - 0.5f*c.nSlices(dims) + 0.5f) + b1 + 0.5f*c.nDim1(dims) - 0.5f + 0.5f;
|
||||||
|
//float f2 = a2 * (startSlice - 0.5f*c.nSlices(dims) + 0.5f) + b2 + 0.5f*c.nDim2(dims) - 0.5f + 0.5f;
|
||||||
|
|
||||||
|
bool is_inside;
|
||||||
|
int lim0, lim1, lim2;
|
||||||
|
lim0 = c.nSlices(dims);
|
||||||
|
lim1 = c.nDim1(dims);
|
||||||
|
lim2 = c.nDim2(dims);
|
||||||
|
const float offset = 0.5*lim0;
|
||||||
|
|
||||||
|
// calculate minimal distance needed to get the subprojection, important for laminography and large projection size
|
||||||
|
|
||||||
|
int startSlice_tmp = startSlice;
|
||||||
|
int endSlice_tmp = endSlice;
|
||||||
|
|
||||||
|
if (a1 > 0)
|
||||||
|
{
|
||||||
|
startSlice_tmp = MAX(startSlice_tmp, floor((-0.5*lim1-b1-0.5f)/a1+offset-1.0f));
|
||||||
|
endSlice_tmp = MIN(endSlice_tmp, ceil((+0.5*lim1-b1+0.5f)/a1+offset+1.0f));
|
||||||
|
}
|
||||||
|
else if (a1 < 0)
|
||||||
|
{
|
||||||
|
startSlice_tmp = MAX(startSlice_tmp, floor((+0.5*lim1-b1+0.5f)/a1+offset-1.0f));
|
||||||
|
endSlice_tmp = MIN(endSlice_tmp, ceil((-0.5*lim1-b1-0.5f)/a1+offset+1.0f));
|
||||||
|
}
|
||||||
|
if (a2 > 0)
|
||||||
|
{
|
||||||
|
startSlice_tmp = MAX(startSlice_tmp, floor((-0.5*lim2-b2-0.5f)/a2+offset-1.0f));
|
||||||
|
endSlice_tmp = MIN(endSlice_tmp, ceil((+0.5*lim2-b2+0.5f)/a2+offset+1.0f));
|
||||||
|
}
|
||||||
|
else if (a2 < 0)
|
||||||
|
{
|
||||||
|
startSlice_tmp = MAX(startSlice_tmp, floor((+0.5*lim2-b2+0.5f)/a2+offset-1.0f));
|
||||||
|
endSlice_tmp = MIN(endSlice_tmp, ceil((-0.5*lim2-b2-0.5f)/a2+offset+1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
endSlice_tmp = MIN(endSlice_tmp, endSlice);
|
||||||
|
endSlice_tmp = MAX(endSlice_tmp, 0);
|
||||||
|
|
||||||
|
startSlice_tmp = MAX(startSlice_tmp, startSlice);
|
||||||
|
startSlice_tmp = MIN(startSlice_tmp, endSlice_tmp);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
float f0 = startSlice_tmp + 0.5f;
|
||||||
|
float f1 = a1 * (startSlice_tmp - offset+0.5f) + b1 + 0.5f*c.nDim1(dims);
|
||||||
|
float f2 = a2 * (startSlice_tmp - offset+0.5f) + b2 + 0.5f*c.nDim2(dims);
|
||||||
|
|
||||||
|
|
||||||
|
float f0s, f1s, f2s; // shifted coordinates
|
||||||
|
float f0n, f1n, f2n; // normalized coordinates
|
||||||
|
|
||||||
|
// 87% of the execution time
|
||||||
|
for (int s = startSlice_tmp; s < endSlice_tmp; ++s)
|
||||||
|
{
|
||||||
|
if (use_deform) {
|
||||||
|
f0n = f0/lim0; // normalized coordinates
|
||||||
|
f1n = f1/lim1;
|
||||||
|
f2n = f2/lim2;
|
||||||
|
|
||||||
|
// load deformed coordinates
|
||||||
|
if (!linear_deform_model) {
|
||||||
|
f0s = f0 - c.texD0x(f0n, f1n, f2n);
|
||||||
|
f1s = f1 - c.texD0y(f0n, f1n, f2n);
|
||||||
|
f2s = f2 - c.texD0z(f0n, f1n, f2n);
|
||||||
|
} else {
|
||||||
|
f0s = f0 - (c.texD0x(f0n, f1n, f2n) * (1-angle_ratio) + (angle_ratio)*c.texD1x(f0n, f1n, f2n));
|
||||||
|
f1s = f1 - (c.texD0y(f0n, f1n, f2n) * (1-angle_ratio) + (angle_ratio)*c.texD1y(f0n, f1n, f2n));
|
||||||
|
f2s = f2 - (c.texD0z(f0n, f1n, f2n) * (1-angle_ratio) + (angle_ratio)*c.texD1z(f0n, f1n, f2n));
|
||||||
|
}
|
||||||
|
// get trilinear interpolation in the shifted coordinates
|
||||||
|
fVal += c.tex(f0s, f1s, f2s);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
is_inside = (f0 > 0 && f1 > 0 && f2 > 0 && f0 < lim0 && f1 < lim1 && f2 < lim2 );
|
||||||
|
// fVal += (is_inside ? c.tex(f0, f1, f2) : 0); // skip textures on boundaries
|
||||||
|
//fVal += c.tex(f0, f1, f2) == 0;
|
||||||
|
//fVal += is_inside == 0;
|
||||||
|
|
||||||
|
fVal += c.tex(f0, f1, f2); // fastest seems to be let texture memory to handle boundaries
|
||||||
|
}
|
||||||
|
|
||||||
|
// move to the next pixel
|
||||||
|
f0 += 1.0f;
|
||||||
|
f1 += a1;
|
||||||
|
f2 += a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fVal *= fDistCorr;
|
||||||
|
|
||||||
|
// !! 10% of the execution time
|
||||||
|
//D_projData[(detectorV*dims.iProjAngles + angle)*projPitch + detectorU] += fVal;
|
||||||
|
atomicAdd(&D_projData[(detectorV*dims.iProjAngles + angle)*projPitch + detectorU], fVal);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supersampling version
|
||||||
|
template<class COORD>
|
||||||
|
__global__ void par3D_FP_SS_t(float* D_projData, unsigned int projPitch,
|
||||||
|
unsigned int startSlice,
|
||||||
|
unsigned int startAngle, unsigned int endAngle,
|
||||||
|
const SDimensions3D dims, float fOutputScale)
|
||||||
|
{
|
||||||
|
COORD c;
|
||||||
|
|
||||||
|
int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y;
|
||||||
|
if (angle >= endAngle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float fRayX = gC_RayX[angle];
|
||||||
|
const float fRayY = gC_RayY[angle];
|
||||||
|
const float fRayZ = gC_RayZ[angle];
|
||||||
|
const float fDetUX = gC_DetUX[angle];
|
||||||
|
const float fDetUY = gC_DetUY[angle];
|
||||||
|
const float fDetUZ = gC_DetUZ[angle];
|
||||||
|
const float fDetVX = gC_DetVX[angle];
|
||||||
|
const float fDetVY = gC_DetVY[angle];
|
||||||
|
const float fDetVZ = gC_DetVZ[angle];
|
||||||
|
const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX;
|
||||||
|
const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY;
|
||||||
|
const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x;
|
||||||
|
const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV;
|
||||||
|
int endDetectorV = startDetectorV + g_detBlockV;
|
||||||
|
if (endDetectorV > dims.iProjV)
|
||||||
|
endDetectorV = dims.iProjV;
|
||||||
|
|
||||||
|
int endSlice = startSlice + g_blockSlices;
|
||||||
|
if (endSlice > c.nSlices(dims))
|
||||||
|
endSlice = c.nSlices(dims);
|
||||||
|
|
||||||
|
const float fSubStep = 1.0f/dims.iRaysPerDetDim;
|
||||||
|
|
||||||
|
for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV)
|
||||||
|
{
|
||||||
|
|
||||||
|
float fV = 0.0f;
|
||||||
|
|
||||||
|
float fdU = detectorU - 0.5f + 0.5f*fSubStep;
|
||||||
|
for (int iSubU = 0; iSubU < dims.iRaysPerDetDim; ++iSubU, fdU+=fSubStep) {
|
||||||
|
float fdV = detectorV - 0.5f + 0.5f*fSubStep;
|
||||||
|
for (int iSubV = 0; iSubV < dims.iRaysPerDetDim; ++iSubV, fdV+=fSubStep) {
|
||||||
|
|
||||||
|
/* Trace ray in direction Ray to (detectorU,detectorV) from */
|
||||||
|
/* X = startSlice to X = endSlice */
|
||||||
|
|
||||||
|
const float fDetX = fDetSX + fdU*fDetUX + fdV*fDetVX;
|
||||||
|
const float fDetY = fDetSY + fdU*fDetUY + fdV*fDetVY;
|
||||||
|
const float fDetZ = fDetSZ + fdU*fDetUZ + fdV*fDetVZ;
|
||||||
|
|
||||||
|
/* (x) ( 1) ( 0) */
|
||||||
|
/* ray: (y) = (ay) * x + (by) */
|
||||||
|
/* (z) (az) (bz) */
|
||||||
|
|
||||||
|
|
||||||
|
const float a1 = c.c1(fRayX,fRayY,fRayZ) / c.c0(fRayX,fRayY,fRayZ);
|
||||||
|
const float a2 = c.c2(fRayX,fRayY,fRayZ) / c.c0(fRayX,fRayY,fRayZ);
|
||||||
|
const float b1 = c.c1(fDetX,fDetY,fDetZ) - a1 * c.c0(fDetX,fDetY,fDetZ);
|
||||||
|
const float b2 = c.c2(fDetX,fDetY,fDetZ) - a2 * c.c0(fDetX,fDetY,fDetZ);
|
||||||
|
|
||||||
|
const float fDistCorr = sqrt(a1*a1+a2*a2+1.0f) * fOutputScale;
|
||||||
|
|
||||||
|
float fVal = 0.0f;
|
||||||
|
|
||||||
|
float f0 = startSlice + 0.5f;
|
||||||
|
float f1 = a1 * (startSlice - 0.5f*c.nSlices(dims) + 0.5f) + b1 + 0.5f*c.nDim1(dims) - 0.5f + 0.5f;
|
||||||
|
float f2 = a2 * (startSlice - 0.5f*c.nSlices(dims) + 0.5f) + b2 + 0.5f*c.nDim2(dims) - 0.5f + 0.5f;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (int s = startSlice; s < endSlice; ++s)
|
||||||
|
{
|
||||||
|
fVal += c.tex(f0, f1, f2);
|
||||||
|
f0 += 1.0f;
|
||||||
|
f1 += a1 ;
|
||||||
|
// f2 += a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fVal *= fDistCorr;
|
||||||
|
fV += fVal;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fV / (dims.iRaysPerDetDim * dims.iRaysPerDetDim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__device__ float dirWeights(float fX, float fN) {
|
||||||
|
if (fX <= -0.5f) // outside image on left
|
||||||
|
return 0.0f;
|
||||||
|
if (fX <= 0.5f) // half outside image on left
|
||||||
|
return (fX + 0.5f) * (fX + 0.5f);
|
||||||
|
if (fX <= fN - 0.5f) { // inside image
|
||||||
|
float t = fX + 0.5f - floorf(fX + 0.5f);
|
||||||
|
return 1; // t*t + (1 - t)*(1 - t);
|
||||||
|
}
|
||||||
|
if (fX <= fN + 0.5f) // half outside image on right
|
||||||
|
return (fN + 0.5f - fX) * (fN + 0.5f - fX);
|
||||||
|
return 0.0f; // outside image on right
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class COORD>
|
||||||
|
__global__ void par3D_FP_SumSqW_t(float* D_projData, unsigned int projPitch,
|
||||||
|
unsigned int startSlice,
|
||||||
|
unsigned int startAngle, unsigned int endAngle,
|
||||||
|
const SDimensions3D dims, float fOutputScale)
|
||||||
|
{
|
||||||
|
COORD c;
|
||||||
|
|
||||||
|
int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y;
|
||||||
|
if (angle >= endAngle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float fRayX = gC_RayX[angle];
|
||||||
|
const float fRayY = gC_RayY[angle];
|
||||||
|
const float fRayZ = gC_RayZ[angle];
|
||||||
|
const float fDetUX = gC_DetUX[angle];
|
||||||
|
const float fDetUY = gC_DetUY[angle];
|
||||||
|
const float fDetUZ = gC_DetUZ[angle];
|
||||||
|
const float fDetVX = gC_DetVX[angle];
|
||||||
|
const float fDetVY = gC_DetVY[angle];
|
||||||
|
const float fDetVZ = gC_DetVZ[angle];
|
||||||
|
const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX;
|
||||||
|
const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY;
|
||||||
|
const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x;
|
||||||
|
const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV;
|
||||||
|
int endDetectorV = startDetectorV + g_detBlockV;
|
||||||
|
if (endDetectorV > dims.iProjV)
|
||||||
|
endDetectorV = dims.iProjV;
|
||||||
|
|
||||||
|
int endSlice = startSlice + g_blockSlices;
|
||||||
|
if (endSlice > c.nSlices(dims))
|
||||||
|
endSlice = c.nSlices(dims);
|
||||||
|
|
||||||
|
for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV)
|
||||||
|
{
|
||||||
|
/* Trace ray in direction Ray to (detectorU,detectorV) from */
|
||||||
|
/* X = startSlice to X = endSlice */
|
||||||
|
|
||||||
|
const float fDetX = fDetSX + detectorU*fDetUX + detectorV*fDetVX;
|
||||||
|
const float fDetY = fDetSY + detectorU*fDetUY + detectorV*fDetVY;
|
||||||
|
const float fDetZ = fDetSZ + detectorU*fDetUZ + detectorV*fDetVZ;
|
||||||
|
|
||||||
|
/* (x) ( 1) ( 0) */
|
||||||
|
/* ray: (y) = (ay) * x + (by) */
|
||||||
|
/* (z) (az) (bz) */
|
||||||
|
|
||||||
|
const float a1 = c.c1(fRayX,fRayY,fRayZ) / c.c0(fRayX,fRayY,fRayZ);
|
||||||
|
const float a2 = c.c2(fRayX,fRayY,fRayZ) / c.c0(fRayX,fRayY,fRayZ);
|
||||||
|
const float b1 = c.c1(fDetX,fDetY,fDetZ) - a1 * c.c0(fDetX,fDetY,fDetZ);
|
||||||
|
const float b2 = c.c2(fDetX,fDetY,fDetZ) - a2 * c.c0(fDetX,fDetY,fDetZ);
|
||||||
|
|
||||||
|
const float fDistCorr = sqrt(a1*a1+a2*a2+1.0f) * fOutputScale;
|
||||||
|
|
||||||
|
float fVal = 0.0f;
|
||||||
|
|
||||||
|
float f0 = startSlice + 0.5f;
|
||||||
|
float f1 = a1 * (startSlice - 0.5f*c.nSlices(dims) + 0.5f) + b1 + 0.5f*c.nDim1(dims) - 0.5f + 0.5f;
|
||||||
|
float f2 = a2 * (startSlice - 0.5f*c.nSlices(dims) + 0.5f) + b2 + 0.5f*c.nDim2(dims) - 0.5f + 0.5f;
|
||||||
|
|
||||||
|
for (int s = startSlice; s < endSlice; ++s)
|
||||||
|
{
|
||||||
|
fVal += dirWeights(f1, c.nDim1(dims)) * dirWeights(f2, c.nDim2(dims)) * fDistCorr * fDistCorr;
|
||||||
|
f0 += 1.0f;
|
||||||
|
f1 += a1;
|
||||||
|
f2 += a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supersampling version
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
|
||||||
|
bool Par3DFP_Array_internal(cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, unsigned int angleCount, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale, const bool use_deform, const bool linear_deform_model)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// transfer angles to constant memory
|
||||||
|
float* tmp = new float[dims.iProjAngles];
|
||||||
|
|
||||||
|
#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < angleCount; ++i) tmp[i] = (float)angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, angleCount*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
|
||||||
|
|
||||||
|
TRANSFER_TO_CONSTANT(RayX);
|
||||||
|
TRANSFER_TO_CONSTANT(RayY);
|
||||||
|
TRANSFER_TO_CONSTANT(RayZ);
|
||||||
|
TRANSFER_TO_CONSTANT(DetSX);
|
||||||
|
TRANSFER_TO_CONSTANT(DetSY);
|
||||||
|
TRANSFER_TO_CONSTANT(DetSZ);
|
||||||
|
TRANSFER_TO_CONSTANT(DetUX);
|
||||||
|
TRANSFER_TO_CONSTANT(DetUY);
|
||||||
|
TRANSFER_TO_CONSTANT(DetUZ);
|
||||||
|
TRANSFER_TO_CONSTANT(DetVX);
|
||||||
|
TRANSFER_TO_CONSTANT(DetVY);
|
||||||
|
TRANSFER_TO_CONSTANT(DetVZ);
|
||||||
|
|
||||||
|
#undef TRANSFER_TO_CONSTANT
|
||||||
|
|
||||||
|
delete[] tmp;
|
||||||
|
|
||||||
|
std::list<cudaStream_t> streams;
|
||||||
|
dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles
|
||||||
|
|
||||||
|
// Run over all angles, grouping them into groups of the same
|
||||||
|
// orientation (roughly horizontal vs. roughly vertical).
|
||||||
|
// Start a stream of grids for each such group.
|
||||||
|
|
||||||
|
unsigned int blockStart = 0;
|
||||||
|
unsigned int blockEnd = 0;
|
||||||
|
int blockDirection = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned int a = 0; a <= angleCount; ++a) {
|
||||||
|
int dir = -1;
|
||||||
|
if (a != dims.iProjAngles) {
|
||||||
|
float dX = fabsf(angles[a].fRayX);
|
||||||
|
float dY = fabsf(angles[a].fRayY);
|
||||||
|
float dZ = fabsf(angles[a].fRayZ);
|
||||||
|
|
||||||
|
if (dX >= dY && dX >= dZ)
|
||||||
|
dir = 0;
|
||||||
|
else if (dY >= dX && dY >= dZ)
|
||||||
|
dir = 1;
|
||||||
|
else
|
||||||
|
dir = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == angleCount || dir != blockDirection) {
|
||||||
|
// block done
|
||||||
|
|
||||||
|
blockEnd = a;
|
||||||
|
if (blockStart != blockEnd) {
|
||||||
|
|
||||||
|
dim3 dimGrid(
|
||||||
|
((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV),
|
||||||
|
(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock);
|
||||||
|
// TODO: check if we can't immediately
|
||||||
|
// destroy the stream after use
|
||||||
|
|
||||||
|
|
||||||
|
cudaStream_t stream;
|
||||||
|
cudaStreamCreate(&stream);
|
||||||
|
streams.push_back(stream);
|
||||||
|
|
||||||
|
//mexPrintf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y);
|
||||||
|
//mexPrintf(" Nelements %i ", (dims.iProjU)*(dims.iProjV)*(dims.iProjAngles));
|
||||||
|
|
||||||
|
|
||||||
|
if (blockDirection == 0) {
|
||||||
|
for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices)
|
||||||
|
if (dims.iRaysPerDetDim == 1)
|
||||||
|
par3D_FP_t<DIR_X><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale, use_deform, linear_deform_model);
|
||||||
|
else
|
||||||
|
par3D_FP_SS_t<DIR_X><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
} else if (blockDirection == 1) {
|
||||||
|
for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices)
|
||||||
|
if (dims.iRaysPerDetDim == 1)
|
||||||
|
par3D_FP_t<DIR_Y><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale, use_deform, linear_deform_model);
|
||||||
|
else
|
||||||
|
par3D_FP_SS_t<DIR_Y><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
} else if (blockDirection == 2) {
|
||||||
|
for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices)
|
||||||
|
if (dims.iRaysPerDetDim == 1)
|
||||||
|
par3D_FP_t<DIR_Z><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale, use_deform, linear_deform_model);
|
||||||
|
else
|
||||||
|
par3D_FP_SS_t<DIR_Z><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
blockDirection = dir;
|
||||||
|
blockStart = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cudaThreadSynchronize();
|
||||||
|
|
||||||
|
for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter)
|
||||||
|
cudaStreamDestroy(*iter);
|
||||||
|
|
||||||
|
|
||||||
|
streams.clear();
|
||||||
|
|
||||||
|
cudaTextForceKernelsCompletion();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Par3DFP(cudaPitchedPtr D_volumeData,
|
||||||
|
cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale, DeformField DF)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
checkLastError("before allocateVolumeArray");
|
||||||
|
/*printFreeMemory();
|
||||||
|
mexPrintf("Allocate memory\n");*/
|
||||||
|
// transfer volume to array
|
||||||
|
|
||||||
|
|
||||||
|
if (dims.iVolX*dims.iVolY*dims.iVolZ * 4 > 1024e6)
|
||||||
|
{
|
||||||
|
mexPrintf("Volume exceeded maximal size of texture 1024MB \n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cudaArray* cuArray = allocateVolumeArray(dims);
|
||||||
|
//mexPrintf("Allocate memory done\n");
|
||||||
|
//printFreeMemory();
|
||||||
|
|
||||||
|
checkLastError("after allocateVolumeArray");
|
||||||
|
|
||||||
|
//mexPrintf("transferVolumeToArray\n");
|
||||||
|
|
||||||
|
transferVolumeToArray(D_volumeData, cuArray, dims);
|
||||||
|
|
||||||
|
|
||||||
|
checkLastError("after transferVolumeToArray\n \n ");
|
||||||
|
//printFreeMemory();
|
||||||
|
|
||||||
|
bindDataTexture(cuArray, gT_par3DVolumeTexture,cudaAddressModeBorder, false);
|
||||||
|
|
||||||
|
//mexPrintf("bindDataTexture done \n");
|
||||||
|
|
||||||
|
|
||||||
|
checkLastError("after bindDataTexture");
|
||||||
|
//printFreeMemory();
|
||||||
|
|
||||||
|
//mexPrintf("preoparation finieshe \n");
|
||||||
|
cudaArray * cuArrX0, *cuArrY0, *cuArrZ0, *cuArrX1, *cuArrY1, *cuArrZ1 ;
|
||||||
|
|
||||||
|
|
||||||
|
if (DF.use_deform) {
|
||||||
|
// mexPrintf("transferDeformationToArray\n");
|
||||||
|
|
||||||
|
cuArrX0 = transferDeformationToArray(DF.X0);
|
||||||
|
cuArrY0 = transferDeformationToArray(DF.Y0);
|
||||||
|
cuArrZ0 = transferDeformationToArray(DF.Z0);
|
||||||
|
bindDataTexture(cuArrX0, Xdef0_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrY0, Ydef0_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrZ0, Zdef0_tex,cudaAddressModeClamp, true);
|
||||||
|
if (DF.use_linear_model) {
|
||||||
|
cuArrX1 = transferDeformationToArray(DF.X1);
|
||||||
|
cuArrY1 = transferDeformationToArray(DF.Y1);
|
||||||
|
cuArrZ1 = transferDeformationToArray(DF.Z1);
|
||||||
|
bindDataTexture(cuArrX1, Xdef1_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrY1, Ydef1_tex,cudaAddressModeClamp, true);
|
||||||
|
bindDataTexture(cuArrZ1, Zdef1_tex,cudaAddressModeClamp, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
// ONLY A LIMITED RANGE OF ANGLES IS AVAILIBLE INSIDE !!!!!
|
||||||
|
checkLastError("before allocateVolumeArray");
|
||||||
|
|
||||||
|
|
||||||
|
// 97% of time spent in Par3DFP_Array_internal
|
||||||
|
ret = Par3DFP_Array_internal(D_projData,
|
||||||
|
dims, dims.iProjAngles, angles,
|
||||||
|
fOutputScale, DF.use_deform, DF.use_linear_model);
|
||||||
|
checkLastError("after allocateVolumeArray");
|
||||||
|
|
||||||
|
cudaFreeArray(cuArray);
|
||||||
|
checkLastError("after cudaFreeArray");
|
||||||
|
|
||||||
|
// THIS WAS BUG IN ASTRA !!!!
|
||||||
|
cudaUnbindTexture(gT_par3DVolumeTexture);
|
||||||
|
checkLastError("cudaUnbindTexture");
|
||||||
|
|
||||||
|
if (DF.use_deform) {
|
||||||
|
cudaFreeArray(cuArrX0);
|
||||||
|
cudaFreeArray(cuArrY0);
|
||||||
|
cudaFreeArray(cuArrZ0);
|
||||||
|
cudaUnbindTexture(Xdef0_tex);
|
||||||
|
cudaUnbindTexture(Ydef0_tex);
|
||||||
|
cudaUnbindTexture(Zdef0_tex);
|
||||||
|
if (DF.use_linear_model) {
|
||||||
|
cudaFreeArray(cuArrX1);
|
||||||
|
cudaFreeArray(cuArrY1);
|
||||||
|
cudaFreeArray(cuArrZ1);
|
||||||
|
cudaUnbindTexture(Xdef1_tex);
|
||||||
|
cudaUnbindTexture(Ydef1_tex);
|
||||||
|
cudaUnbindTexture(Zdef1_tex);
|
||||||
|
}
|
||||||
|
checkLastError("unbind deforms");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool Par3DFP_SumSqW(cudaPitchedPtr D_volumeData,
|
||||||
|
cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale)
|
||||||
|
{
|
||||||
|
// transfer angles to constant memory
|
||||||
|
float* tmp = new float[dims.iProjAngles];
|
||||||
|
|
||||||
|
#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
|
||||||
|
|
||||||
|
TRANSFER_TO_CONSTANT(RayX);
|
||||||
|
TRANSFER_TO_CONSTANT(RayY);
|
||||||
|
TRANSFER_TO_CONSTANT(RayZ);
|
||||||
|
TRANSFER_TO_CONSTANT(DetSX);
|
||||||
|
TRANSFER_TO_CONSTANT(DetSY);
|
||||||
|
TRANSFER_TO_CONSTANT(DetSZ);
|
||||||
|
TRANSFER_TO_CONSTANT(DetUX);
|
||||||
|
TRANSFER_TO_CONSTANT(DetUY);
|
||||||
|
TRANSFER_TO_CONSTANT(DetUZ);
|
||||||
|
TRANSFER_TO_CONSTANT(DetVX);
|
||||||
|
TRANSFER_TO_CONSTANT(DetVY);
|
||||||
|
TRANSFER_TO_CONSTANT(DetVZ);
|
||||||
|
|
||||||
|
#undef TRANSFER_TO_CONSTANT
|
||||||
|
|
||||||
|
delete[] tmp;
|
||||||
|
|
||||||
|
std::list<cudaStream_t> streams;
|
||||||
|
dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles
|
||||||
|
|
||||||
|
// Run over all angles, grouping them into groups of the same
|
||||||
|
// orientation (roughly horizontal vs. roughly vertical).
|
||||||
|
// Start a stream of grids for each such group.
|
||||||
|
|
||||||
|
unsigned int blockStart = 0;
|
||||||
|
unsigned int blockEnd = 0;
|
||||||
|
int blockDirection = 0;
|
||||||
|
|
||||||
|
// timeval t;
|
||||||
|
// tic(t);
|
||||||
|
|
||||||
|
for (unsigned int a = 0; a <= dims.iProjAngles; ++a) {
|
||||||
|
int dir;
|
||||||
|
if (a != dims.iProjAngles) {
|
||||||
|
float dX = fabsf(angles[a].fRayX);
|
||||||
|
float dY = fabsf(angles[a].fRayY);
|
||||||
|
float dZ = fabsf(angles[a].fRayZ);
|
||||||
|
|
||||||
|
if (dX >= dY && dX >= dZ)
|
||||||
|
dir = 0;
|
||||||
|
else if (dY >= dX && dY >= dZ)
|
||||||
|
dir = 1;
|
||||||
|
else
|
||||||
|
dir = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == dims.iProjAngles || dir != blockDirection) {
|
||||||
|
// block done
|
||||||
|
|
||||||
|
blockEnd = a;
|
||||||
|
if (blockStart != blockEnd) {
|
||||||
|
|
||||||
|
dim3 dimGrid(
|
||||||
|
((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV),
|
||||||
|
(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock);
|
||||||
|
// TODO: check if we can't immediately
|
||||||
|
// destroy the stream after use
|
||||||
|
cudaStream_t stream;
|
||||||
|
cudaStreamCreate(&stream);
|
||||||
|
streams.push_back(stream);
|
||||||
|
|
||||||
|
//printf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y);
|
||||||
|
|
||||||
|
if (blockDirection == 0) {
|
||||||
|
for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices)
|
||||||
|
if (dims.iRaysPerDetDim == 1)
|
||||||
|
par3D_FP_SumSqW_t<DIR_X><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
else
|
||||||
|
#if 0
|
||||||
|
par3D_FP_SS_SumSqW_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
#else
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
} else if (blockDirection == 1) {
|
||||||
|
for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices)
|
||||||
|
if (dims.iRaysPerDetDim == 1)
|
||||||
|
par3D_FP_SumSqW_t<DIR_Y><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
else
|
||||||
|
#if 0
|
||||||
|
par3D_FP_SS_SumSqW_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
#else
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
} else if (blockDirection == 2) {
|
||||||
|
for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices)
|
||||||
|
if (dims.iRaysPerDetDim == 1)
|
||||||
|
par3D_FP_SumSqW_t<DIR_Z><<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
else
|
||||||
|
#if 0
|
||||||
|
par3D_FP_SS_SumSqW_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
|
||||||
|
#else
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
blockDirection = dir;
|
||||||
|
blockStart = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter)
|
||||||
|
cudaStreamDestroy(*iter);
|
||||||
|
|
||||||
|
streams.clear();
|
||||||
|
|
||||||
|
cudaTextForceKernelsCompletion();
|
||||||
|
|
||||||
|
|
||||||
|
// printf("%f\n", toc(t));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CUDA_PAR3D_FP_H
|
||||||
|
#define _CUDA_PAR3D_FP_H
|
||||||
|
|
||||||
|
namespace astraCUDA3d {
|
||||||
|
|
||||||
|
_AstraExport bool Par3DFP_Array(cudaArray *D_volArray,
|
||||||
|
cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale);
|
||||||
|
|
||||||
|
_AstraExport bool Par3DFP(cudaPitchedPtr D_volumeData,
|
||||||
|
cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale, DeformField DF);
|
||||||
|
|
||||||
|
_AstraExport bool Par3DFP_SumSqW(cudaPitchedPtr D_volumeData,
|
||||||
|
cudaPitchedPtr D_projData,
|
||||||
|
const SDimensions3D& dims, const SPar3DProjection* angles,
|
||||||
|
float fOutputScale);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// stdafx.cpp : source file that includes just the standard includes
|
||||||
|
// ConsoleApplication2.pch will be the pre-compiled header
|
||||||
|
// stdafx.obj will contain the pre-compiled type information
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
// TODO: reference any additional headers you need in STDAFX.H
|
||||||
|
// and not in this file
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// stdafx.h : include file for standard system include files,
|
||||||
|
// or project specific include files that are used frequently, but
|
||||||
|
// are changed infrequently
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "targetver.h"
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
// Windows Header Files:
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: reference additional headers your program requires here
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||||
|
|
||||||
|
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||||
|
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||||
|
|
||||||
|
#include <SDKDDKVer.h>
|
||||||
@@ -0,0 +1,688 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include "util3d.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include <cuda.h>
|
||||||
|
#include "cuda_runtime.h"
|
||||||
|
#include "device_launch_parameters.h"
|
||||||
|
|
||||||
|
//#include "../2d/util.h"
|
||||||
|
|
||||||
|
#include "astra/Logging.h"
|
||||||
|
#include "mex.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace astraCUDA3d {
|
||||||
|
|
||||||
|
|
||||||
|
cudaPitchedPtr allocateVolumeData(const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaExtent extentV;
|
||||||
|
extentV.width = dims.iVolX*sizeof(float);
|
||||||
|
extentV.height = dims.iVolY;
|
||||||
|
extentV.depth = dims.iVolZ;
|
||||||
|
|
||||||
|
cudaPitchedPtr volData;
|
||||||
|
|
||||||
|
cudaError err = cudaMalloc3D(&volData, extentV);
|
||||||
|
if (err != cudaSuccess) {
|
||||||
|
astraCUDA3d::reportCudaError(err);
|
||||||
|
ASTRA_ERROR("Failed to allocate %dx%dx%d GPU buffer", dims.iVolX, dims.iVolY, dims.iVolZ);
|
||||||
|
volData.ptr = 0;
|
||||||
|
// TODO: return 0 somehow?
|
||||||
|
}
|
||||||
|
|
||||||
|
return volData;
|
||||||
|
}
|
||||||
|
cudaPitchedPtr allocateProjectionData(const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaExtent extentP;
|
||||||
|
extentP.width = dims.iProjU*sizeof(float);
|
||||||
|
extentP.height = dims.iProjAngles;
|
||||||
|
extentP.depth = dims.iProjV;
|
||||||
|
|
||||||
|
cudaPitchedPtr projData;
|
||||||
|
|
||||||
|
cudaError err = cudaMalloc3D(&projData, extentP);
|
||||||
|
if (err != cudaSuccess) {
|
||||||
|
mexPrintf("Failed to allocate %dx%dx%d GPU buffer", dims.iProjU, dims.iProjAngles, dims.iProjV);
|
||||||
|
projData.ptr = 0;
|
||||||
|
// TODO: return 0 somehow?
|
||||||
|
}
|
||||||
|
|
||||||
|
return projData;
|
||||||
|
}
|
||||||
|
bool zeroVolumeData(cudaPitchedPtr& D_data, const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
char* t = (char*)D_data.ptr;
|
||||||
|
cudaError err;
|
||||||
|
|
||||||
|
for (unsigned int z = 0; z < dims.iVolZ; ++z) {
|
||||||
|
err = cudaMemset2D(t, D_data.pitch, 0, dims.iVolX*sizeof(float), dims.iVolY);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
t += D_data.pitch * dims.iVolY;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool zeroProjectionData(cudaPitchedPtr& D_data, const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
char* t = (char*)D_data.ptr;
|
||||||
|
cudaError err;
|
||||||
|
|
||||||
|
for (unsigned int z = 0; z < dims.iProjV; ++z) {
|
||||||
|
err = cudaMemset2D(t, D_data.pitch, 0, dims.iProjU*sizeof(float), dims.iProjAngles);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
t += D_data.pitch * dims.iProjAngles;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool copyVolumeToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
|
||||||
|
{
|
||||||
|
if (!pitch)
|
||||||
|
pitch = dims.iVolX;
|
||||||
|
|
||||||
|
cudaPitchedPtr ptr;
|
||||||
|
ptr.ptr = (void*)data; // const cast away
|
||||||
|
ptr.pitch = pitch*sizeof(float);
|
||||||
|
ptr.xsize = dims.iVolX*sizeof(float);
|
||||||
|
ptr.ysize = dims.iVolY;
|
||||||
|
|
||||||
|
cudaExtent extentV;
|
||||||
|
extentV.width = dims.iVolX*sizeof(float);
|
||||||
|
extentV.height = dims.iVolY;
|
||||||
|
extentV.depth = dims.iVolZ;
|
||||||
|
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = ptr;
|
||||||
|
p.dstArray = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.dstPtr = D_data;
|
||||||
|
p.extent = extentV;
|
||||||
|
p.kind = cudaMemcpyHostToDevice;
|
||||||
|
|
||||||
|
cudaError err;
|
||||||
|
err = cudaMemcpy3D(&p);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
return err == cudaSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copyProjectionsToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
|
||||||
|
{
|
||||||
|
if (!pitch)
|
||||||
|
pitch = dims.iProjU;
|
||||||
|
|
||||||
|
cudaPitchedPtr ptr;
|
||||||
|
ptr.ptr = (void*)data; // const cast away
|
||||||
|
ptr.pitch = pitch*sizeof(float);
|
||||||
|
ptr.xsize = dims.iProjU*sizeof(float);
|
||||||
|
ptr.ysize = dims.iProjAngles;
|
||||||
|
|
||||||
|
cudaExtent extentV;
|
||||||
|
extentV.width = dims.iProjU*sizeof(float);
|
||||||
|
extentV.height = dims.iProjAngles;
|
||||||
|
extentV.depth = dims.iProjV;
|
||||||
|
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = ptr;
|
||||||
|
p.dstArray = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.dstPtr = D_data;
|
||||||
|
p.extent = extentV;
|
||||||
|
p.kind = cudaMemcpyHostToDevice;
|
||||||
|
|
||||||
|
cudaError err;
|
||||||
|
err = cudaMemcpy3D(&p);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
return err == cudaSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copyVolumeFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
|
||||||
|
{
|
||||||
|
if (!pitch)
|
||||||
|
pitch = dims.iVolX;
|
||||||
|
|
||||||
|
cudaPitchedPtr ptr;
|
||||||
|
ptr.ptr = data;
|
||||||
|
ptr.pitch = pitch*sizeof(float);
|
||||||
|
ptr.xsize = dims.iVolX*sizeof(float);
|
||||||
|
ptr.ysize = dims.iVolY;
|
||||||
|
|
||||||
|
cudaExtent extentV;
|
||||||
|
extentV.width = dims.iVolX*sizeof(float);
|
||||||
|
extentV.height = dims.iVolY;
|
||||||
|
extentV.depth = dims.iVolZ;
|
||||||
|
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = D_data;
|
||||||
|
p.dstArray = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.dstPtr = ptr;
|
||||||
|
p.extent = extentV;
|
||||||
|
p.kind = cudaMemcpyDeviceToHost;
|
||||||
|
|
||||||
|
cudaError err;
|
||||||
|
err = cudaMemcpy3D(&p);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
return err == cudaSuccess;
|
||||||
|
}
|
||||||
|
bool copyProjectionsFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
|
||||||
|
{
|
||||||
|
if (!pitch)
|
||||||
|
pitch = dims.iProjU;
|
||||||
|
|
||||||
|
cudaPitchedPtr ptr;
|
||||||
|
ptr.ptr = data;
|
||||||
|
ptr.pitch = pitch*sizeof(float);
|
||||||
|
ptr.xsize = dims.iProjU*sizeof(float);
|
||||||
|
ptr.ysize = dims.iProjAngles;
|
||||||
|
|
||||||
|
cudaExtent extentV;
|
||||||
|
extentV.width = dims.iProjU*sizeof(float);
|
||||||
|
extentV.height = dims.iProjAngles;
|
||||||
|
extentV.depth = dims.iProjV;
|
||||||
|
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = D_data;
|
||||||
|
p.dstArray = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.dstPtr = ptr;
|
||||||
|
p.extent = extentV;
|
||||||
|
p.kind = cudaMemcpyDeviceToHost;
|
||||||
|
|
||||||
|
cudaError err;
|
||||||
|
err = cudaMemcpy3D(&p);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
return err == cudaSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool duplicateVolumeData(cudaPitchedPtr& D_dst, const cudaPitchedPtr& D_src, const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaExtent extentV;
|
||||||
|
extentV.width = dims.iVolX*sizeof(float);
|
||||||
|
extentV.height = dims.iVolY;
|
||||||
|
extentV.depth = dims.iVolZ;
|
||||||
|
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = D_src;
|
||||||
|
p.dstArray = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.dstPtr = D_dst;
|
||||||
|
p.extent = extentV;
|
||||||
|
p.kind = cudaMemcpyDeviceToDevice;
|
||||||
|
|
||||||
|
cudaError err;
|
||||||
|
err = cudaMemcpy3D(&p);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
return err == cudaSuccess;
|
||||||
|
}
|
||||||
|
bool duplicateProjectionData(cudaPitchedPtr& D_dst, const cudaPitchedPtr& D_src, const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaExtent extentV;
|
||||||
|
extentV.width = dims.iProjU*sizeof(float);
|
||||||
|
extentV.height = dims.iProjAngles;
|
||||||
|
extentV.depth = dims.iProjV;
|
||||||
|
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = D_src;
|
||||||
|
p.dstArray = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.dstPtr = D_dst;
|
||||||
|
p.extent = extentV;
|
||||||
|
p.kind = cudaMemcpyDeviceToDevice;
|
||||||
|
|
||||||
|
cudaError err;
|
||||||
|
err = cudaMemcpy3D(&p);
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
return err == cudaSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Consider using a single array of size max(proj,volume) (per dim)
|
||||||
|
// instead of allocating a new one each time
|
||||||
|
|
||||||
|
cudaArray* allocateVolumeArray(const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
|
||||||
|
cudaArray* cuArray;
|
||||||
|
cudaExtent extentA;
|
||||||
|
extentA.width = dims.iVolX;
|
||||||
|
extentA.height = dims.iVolY;
|
||||||
|
extentA.depth = dims.iVolZ;
|
||||||
|
cudaError err = cudaMalloc3DArray(&cuArray, &channelDesc, extentA);
|
||||||
|
if (err != cudaSuccess) {
|
||||||
|
mexPrintf("Failed to allocate %dx%dx%d GPU array", dims.iVolX, dims.iVolY, dims.iVolZ);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cuArray;
|
||||||
|
}
|
||||||
|
cudaArray* allocateProjectionArray(const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
|
||||||
|
cudaArray* cuArray;
|
||||||
|
cudaExtent extentA;
|
||||||
|
extentA.width = dims.iProjU;
|
||||||
|
extentA.height = dims.iProjAngles;
|
||||||
|
extentA.depth = dims.iProjV;
|
||||||
|
cudaError err = cudaMalloc3DArray(&cuArray, &channelDesc, extentA);
|
||||||
|
|
||||||
|
if (err != cudaSuccess) {
|
||||||
|
mexPrintf("Failed to allocate %dx%dx%d GPU array", dims.iProjU, dims.iProjAngles, dims.iProjV);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cuArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bindDataTexture(const cudaArray* array, texture3D & Texture, cudaTextureAddressMode bordermode, bool normalized)
|
||||||
|
{
|
||||||
|
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
|
||||||
|
Texture.addressMode[0] = bordermode;
|
||||||
|
Texture.addressMode[1] = bordermode;
|
||||||
|
Texture.addressMode[2] = bordermode;
|
||||||
|
Texture.filterMode = cudaFilterModeLinear;
|
||||||
|
Texture.normalized = normalized;
|
||||||
|
|
||||||
|
cudaError err = cudaBindTextureToArray(Texture, array, channelDesc);
|
||||||
|
|
||||||
|
checkLastError("cudaBindTextureToArray cudaMemcpy3D");
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
//mexPrintf("Max texture size !!! %i %i %i", cudaDeviceProp.maxTexture3D[0], cudaDeviceProp.maxTexture3D[1], cudaDeviceProp.maxTexture3D[2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cudaArray * transferDeformationToArray(const mxGPUArray * m_img)
|
||||||
|
{
|
||||||
|
mwSize const * dimensions = mxGPUGetDimensions(m_img);
|
||||||
|
mwSize Ndim = mxGPUGetNumberOfDimensions(m_img);
|
||||||
|
int M = (int)dimensions[0];
|
||||||
|
int N = (int)dimensions[1];
|
||||||
|
int O = Ndim > 2 ? (int)dimensions[2] : 1;
|
||||||
|
|
||||||
|
SDimensions3D dims;
|
||||||
|
dims.iVolX = M;
|
||||||
|
dims.iVolY = N;
|
||||||
|
dims.iVolZ = O;
|
||||||
|
|
||||||
|
//mexPrintf("Deformation field size: %i %i %i \n", M,N,O);
|
||||||
|
|
||||||
|
|
||||||
|
cudaArray* array = allocateVolumeArray(dims);
|
||||||
|
|
||||||
|
// get the values into float array
|
||||||
|
const float * img =(const float *)mxGPUGetDataReadOnly(m_img);
|
||||||
|
|
||||||
|
if (array == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (M * sizeof(float) > 2048) {
|
||||||
|
mexPrintf("Volume is too large to be transfered to GPU array");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make volume array (no copying)
|
||||||
|
cudaPitchedPtr volume;
|
||||||
|
volume.ptr = (float *)img;
|
||||||
|
volume.pitch = M * sizeof(float);
|
||||||
|
volume.xsize = M;
|
||||||
|
volume.ysize = N;
|
||||||
|
|
||||||
|
|
||||||
|
transferVolumeToArray(volume, array,dims);
|
||||||
|
|
||||||
|
// if (!checkLastError("transferDeformToArray cudaMemcpy3D"))
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool transferVolumeToArray(cudaPitchedPtr D_volumeData, cudaArray* array, const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaExtent extentA;
|
||||||
|
extentA.width = dims.iVolX;
|
||||||
|
extentA.height = dims.iVolY;
|
||||||
|
extentA.depth = dims.iVolZ;
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = D_volumeData;
|
||||||
|
p.dstArray = array;
|
||||||
|
p.dstPtr.ptr = 0;
|
||||||
|
p.dstPtr.pitch = 0;
|
||||||
|
p.dstPtr.xsize = 0;
|
||||||
|
p.dstPtr.ysize = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.extent = extentA;
|
||||||
|
p.kind = cudaMemcpyDeviceToDevice;
|
||||||
|
|
||||||
|
cudaError err = cudaMemcpy3D(&p);
|
||||||
|
|
||||||
|
checkLastError("transferVolumeToArray cudaMemcpy3D");
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
// TODO: check errors
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool transferProjectionsToArray(cudaPitchedPtr D_projData, cudaArray* array, const SDimensions3D& dims)
|
||||||
|
{
|
||||||
|
cudaExtent extentA;
|
||||||
|
extentA.width = dims.iProjU;
|
||||||
|
extentA.height = dims.iProjAngles;
|
||||||
|
extentA.depth = dims.iProjV;
|
||||||
|
|
||||||
|
cudaMemcpy3DParms p;
|
||||||
|
cudaPos zp = { 0, 0, 0 };
|
||||||
|
p.srcArray = 0;
|
||||||
|
p.srcPos = zp;
|
||||||
|
p.srcPtr = D_projData;
|
||||||
|
p.dstArray = array;
|
||||||
|
p.dstPtr.ptr = 0;
|
||||||
|
p.dstPtr.pitch = 0;
|
||||||
|
p.dstPtr.xsize = 0;
|
||||||
|
p.dstPtr.ysize = 0;
|
||||||
|
p.dstPos = zp;
|
||||||
|
p.extent = extentA;
|
||||||
|
p.kind = cudaMemcpyDeviceToDevice;
|
||||||
|
|
||||||
|
cudaError err = cudaMemcpy3D(&p);
|
||||||
|
checkLastError("transferProjectionsToArray cudaMemcpy3D");
|
||||||
|
|
||||||
|
ASTRA_CUDA_ASSERT(err);
|
||||||
|
|
||||||
|
// TODO: check errors
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool cudaTextForceKernelsCompletion()
|
||||||
|
{
|
||||||
|
cudaError_t returnedCudaError = cudaThreadSynchronize();
|
||||||
|
|
||||||
|
if (returnedCudaError != cudaSuccess) {
|
||||||
|
//FIXME
|
||||||
|
fprintf(stderr, "Failed to force completion of cuda kernels: %d: %s. \n ", returnedCudaError, cudaGetErrorString(returnedCudaError));
|
||||||
|
ASTRA_ERROR("Failed to force completion of cuda kernels: %d: %s.\n ", returnedCudaError, cudaGetErrorString(returnedCudaError));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reportCudaError(cudaError_t err)
|
||||||
|
{
|
||||||
|
if (err != cudaSuccess) {
|
||||||
|
mexPrintf("CUDA error %d: %s.", err, cudaGetErrorString(err));
|
||||||
|
mexErrMsgTxt("ASTRA failed, reboot GPU");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//float dotproduct3d(cudapitchedptr data, unsigned int x, unsigned int y,
|
||||||
|
// unsigned int z)
|
||||||
|
//{
|
||||||
|
// return astraCUDA3d::dotproduct2d((float*)data.ptr, data.pitch/sizeof(float), x, y*z);
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int calcNextPowerOfTwo(int _iValue)
|
||||||
|
{
|
||||||
|
int iOutput = 1;
|
||||||
|
while (iOutput < _iValue)
|
||||||
|
iOutput *= 2;
|
||||||
|
return iOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
double tic()
|
||||||
|
{
|
||||||
|
return clock();
|
||||||
|
}
|
||||||
|
|
||||||
|
double toc(double tstart)
|
||||||
|
{
|
||||||
|
return (clock() - tstart) / CLOCKS_PER_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void printFreeMemory()
|
||||||
|
{
|
||||||
|
// show memory usage of GPU
|
||||||
|
size_t free_byte;
|
||||||
|
size_t total_byte;
|
||||||
|
cudaError_t cuda_status = cudaMemGetInfo(&free_byte, &total_byte);
|
||||||
|
|
||||||
|
if (cudaSuccess != cuda_status){
|
||||||
|
mexPrintf("Error: cudaMemGetInfo fails, %s \n", cudaGetErrorString(cuda_status));
|
||||||
|
}
|
||||||
|
double free_db = (double)free_byte;
|
||||||
|
double total_db = (double)total_byte;
|
||||||
|
double used_db = total_db - free_db;
|
||||||
|
mexPrintf("GPU memory usage: used = %g, free = %g MB, total = %g MB\n",
|
||||||
|
used_db / 1024.0 / 1024.0, free_db / 1024.0 / 1024.0, total_db / 1024.0 / 1024.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int checkLastError(char * msg)
|
||||||
|
{
|
||||||
|
cudaError_t cudaStatus = cudaGetLastError();
|
||||||
|
if (cudaStatus != cudaSuccess) {
|
||||||
|
char err[512];
|
||||||
|
sprintf(err, "astraCUDA3d failed %s: %s. \n", msg, cudaGetErrorString(cudaStatus));
|
||||||
|
mexErrMsgTxt(err);
|
||||||
|
//mexPrintf(err);
|
||||||
|
//mexPrintf("assert \n");
|
||||||
|
//ASTRA_CUDA_ASSERT(cudaStatus);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dumpArray(char* filename, int width, int height, float *buffer)
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
int i, j;
|
||||||
|
f = fopen(filename, "w");
|
||||||
|
for (i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < width; j++)
|
||||||
|
{
|
||||||
|
fprintf(f, "%3.2g\t", buffer[i*width + j]);
|
||||||
|
// fprintf(f, "%i %i\t", i, j);
|
||||||
|
|
||||||
|
//fprintf(f, "%3.2g\t", 1);
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dumpCudaArray(cudaPitchedPtr Data, int start, int end, char * filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
char fname[32], msg[32];
|
||||||
|
int width = Data.xsize / sizeof(float);
|
||||||
|
int height = Data.ysize;
|
||||||
|
int slice_size = width*height*sizeof(float);
|
||||||
|
float* buffer = new float[width*height];
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
cudaMemcpy(buffer, ((float*)Data.ptr) + slice_size*i, slice_size, cudaMemcpyDeviceToHost);
|
||||||
|
sprintf(fname, filename, i);
|
||||||
|
sprintf(msg, filename, i);
|
||||||
|
fprintf(stdout, "%s\n", msg);
|
||||||
|
dumpArray(fname, width, height, buffer);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int writeImageCudaArray(cudaPitchedPtr Data, int start, int end, char * filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
char fname[32];
|
||||||
|
int width = Data.xsize / sizeof(float);
|
||||||
|
int height = Data.ysize;
|
||||||
|
int slice_size = width*height*sizeof(float);
|
||||||
|
float* buffer = new float[width*height];
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
cudaMemcpy(buffer, ((float*)Data.ptr) + slice_size*i, slice_size, cudaMemcpyDeviceToHost);
|
||||||
|
sprintf(fname, filename, i);
|
||||||
|
writeImage(fname, width, height, buffer);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int writeImage(char * fname, int w, int h, float * data)
|
||||||
|
{
|
||||||
|
// normalize image
|
||||||
|
float max = 0;
|
||||||
|
for (int i = 0; i < w*h; i++)
|
||||||
|
if (data[i] > max)
|
||||||
|
max = data[i];
|
||||||
|
|
||||||
|
float **x;
|
||||||
|
/* allocate the array */
|
||||||
|
x = (float **)malloc(h * sizeof *x);
|
||||||
|
for (int i = 0; i<h; i++)
|
||||||
|
x[i] = (float *)malloc(w * sizeof *x[i]);
|
||||||
|
for (int i = 0; i<h; i++)
|
||||||
|
for (int j = 0; j < w; j++)
|
||||||
|
x[i][j] = data[i*w + j] / max; // fill the array
|
||||||
|
|
||||||
|
writeBMPImage(fname, w,h, x,x,x);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int writeBMPImage(char * fname, int w, int h, float ** red, float ** green, float ** blue)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
unsigned char *img = NULL;
|
||||||
|
int filesize = 54 + 3 * w*h; //w is your image width, h is image height, both int
|
||||||
|
if (img)
|
||||||
|
free(img);
|
||||||
|
img = (unsigned char *)malloc(3 * w*h);
|
||||||
|
memset(img, 0, sizeof(img));
|
||||||
|
|
||||||
|
float r, g, b;
|
||||||
|
int x, y;
|
||||||
|
for (int i = 0; i<w; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j<h; j++)
|
||||||
|
{
|
||||||
|
x = i; y = (h - 1) - j;
|
||||||
|
r = red[i][j] * 255;
|
||||||
|
g = green[i][j] * 255;
|
||||||
|
b = blue[i][j] * 255;
|
||||||
|
if (r > 255) r = 255;
|
||||||
|
if (g > 255) g = 255;
|
||||||
|
if (b > 255) b = 255;
|
||||||
|
img[(x + y*w) * 3 + 2] = (unsigned char)(r);
|
||||||
|
img[(x + y*w) * 3 + 1] = (unsigned char)(g);
|
||||||
|
img[(x + y*w) * 3 + 0] = (unsigned char)(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char bmpfileheader[14] = { 'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0 };
|
||||||
|
unsigned char bmpinfoheader[40] = { 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0 };
|
||||||
|
unsigned char bmppad[3] = { 0, 0, 0 };
|
||||||
|
|
||||||
|
bmpfileheader[2] = (unsigned char)(filesize);
|
||||||
|
bmpfileheader[3] = (unsigned char)(filesize >> 8);
|
||||||
|
bmpfileheader[4] = (unsigned char)(filesize >> 16);
|
||||||
|
bmpfileheader[5] = (unsigned char)(filesize >> 24);
|
||||||
|
|
||||||
|
bmpinfoheader[4] = (unsigned char)(w);
|
||||||
|
bmpinfoheader[5] = (unsigned char)(w >> 8);
|
||||||
|
bmpinfoheader[6] = (unsigned char)(w >> 16);
|
||||||
|
bmpinfoheader[7] = (unsigned char)(w >> 24);
|
||||||
|
bmpinfoheader[8] = (unsigned char)(h);
|
||||||
|
bmpinfoheader[9] = (unsigned char)(h >> 8);
|
||||||
|
bmpinfoheader[10] = (unsigned char)(h >> 16);
|
||||||
|
bmpinfoheader[11] = (unsigned char)(h >> 24);
|
||||||
|
|
||||||
|
f = fopen(fname, "wb");
|
||||||
|
fwrite(bmpfileheader, 1, 14, f);
|
||||||
|
fwrite(bmpinfoheader, 1, 40, f);
|
||||||
|
for (int i = 0; i < h; i++)
|
||||||
|
{
|
||||||
|
fwrite(img + (w*(h - i - 1) * 3), 3, w, f);
|
||||||
|
fwrite(bmppad, 1, (4 - (w * 3) % 4) % 4, f);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
|
||||||
|
fprintf(stdout, "Saved image %s\n", fname);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||||
|
2014-2015, CWI, Amsterdam
|
||||||
|
|
||||||
|
Contact: astra@uantwerpen.be
|
||||||
|
Website: http://sf.net/projects/astra-toolbox
|
||||||
|
|
||||||
|
This file is part of the ASTRA Toolbox.
|
||||||
|
|
||||||
|
|
||||||
|
The ASTRA Toolbox is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
The ASTRA Toolbox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <cuda.h>
|
||||||
|
#include <driver_types.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#ifdef DLL_EXPORTS
|
||||||
|
#define _AstraExport __declspec(dllexport)
|
||||||
|
#define EXPIMP_TEMPLATE
|
||||||
|
#else
|
||||||
|
#define _AstraExport __declspec(dllimport)
|
||||||
|
#define EXPIMP_TEMPLATE extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define _AstraExport
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include "dims.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ASTRA_CUDA_ASSERT(err) do { if (err != cudaSuccess) { astraCUDA3d::reportCudaError(err); assert(err == cudaSuccess); } } while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _CUDA_UTIL3D_H
|
||||||
|
#define _CUDA_UTIL3D_H
|
||||||
|
|
||||||
|
#include <cuda.h>
|
||||||
|
#include "dims3d.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
//#include "../2d/util.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace astraCUDA3d {
|
||||||
|
|
||||||
|
typedef texture<float, 3, cudaReadModeElementType> texture3D;
|
||||||
|
|
||||||
|
cudaPitchedPtr allocateVolumeData(const SDimensions3D& dims);
|
||||||
|
cudaPitchedPtr allocateProjectionData(const SDimensions3D& dims);
|
||||||
|
bool zeroVolumeData(cudaPitchedPtr& D_data, const SDimensions3D& dims);
|
||||||
|
bool zeroProjectionData(cudaPitchedPtr& D_data, const SDimensions3D& dims);
|
||||||
|
bool copyVolumeToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
|
||||||
|
bool copyProjectionsToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
|
||||||
|
bool copyVolumeFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
|
||||||
|
bool copyProjectionsFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
|
||||||
|
bool duplicateVolumeData(cudaPitchedPtr& D_dest, const cudaPitchedPtr& D_src, const SDimensions3D& dims);
|
||||||
|
bool duplicateProjectionData(cudaPitchedPtr& D_dest, const cudaPitchedPtr& D_src, const SDimensions3D& dims);
|
||||||
|
|
||||||
|
bool transferVolumeToArray_1D(cudaPitchedPtr D_volumeData, cudaArray* array, const SDimensions3D& dims);
|
||||||
|
|
||||||
|
bool transferProjectionsToArray(cudaPitchedPtr D_projData, cudaArray* array, const SDimensions3D& dims);
|
||||||
|
bool transferVolumeToArray(cudaPitchedPtr D_volumeData, cudaArray* array, const SDimensions3D& dims);
|
||||||
|
bool zeroProjectionArray(cudaArray* array, const SDimensions3D& dims);
|
||||||
|
bool zeroVolumeArray(cudaArray* array, const SDimensions3D& dims);
|
||||||
|
cudaArray* allocateProjectionArray(const SDimensions3D& dims);
|
||||||
|
cudaArray* allocateVolumeArray(const SDimensions3D& dims);
|
||||||
|
cudaArray* transferDeformationToArray(const mxGPUArray * m_img);
|
||||||
|
bool bindDataTexture(const cudaArray* array, texture3D & Texture, cudaTextureAddressMode bordermode, bool normalized);
|
||||||
|
|
||||||
|
//float dotProduct3D(cudaPitchedPtr data, unsigned int x, unsigned int y, unsigned int z);
|
||||||
|
|
||||||
|
int calcNextPowerOfTwo(int _iValue);
|
||||||
|
|
||||||
|
|
||||||
|
bool cudaTextForceKernelsCompletion();
|
||||||
|
void reportCudaError(cudaError_t err);
|
||||||
|
|
||||||
|
double toc(double tstart);
|
||||||
|
double tic();
|
||||||
|
int checkLastError(char * msg);
|
||||||
|
void printFreeMemory();
|
||||||
|
|
||||||
|
int dumpArray(char* filename, int width, int height, float *buffer);
|
||||||
|
int dumpCudaArray(cudaPitchedPtr projData, int syart, int end, char * filename);
|
||||||
|
int writeImage(char * fname, int w, int h, float * data);
|
||||||
|
int writeBMPImage(char * fname, int w, int h, float ** red, float ** green, float ** blue);
|
||||||
|
int writeImageCudaArray(cudaPitchedPtr Data, int start, int end, char * filename);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
% ASTRA_FIND_OPTIMAL_SPLIT Find optimal split of data and make the blocks sufficiently small for
|
||||||
|
% limited GPU memory
|
||||||
|
%
|
||||||
|
% split = ASTRA_find_optimal_split(cfg, num_gpu, angle_blocks, propagator)
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% **cfg - config structure generated by ASTRA_initialize
|
||||||
|
% **num_gpu - number of gpu to split the data
|
||||||
|
% **angle_blocks - number of angular blocks (ie in SART method or FSC)
|
||||||
|
% **propagator - which propagator should be assumed : FWD, BACK, both (default)
|
||||||
|
% Outputs:
|
||||||
|
% ++split - volume / angle split - [split_x,split_y,split_z,split_angles]
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function split = ASTRA_find_optimal_split(cfg, num_gpu, angle_blocks, propagator)
|
||||||
|
|
||||||
|
if gpuDeviceCount == 0
|
||||||
|
split = 1;
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
gpu = gpuDevice;
|
||||||
|
if nargin < 2 || num_gpu == 0
|
||||||
|
num_gpu = 1;
|
||||||
|
end
|
||||||
|
if nargin < 3
|
||||||
|
angle_blocks = 1;
|
||||||
|
end
|
||||||
|
if nargin < 4
|
||||||
|
propagator = 'both';
|
||||||
|
end
|
||||||
|
|
||||||
|
Nangles = cfg.iProjAngles / angle_blocks;
|
||||||
|
if isfield(cfg, 'Grouping')
|
||||||
|
Nangles = min(Nangles, cfg.Grouping);
|
||||||
|
end
|
||||||
|
|
||||||
|
split = [1,1,1];
|
||||||
|
if ismember(lower(propagator), {'fwd','both'})
|
||||||
|
split = max(split, ceil([cfg.iVolX, cfg.iVolY, cfg.iVolZ] / 4096 )); % texture memory limit
|
||||||
|
split = max(split, [1,1,ceil( (cfg.iVolX*cfg.iVolY*cfg.iVolZ*4) / 1.024e9 / prod(split)/num_gpu)]); % texture memory limit
|
||||||
|
end
|
||||||
|
split = max(split, [1,1,split(3)*ceil( ((cfg.iVolX*cfg.iVolY*cfg.iVolZ*4)/ prod(split)/num_gpu) / (gpu.AvailableMemory/2 - min(1.1e9, cfg.iVolX*cfg.iVolY*cfg.iVolZ*4)) )]); % gpu memory limit
|
||||||
|
split = max(split, [1,1,split(3)*ceil( ((cfg.iVolX*cfg.iVolY*cfg.iVolZ )/ prod(split)/num_gpu) / double(intmax('int32')) )]); % maximal array on GPU limit
|
||||||
|
|
||||||
|
if ismember(lower(propagator), {'back','both'})
|
||||||
|
% if projection would be larger than 4096x4096 -> split the reconstruction volume
|
||||||
|
split = max(split, [cfg.iProjU, cfg.iProjU, cfg.iProjV]/4096 ); % texture memory limit
|
||||||
|
end
|
||||||
|
|
||||||
|
% projection size limitation + astra allows only < 1024 angles
|
||||||
|
split(4) = max(ceil(Nangles/1024), ceil( (cfg.iProjU*cfg.iProjV*min(1024,Nangles)*4) / gpu.TotalMemory/num_gpu)); % gpu memory limit
|
||||||
|
|
||||||
|
% RAM limits
|
||||||
|
if cfg.iVolX*cfg.iVolY*cfg.iVolZ > 2e6
|
||||||
|
freemem = 0.8 * utils.check_available_memory;
|
||||||
|
split(4) = max(split(4), num_gpu*(4*(cfg.iProjU*cfg.iProjV*cfg.iProjAngles...
|
||||||
|
+ cfg.iVolX*cfg.iVolY*cfg.iVolZ*(1+1/prod(split(1:3)))))...
|
||||||
|
/ (freemem * 1e6) ); % RAM memory limit
|
||||||
|
end
|
||||||
|
split(4) = ceil(split(4));
|
||||||
|
split(1:3) = 2.^nextpow2(split(1:3));
|
||||||
|
% if any(split ~= 1)
|
||||||
|
% fprintf('Automatically splitting to %ix%ix%ix(%i) cubes \n', split);
|
||||||
|
% end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
% ASTRA_INITIALIZE Generate inputs needed for astra MEX wrapper
|
||||||
|
%
|
||||||
|
% [cfg, vectors] = ASTRA_initialize(Npix, size_projection,angles,lamino_angle, tilt_angle, pixel_scale, rotation_center)
|
||||||
|
%
|
||||||
|
% Inputs for angular geometry (!! all angles are expected in degress !!):
|
||||||
|
% **Npix - size of tomogram
|
||||||
|
% **size_projection - size of sinogram (Nlayers, width, Nangles)
|
||||||
|
% **angles - rotation angles of projections in degrees
|
||||||
|
% *optional*:
|
||||||
|
% **lamino_angle - laminography angle / angles in degrees. lamino_angle ==
|
||||||
|
% 90 is standard tomography , default = 90
|
||||||
|
% **tilt_angle - tilt of camera with respect to the rotation axis coordinates, in degrees, default = 0
|
||||||
|
% **pixel_scale - scale of pixels in tomogram compares to the
|
||||||
|
% projection pixel size, default = 1
|
||||||
|
% **rotation_center - center of rotation coordinates, default = size_projection/2
|
||||||
|
% **skewness_angle - distorsion of parallel axis by [1, sind(alpha); 0, 1]
|
||||||
|
%
|
||||||
|
% Inputs for rotation matrix geometry:
|
||||||
|
% **Npix - size of tomogram
|
||||||
|
% **size_projection - size of sinogram (Nlayers, width, Nangles)
|
||||||
|
% **rotation_matrix - R is a 3x3xn matrix, for n projections
|
||||||
|
%
|
||||||
|
% Outputs:
|
||||||
|
% ++cfg - config structure for ASTRA mex wrapper
|
||||||
|
% ++vectors - parameter vector for each angle
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function [cfg, vectors] = ASTRA_initialize(Npix, size_projection, varargin)
|
||||||
|
use_rotmat = length(varargin) == 1 && size(varargin{1},1) == 3 && size(varargin{1},2) == 3 ;
|
||||||
|
if use_rotmat
|
||||||
|
% rotation matrices were provided
|
||||||
|
rot_mat = varargin{1};
|
||||||
|
Nangles = size(rot_mat,3);
|
||||||
|
r.rotation_center = size_projection/2; % only centered geometry is supported when rotation matrix is provided
|
||||||
|
else
|
||||||
|
% angles and other parameters were provided
|
||||||
|
par = inputParser;
|
||||||
|
par.KeepUnmatched = true;
|
||||||
|
%% ALL angles are assumed in degrees
|
||||||
|
par.addRequired('angles') % rotation angles of projections in degrees
|
||||||
|
par.addOptional('lamino_angle', 90, @isnumeric) % laminography angle / angles in degrees. lamino_angle == 90 is standard tomography , default = 90
|
||||||
|
par.addOptional('tilt_angle', 0, @isnumeric) % tilt of camera with respect to the rotation axis coordinates, in
|
||||||
|
par.addOptional('pixel_scale', [1,1], @isnumeric) % scale of pixels in tomogram compares to the projection pixel size, default = 1
|
||||||
|
par.addOptional('rotation_center', size_projection/2, @isnumeric) % center of rotation cooridinates, default = size_projection/2
|
||||||
|
par.addOptional('skewness_angle', 0) % distorsion of parallel axis by [1, sind(alpha); 0, 1]
|
||||||
|
par.addParameter('show_geometry', false) % plot also a geometry for each projection
|
||||||
|
par.parse(varargin{:})
|
||||||
|
r = par.Results;
|
||||||
|
Nangles = length(r.angles);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% angles should be sorted in order to maximize performance of the astra
|
||||||
|
% toolbox -> better use of texture memory
|
||||||
|
|
||||||
|
assert(math.isint(Npix), 'Npix is not integer');
|
||||||
|
assert(math.isint(size_projection), 'size_projection is not integer');
|
||||||
|
|
||||||
|
if isscalar(Npix)
|
||||||
|
Npix(2) = Npix;
|
||||||
|
end
|
||||||
|
if length(Npix) == 2 && all(r.lamino_angle == 90)
|
||||||
|
Npix(3) = size_projection(1); % default behaviour is to have same number of layers in reconstruction and in laminography
|
||||||
|
elseif length(Npix) == 2 && any(r.lamino_angle ~= 90)
|
||||||
|
error('All three dimensions of the volume size has to be specified for the laminograhy geometry')
|
||||||
|
end
|
||||||
|
|
||||||
|
cfg.iVolX = Npix(1);
|
||||||
|
cfg.iVolY = Npix(2);
|
||||||
|
cfg.iVolZ = Npix(3);
|
||||||
|
cfg.iProjAngles = Nangles;
|
||||||
|
cfg.iProjU = size_projection(2);
|
||||||
|
cfg.iProjV = size_projection(1);
|
||||||
|
cfg.iRaysPerDet = 1;
|
||||||
|
cfg.iRaysPerDetDim = 1;
|
||||||
|
cfg.iRaysPerVoxelDim = 1;
|
||||||
|
source_distance = 1; % currenlty not implemented in the ASTRA wrapper
|
||||||
|
|
||||||
|
|
||||||
|
if use_rotmat
|
||||||
|
[vectors] = astra_convert_R_vectors(rot_mat,Nangles);
|
||||||
|
else
|
||||||
|
% compatibility with iradonfast
|
||||||
|
r.angles = r.angles + 90;
|
||||||
|
cfg.lamino_angle = r.lamino_angle;
|
||||||
|
cfg.pixel_scale = r.pixel_scale;
|
||||||
|
cfg.tilt_angle = r.tilt_angle;
|
||||||
|
cfg.skewness_angle = r.skewness_angle;
|
||||||
|
vectors = ASTRA_get_geometry(r.angles, r.lamino_angle, r.tilt_angle, source_distance,r.pixel_scale,r.skewness_angle,r.show_geometry);
|
||||||
|
end
|
||||||
|
|
||||||
|
%%%% apply geometry correction to shift reconstruction into center %%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
vectors(:,4:6) = vectors(:,4:6) -(vectors(:,10:12).*(r.rotation_center(:,1) )+vectors(:,7:9).*(r.rotation_center(:,2) ));
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function vectors = ASTRA_get_geometry(angles, lamino_angle, tilt_angle, source_distance,pixel_scale,skewness_angle,show)
|
||||||
|
|
||||||
|
Nangles = numel(angles);
|
||||||
|
% angles should be sorted in order to maximize performance of the astra
|
||||||
|
% toolbox -> better use of texture memory
|
||||||
|
|
||||||
|
angles = deg2rad(angles(:));
|
||||||
|
lamino_angle = pi/2 - deg2rad(lamino_angle);
|
||||||
|
tilt_angle = deg2rad(tilt_angle);
|
||||||
|
skewness_angle = deg2rad(skewness_angle);
|
||||||
|
|
||||||
|
if isscalar(lamino_angle)
|
||||||
|
lamino_angle = lamino_angle .* ones(Nangles,1);
|
||||||
|
end
|
||||||
|
if isscalar(tilt_angle)
|
||||||
|
tilt_angle = tilt_angle .* ones(Nangles,1);
|
||||||
|
end
|
||||||
|
if isscalar(skewness_angle)
|
||||||
|
skewness_angle = skewness_angle .* ones(Nangles,1);
|
||||||
|
end
|
||||||
|
if isscalar(pixel_scale) || numel(pixel_scale) == 2
|
||||||
|
pixel_scale = bsxfun(@times, pixel_scale , ones(Nangles,2));
|
||||||
|
end
|
||||||
|
|
||||||
|
% We generate the same geometry as the circular one above.
|
||||||
|
vectors = zeros(Nangles, 12);
|
||||||
|
% ray direction
|
||||||
|
vectors(:,1) = sin(angles).*cos(lamino_angle);
|
||||||
|
vectors(:,2) = -cos(angles).*cos(lamino_angle);
|
||||||
|
vectors(:,3) = sin(lamino_angle);
|
||||||
|
|
||||||
|
vectors(:,1:3) = vectors(:,1:3) .*source_distance;
|
||||||
|
% center of detector
|
||||||
|
vectors(:,4:6) = 0;
|
||||||
|
% vector from detector pixel (0,0) to (0,1)
|
||||||
|
vectors(:,7) = cos(angles)./pixel_scale(:,1);
|
||||||
|
vectors(:,8) = sin(angles)./pixel_scale(:,1);
|
||||||
|
vectors(:,9) = 0/pixel_scale(:,1);
|
||||||
|
|
||||||
|
% vector from detector pixel (0,0) to (1,0)
|
||||||
|
|
||||||
|
% cross(vectors(i,1:3), vectors(i,7:9))
|
||||||
|
% dot(vectors(i,1:3), vectors(i,7:9))
|
||||||
|
|
||||||
|
vectors(:,10) = - sin(lamino_angle).*sin(angles)./pixel_scale(:,2);
|
||||||
|
vectors(:,11) = sin(lamino_angle).*cos(angles)./pixel_scale(:,2);
|
||||||
|
vectors(:,12) = cos(lamino_angle)./pixel_scale(:,2);
|
||||||
|
|
||||||
|
% Rodrigues' rotation formula - rotate detector in plane
|
||||||
|
% perpendicular to the beam axis
|
||||||
|
if any(tilt_angle ~= 0)
|
||||||
|
for i = 1:Nangles
|
||||||
|
vectors(i,7:9)=vectors(i,7:9).*cos(tilt_angle(i)) + ...
|
||||||
|
cross(vectors(i,1:3), vectors(i,7:9)).*sin(tilt_angle(i)) + ...
|
||||||
|
(vectors(i,1:3)*dot(vectors(i,1:3),vectors(i,7:9))).*(1-cos(tilt_angle(i)));
|
||||||
|
vectors(i,10:12)=vectors(i,10:12).*cos(tilt_angle(i)) + ...
|
||||||
|
cross(vectors(i,1:3), vectors(i,10:12)).*sin(tilt_angle(i)) + ...
|
||||||
|
(vectors(i,1:3).*dot(vectors(i,1:3),vectors(i,10:12))).*(1-cos(tilt_angle(i)));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% search also for skewness => the same as rotation, but rotate
|
||||||
|
% only one axis of the detector !!
|
||||||
|
if any(skewness_angle ~= 0)
|
||||||
|
for i = 1:Nangles
|
||||||
|
vectors(i,10:12)=vectors(i,10:12).*cos(skewness_angle(i)/2) + ...
|
||||||
|
cross(vectors(i,1:3), vectors(i,10:12)).*sin(skewness_angle(i)/2) + ...
|
||||||
|
(vectors(i,1:3).*dot(vectors(i,1:3),vectors(i,10:12))).*(1-cos(skewness_angle(i)/2));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% PLOT THE CURRENT SETUP
|
||||||
|
|
||||||
|
if show
|
||||||
|
for i = 1:Nangles
|
||||||
|
draw_projection_geometry(vectors(i,:))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function [vectors] = astra_convert_R_vectors(rot_mat,Nangles)
|
||||||
|
|
||||||
|
% R is defined as in the arbitrary projection code by Manuel
|
||||||
|
% This integrates along z (2nd index) and so this code follows this
|
||||||
|
% convention.
|
||||||
|
pixel_scale(1:Nangles,1:2) = [1];
|
||||||
|
|
||||||
|
|
||||||
|
convert_matrix = [0 0 1
|
||||||
|
0 1 0
|
||||||
|
1 0 0];
|
||||||
|
|
||||||
|
for ii=1:size(rot_mat,3)
|
||||||
|
rot_mat(:,:,ii)=rot_mat(:,:,ii)*convert_matrix;
|
||||||
|
end
|
||||||
|
|
||||||
|
vectors = zeros(Nangles, 12);
|
||||||
|
for i = 1:Nangles
|
||||||
|
% before starting to mess around: works with a correction matrix
|
||||||
|
% with the magnetic contrast, but not for the laminography
|
||||||
|
vectors(i,1) = -rot_mat(3,1,i);
|
||||||
|
vectors(i,2) = -rot_mat(3,3,i);
|
||||||
|
vectors(i,3) = -rot_mat(3,2,i);
|
||||||
|
|
||||||
|
vectors(i,4:6) = 0;
|
||||||
|
|
||||||
|
vectors(i,7) = rot_mat(1,1,i)/pixel_scale(i,1);
|
||||||
|
vectors(i,8) = rot_mat(1,3,i)/pixel_scale(i,1);
|
||||||
|
vectors(i,9) = rot_mat(1,2,i)/pixel_scale(i,1);
|
||||||
|
|
||||||
|
vectors(i,10) = rot_mat(2,1,i)/pixel_scale(i,2);
|
||||||
|
vectors(i,11) = rot_mat(2,3,i)/pixel_scale(i,2);
|
||||||
|
vectors(i,12) = rot_mat(2,2,i)/pixel_scale(i,2);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function draw_projection_geometry(vectors)
|
||||||
|
% show geometry saved in the "vectors" matrix
|
||||||
|
ray = vectors(1:3);
|
||||||
|
c_center = vectors(4:6)-ray;
|
||||||
|
c_origin = c_center - vectors( 7:9)/2-vectors( 10:12)/2;
|
||||||
|
|
||||||
|
k = 6;
|
||||||
|
n = 2^k-1;
|
||||||
|
[x,y,z] = sphere(n);
|
||||||
|
c = hadamard(2^k);
|
||||||
|
s = 0.5;
|
||||||
|
figure(15)
|
||||||
|
surf(vectors(4)+s*x,vectors(5)+s*y,vectors(6)+s*z,c);
|
||||||
|
shading flat
|
||||||
|
colormap([1 1 0; 0 1 1])
|
||||||
|
|
||||||
|
hold all
|
||||||
|
plot3d_vec(c_origin, vectors( 7:9), 'r');
|
||||||
|
plot3d_vec(c_origin, vectors( 10:12), 'r');
|
||||||
|
plot3d_vec(c_origin+vectors( 7:9), vectors( 10:12), 'r');
|
||||||
|
plot3d_vec(c_origin+vectors( 10:12), vectors( 7:9), 'r');
|
||||||
|
% draw "pixels" on a 10x10 grid
|
||||||
|
for x = linspace(0,1,10)
|
||||||
|
plot3d_vec(c_origin+x*vectors( 10:12), vectors( 7:9), 'r:');
|
||||||
|
plot3d_vec(c_origin+x*vectors( 7:9),vectors( 10:12), 'r:');
|
||||||
|
end
|
||||||
|
plotting.mArrow3(c_center+ray*2,c_center, 'color', 'blue', 'stemWidth',0.02,'facealpha',0.5);
|
||||||
|
|
||||||
|
hold off
|
||||||
|
axis([-1,1,-1,1,-1,1])
|
||||||
|
drawnow
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function h_out = plot3d_vec(x0, vec, varargin)
|
||||||
|
h = plot3(x0(1)+[0,vec(1)], ...
|
||||||
|
x0(2)+[0,vec(2)], ...
|
||||||
|
x0(3)+[0,vec(3)], varargin{:});
|
||||||
|
if nargout > 1
|
||||||
|
h_out = h;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
% AX_PARTIAL backprojector that allows to split the full volume into smaller pieces
|
||||||
|
% composed tomography back-projector based on ASTRA toolbox
|
||||||
|
% can be used either for data in RAM or on GPU (automatically decided from class of volData)
|
||||||
|
% * volume is split based on "split" parameter, 1 == no splitting
|
||||||
|
% * Ax_partial tries to split data if GPU limits are exceeded (ie texture memory limits)
|
||||||
|
%
|
||||||
|
% vol_full = Atx_partial(projData, cfg, vectors,split,varargin)
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% **projData - array Nx x Ny x Nz of projected volume
|
||||||
|
% **cfg - config structure generated by ASTRA_initialize
|
||||||
|
% **vectors - orientation of projections generated by ASTRA_initialize
|
||||||
|
% **split - 3 or 4 elements vector, [split X, split Y, split Z, split angle ]
|
||||||
|
% *optional*
|
||||||
|
% **deformation_fields - 3x1 cell contaning 3D arrays of local deformation of the object
|
||||||
|
% **GPU - GPU id to be used for reconstruction
|
||||||
|
% **verbose - verbose = 0 : (default) quiet, verbose = 1: standard info , verbose = 2: debug
|
||||||
|
% **keep_on_GPU - if true keep reconstructed volume on GPU to make is faster, default == false (the safe option)
|
||||||
|
%
|
||||||
|
% *returns*
|
||||||
|
% ++vol_full - projection of volData
|
||||||
|
%
|
||||||
|
% recompile commands
|
||||||
|
% (Linux, GCC 4.8.5) mexcuda -outdir private ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper/util3d.cu ASTRA_GPU_wrapper/par3d_fp.cu ASTRA_GPU_wrapper/par3d_bp.cu
|
||||||
|
% (Windows) mexcuda -outdir private ASTRA_GPU_wrapper\ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper\util3d.cu ASTRA_GPU_wrapper\par3d_fp.cu ASTRA_GPU_wrapper\par3d_bp.cu
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
function vol_full = Atx_partial(projData, cfg, vectors,split,varargin)
|
||||||
|
|
||||||
|
|
||||||
|
import utils.*
|
||||||
|
import math.*
|
||||||
|
|
||||||
|
par = inputParser;
|
||||||
|
par.KeepUnmatched = true;
|
||||||
|
|
||||||
|
par.addOptional('deformation_fields', {}) % deformation_fields: 3x1 cell contaning 3D arrays of local deformation of the object
|
||||||
|
par.addOptional('GPU', []) % GPUs id to be used in reconstruction
|
||||||
|
par.addOptional('keep_on_GPU', false) % true - keep reconstructed volume on GPU to make is faster
|
||||||
|
par.addOptional('verbose', 0) %
|
||||||
|
|
||||||
|
par.parse(varargin{:})
|
||||||
|
r = par.Results;
|
||||||
|
|
||||||
|
if isempty(r.deformation_fields); r.deformation_fields = {}; end
|
||||||
|
|
||||||
|
%% check the inputs + check memory availibility on GPU
|
||||||
|
assert(gpuDeviceCount>0, 'No CUDA enabled GPU availible')
|
||||||
|
|
||||||
|
if ~( (isa(projData, 'gpuArray') && strcmp(classUnderlying(projData), 'single')) || ...
|
||||||
|
isa(projData, 'single') ) || ~isreal(projData)
|
||||||
|
error('Only single precision real input array supported')
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isempty(r.deformation_fields)
|
||||||
|
assert(any(numel(r.deformation_fields) == [3,6]), 'Deformation field expected as 3x1 or 6x1 cell array')
|
||||||
|
|
||||||
|
for i = 1:numel(r.deformation_fields)
|
||||||
|
if ~( (isa(r.deformation_fields{i}, 'gpuArray') && strcmp(classUnderlying(r.deformation_fields{i}), 'single')) || ...
|
||||||
|
isa(r.deformation_fields{i}, 'single'))
|
||||||
|
error('Only single precision for deformation fields is supported')
|
||||||
|
end
|
||||||
|
r.deformation_fields{i} = gpuArray(r.deformation_fields{i}); % move on GPU, they are usually small
|
||||||
|
end
|
||||||
|
r.deformation_fields = r.deformation_fields' ; % transpose to that array(:) results in sorted field
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
projSize = size(projData);
|
||||||
|
cfg.iProjAngles = size(vectors,1); % ignore value in config
|
||||||
|
|
||||||
|
gpu = gpuDevice();
|
||||||
|
if ~isempty(r.GPU) && gpu.Index ~= r.GPU(1)
|
||||||
|
% switch and !! reset !! GPU
|
||||||
|
if isa(projData, 'gpuArray'), error('Switching GPUs will reset content'); end
|
||||||
|
gpu = gpuDevice(r.GPU(1));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
assert(cfg.iVolX*cfg.iVolY*cfg.iVolZ > 0, 'Volume is empty');
|
||||||
|
assert(numel(projSize) > 0, 'Projections are empty');
|
||||||
|
|
||||||
|
% input parameters check
|
||||||
|
if ismatrix(projData); projSize = [projSize,1]; end
|
||||||
|
assert(max(cfg.iProjU, cfg.iProjV) <= 4096, 'Sinogram exceed maximal size allowed by GPU (4096)')
|
||||||
|
assert(all(projSize==[cfg.iProjV,cfg.iProjU,cfg.iProjAngles]), 'Wrong inputs size')
|
||||||
|
assert(all(size(vectors)==[cfg.iProjAngles,12]), 'Wrong vectors size')
|
||||||
|
|
||||||
|
split_projections = cfg.iProjAngles > 1024 || ...
|
||||||
|
numel(projData)*4 > 1024e6 || ... ; % Data array is to large, try splitting
|
||||||
|
(length(split) > 3 && split(4) > 1); % split contains also angular split
|
||||||
|
|
||||||
|
% be sure that ASTRA wrapper is feeded by doubles !!
|
||||||
|
for i = fieldnames(cfg)'
|
||||||
|
cfg.(i{1}) = double(cfg.(i{1}));
|
||||||
|
end
|
||||||
|
vectors = double(vectors);
|
||||||
|
split=double(split);
|
||||||
|
|
||||||
|
if all(split == 1) && ~split_projections
|
||||||
|
assert(cfg.iVolX*cfg.iVolY*cfg.iVolZ*4 < min(4*double(intmax('int32')),gpu.AvailableMemory), 'Volume array is too large for GPU, use Atx_sup_partial');
|
||||||
|
%% in the simplest case call ASTRA_GPU_wrapper directly
|
||||||
|
if isa(projData, 'gpuArray'), r.keep_on_GPU = true; end % assume that the data should stay on GPU if provided
|
||||||
|
projData = matlab2astra(gpuArray(projData));
|
||||||
|
vol_full = astra.ASTRA_GPU_wrapper('bp',projData, cfg, vectors,[],r.deformation_fields{:});
|
||||||
|
if ~r.keep_on_GPU; vol_full = gather(vol_full); end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
%% otherwise prepare data for split and call ASTRA_GPU_wrapper on subvolumes
|
||||||
|
|
||||||
|
split = ceil(max(1,split));
|
||||||
|
if isscalar(split)
|
||||||
|
split = split .* ones(3,1);
|
||||||
|
end
|
||||||
|
|
||||||
|
if length(split) < 4
|
||||||
|
split(4) = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% PREPARE VOLUME %%
|
||||||
|
|
||||||
|
Npix_full = [cfg.iVolX,cfg.iVolY,cfg.iVolZ];
|
||||||
|
Npix_small = Npix_full(:)./reshape(split(1:3),[],1);
|
||||||
|
|
||||||
|
cfg.iVolX = Npix_small(1);
|
||||||
|
cfg.iVolY = Npix_small(2);
|
||||||
|
cfg.iVolZ = Npix_small(3);
|
||||||
|
|
||||||
|
assert( all(mod(Npix_small,1)==0), sprintf('Volume array cannot be divided to %i %i %i cubes', split))
|
||||||
|
assert(prod(Npix_small)*4 < min(4*double(intmax('int32')),gpu.AvailableMemory), 'Volume array is too large for GPU, use Atx_sup_partial');
|
||||||
|
|
||||||
|
|
||||||
|
req_vol_memory = 4*(cfg.iVolX*cfg.iVolY*cfg.iVolZ) * (1+any(split(1:3)>1));
|
||||||
|
|
||||||
|
keep_volume_on_GPU = isa(projData, 'gpuArray') ||...
|
||||||
|
(gpu.AvailableMemory * 0.5 > req_vol_memory) && ...
|
||||||
|
( (cfg.iVolX*cfg.iVolY*cfg.iVolZ) < intmax('int32') );
|
||||||
|
|
||||||
|
% preallocate large array for results
|
||||||
|
if keep_volume_on_GPU || prod(split(1:3)) == 1
|
||||||
|
% transfer to GPU now
|
||||||
|
vol_full = gpuArray.zeros(Npix_full, 'single');
|
||||||
|
else
|
||||||
|
% keep the volume in RAM
|
||||||
|
vol_full = zeros(Npix_full, 'single');
|
||||||
|
end
|
||||||
|
|
||||||
|
%% PREPARE PROJECTIONS %%
|
||||||
|
|
||||||
|
% fix if the number of projections is > 1024, or arrays are too large
|
||||||
|
Nproj_groups = max(split(4),ceil(max([cfg.iProjAngles/1024, ...
|
||||||
|
cfg.iProjU*cfg.iProjV*cfg.iProjAngles*4 / min(1024e6,gpu.AvailableMemory-1.024e9), ...
|
||||||
|
cfg.iProjU * cfg.iProjV * cfg.iProjAngles / double(intmax('int32'))])));
|
||||||
|
|
||||||
|
% avoid some rounding issues during splitting
|
||||||
|
Nproj_groups = ceil(cfg.iProjAngles / floor(cfg.iProjAngles/Nproj_groups));
|
||||||
|
|
||||||
|
|
||||||
|
if r.verbose > 1
|
||||||
|
fprintf('Size of the full volume: %i %i %i\n', Npix_full)
|
||||||
|
fprintf('Size of the subvolume: %i %i %i\n', Npix_small)
|
||||||
|
fprintf('Size of the data: %i %i %i\n', size(projData))
|
||||||
|
fprintf('Free GPU memory: %3.2g%%\n', gpu.AvailableMemory/gpu.TotalMemory*100)
|
||||||
|
end
|
||||||
|
|
||||||
|
if Nproj_groups > 1
|
||||||
|
% fix if the number of projections is > 1024 (limitation of the ASTRA code )
|
||||||
|
% also if the dataset is too large (>1024MB), do automatic splitting along angles
|
||||||
|
|
||||||
|
for i = 1:Nproj_groups
|
||||||
|
ind = (1+(i-1)*ceil(cfg.iProjAngles/Nproj_groups)):i*ceil(cfg.iProjAngles/Nproj_groups);
|
||||||
|
ind = ind(ind <= cfg.iProjAngles);
|
||||||
|
proj_ind{i} = ind;
|
||||||
|
vectors_tmp{i} = vectors(ind,:);
|
||||||
|
cfg_tmp{i} = cfg;
|
||||||
|
cfg_tmp{i}.iProjAngles = length(ind);
|
||||||
|
end
|
||||||
|
cfg = cfg_tmp; vectors = vectors_tmp;
|
||||||
|
clear projData_tmp
|
||||||
|
else
|
||||||
|
Nproj_groups = 1;
|
||||||
|
cfg = {cfg};
|
||||||
|
vectors = {vectors};
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isempty(r.deformation_fields) && any(split(1:3) > 1)
|
||||||
|
error('Deformation field splitting not implemented')
|
||||||
|
end
|
||||||
|
|
||||||
|
if gpu.AvailableMemory > 4*(numel(projData)+ ...
|
||||||
|
cfg{1}.iProjU* cfg{1}.iProjV*cfg{1}.iProjAngles * (Nproj_groups>1) ...
|
||||||
|
+any(split>1)*prod(Npix_small)*(2 + ~isa(vol_full, 'gpuArray'))) && ...
|
||||||
|
numel(projData) < intmax('int32')
|
||||||
|
projData = gpuArray(projData); % move small blocks directly on GPU
|
||||||
|
end
|
||||||
|
|
||||||
|
inParpool = ~isempty(getCurrentTask());
|
||||||
|
iter = 1;
|
||||||
|
for k = 1:Nproj_groups
|
||||||
|
if Nproj_groups > 1
|
||||||
|
if length(proj_ind{k}) > 1 && ~inParpool && ~isa(projData, 'gpuArray') && exist('+tomo/get_from_array.m', 'file')
|
||||||
|
% use custom made MEX function from +tomo package, usually
|
||||||
|
% faster but use a lot of CPU
|
||||||
|
projData_small = tomo.get_from_array(projData, [], proj_ind{k}); % load subblock from projections
|
||||||
|
else
|
||||||
|
projData_small = projData(:,:,proj_ind{k}); % split the projections if needed
|
||||||
|
end
|
||||||
|
else
|
||||||
|
projData_small = projData;
|
||||||
|
end
|
||||||
|
if gpu.AvailableMemory < 2*4*numel(projData_small)
|
||||||
|
% in case of low GPU memory, transpose data in RAM
|
||||||
|
projData_small = gpuArray(matlab2astra(projData_small)); % transfer projections to GPU if not there yet
|
||||||
|
else
|
||||||
|
% move subblocks of the data on GPU
|
||||||
|
projData_small = gpuArray(projData_small);
|
||||||
|
projData_small = matlab2astra(projData_small);
|
||||||
|
end
|
||||||
|
if numel(projData_small) * 4 > 1024e6
|
||||||
|
error('Data exceeded maximal size of texture memory 1024MB, Increase "split" to reduce the projection size')
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if gpu.AvailableMemory < prod(Npix_small)*4 && prod(split(1:3)) ~= 1
|
||||||
|
% memory needed to make CUDA array for texture memory
|
||||||
|
pause(0.1)
|
||||||
|
!nvidia-smi
|
||||||
|
whos
|
||||||
|
error('Too low GPU memory, avail: %3.2gGB / req: %3.2gGB, GPU %i/%i', gpu.AvailableMemory/1e9,prod(Npix_small)*4/1e9, gpu.Index, gpuDeviceCount)
|
||||||
|
end
|
||||||
|
for z = 1:split(3)
|
||||||
|
for x = 1:split(1)
|
||||||
|
for y =1:split(2)
|
||||||
|
if r.verbose > 0
|
||||||
|
progressbar(iter, prod(split(1:3))*Nproj_groups+1, 20);
|
||||||
|
end
|
||||||
|
pos = [x,y,z];
|
||||||
|
for n = 1:3
|
||||||
|
% find optimal shift of the subvolume
|
||||||
|
if mod(split(n),2)==1 %% odd
|
||||||
|
shift(n) = (pos(n) - ceil(split(n)/2))*Npix_small(n);
|
||||||
|
else
|
||||||
|
shift(n) = (pos(n) - ceil(split(n)/2)-1/2)*Npix_small(n);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vectors_tmp = vectors{k};
|
||||||
|
vectors_tmp(:,4:6) = bsxfun(@minus, vectors_tmp(:,4:6), shift);
|
||||||
|
if prod(split(1:3))== 1
|
||||||
|
req_mem = numel(projData_small)*4 ;
|
||||||
|
else
|
||||||
|
req_mem = 2*numel(projData_small)*4 ;
|
||||||
|
end
|
||||||
|
if gpu.AvailableMemory < req_mem
|
||||||
|
error('Too low GPU memory, avail: %3.2gGB / req: %3.2gGB, GPU %i/%i', gpu.AvailableMemory/1e9,req_mem/1e9, gpu.Index, gpuDeviceCount)
|
||||||
|
end
|
||||||
|
try
|
||||||
|
if prod(split(1:3))== 1
|
||||||
|
% no splitting, vol_small == vol_full -> write
|
||||||
|
% the backprojection directly to vol_full
|
||||||
|
% without copying -> no output arguments are needed
|
||||||
|
astra.ASTRA_GPU_wrapper('bp', projData_small, cfg{k}, vectors_tmp,vol_full,r.deformation_fields{:});
|
||||||
|
else
|
||||||
|
vol_small = astra.ASTRA_GPU_wrapper('bp', projData_small, cfg{k}, vectors_tmp,[],r.deformation_fields{:});
|
||||||
|
% if some volume split is needed, add the subvolume
|
||||||
|
% to the full volume
|
||||||
|
if ~keep_volume_on_GPU
|
||||||
|
vol_small = gather(vol_small); % return to RAM
|
||||||
|
end
|
||||||
|
if keep_volume_on_GPU || isa(vol_full, 'gpuArray') || ~exist('+tomo/add_to_3D_volume.m', 'file')
|
||||||
|
% return results to the large array
|
||||||
|
% use matlab to do the copying on GPU
|
||||||
|
vol_full =add_to_3D(vol_full, vol_small,([x,y,z]-1).*Npix_small');
|
||||||
|
else
|
||||||
|
% otherwise use paralelized CPU code
|
||||||
|
tomo.add_to_3D_volume(vol_full,vol_small, ([x,y,z]-1).*Npix_small', true);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
catch err
|
||||||
|
if strcmpi(err.identifier,'parallel:gpu:array:OOM')
|
||||||
|
warning('Out of memory on GPU %i, try reset GPU or split the array onto smaller blocks', gpu.Index)
|
||||||
|
gpuDevice
|
||||||
|
end
|
||||||
|
reset(gpuDevice)
|
||||||
|
rethrow(err)
|
||||||
|
end
|
||||||
|
|
||||||
|
iter = iter+1;
|
||||||
|
if r.verbose > 0
|
||||||
|
progressbar(iter, prod(split(1:3))*Nproj_groups+1, 20);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~r.keep_on_GPU
|
||||||
|
vol_full = gather(vol_full);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,385 @@
|
|||||||
|
% AX_PARTIAL forward projector that allows to split the full volume into smaller pieces
|
||||||
|
% composed tomography projector based on ASTRA toolbox
|
||||||
|
% can be used either for data in RAM or on GPU (automatically decided from class of volData)
|
||||||
|
% * volume is split based on "split" parameter, 1 == no splitting
|
||||||
|
% * Ax_partial tries to split data if GPU limits are exceeded (ie texture memory limits)
|
||||||
|
%
|
||||||
|
% projData = Ax_partial(volData, cfg, vectors,split, varargin)
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% **volData - array Nx x Ny x Nz of projected volume
|
||||||
|
% **cfg - config structure generated by ASTRA_initialize
|
||||||
|
% **vectors - orientation of projections generated by ASTRA_initialize
|
||||||
|
% **split - 3 or 4 elements vector, [split X, split Y, split Z, split angle ]
|
||||||
|
% *optional*
|
||||||
|
% **deformation_fields - 3x1 cell contaning 3D arrays of local deformation of the object
|
||||||
|
% **GPU - GPU id to be used for reconstruction
|
||||||
|
% **verbose - verbose = 0 : (default) quiet, verbose = 1: standard info , verbose = 2: debug
|
||||||
|
% **keep_on_GPU - if true keep reconstructed volume on GPU to make is faster, default == false (the safe option)
|
||||||
|
%
|
||||||
|
% *returns*
|
||||||
|
% ++projData - projection of volData
|
||||||
|
%
|
||||||
|
% recompile commands
|
||||||
|
% (Linux, GCC 4.8.5) mexcuda -outdir private ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper/util3d.cu ASTRA_GPU_wrapper/par3d_fp.cu ASTRA_GPU_wrapper/par3d_bp.cu
|
||||||
|
% (Windows) mexcuda -outdir private ASTRA_GPU_wrapper\ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper\util3d.cu ASTRA_GPU_wrapper\par3d_fp.cu ASTRA_GPU_wrapper\par3d_bp.cu
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
function projData = Ax_partial(volData, cfg, vectors,split, varargin)
|
||||||
|
|
||||||
|
|
||||||
|
import utils.*
|
||||||
|
import math.*
|
||||||
|
|
||||||
|
par = inputParser;
|
||||||
|
par.KeepUnmatched = true;
|
||||||
|
|
||||||
|
par.addOptional('deformation_fields', {}) % deformation_fields: 3x1 cell contaning 3D arrays of local deformation of the object
|
||||||
|
par.addOptional('GPU', []) % GPUs id to be used in reconstruction
|
||||||
|
par.addOptional('verbose', 0) % verbose = 0 : quiet, verbose : standard info , verbose = 2: debug
|
||||||
|
par.addOptional('keep_on_GPU', false) % true - keep reconstructed volume on GPU to make is faster
|
||||||
|
|
||||||
|
par.parse(varargin{:})
|
||||||
|
r = par.Results;
|
||||||
|
|
||||||
|
if isempty(r.deformation_fields); r.deformation_fields = {}; end
|
||||||
|
|
||||||
|
%% check the inputs + check memory availibility on GPU
|
||||||
|
assert(gpuDeviceCount>0, 'No CUDA enabled GPU availible')
|
||||||
|
|
||||||
|
if ~( (isa(volData, 'gpuArray') && strcmp(classUnderlying(volData), 'single')) || ...
|
||||||
|
isa(volData, 'single') ) || ~isreal(volData)
|
||||||
|
error('Only single precision real input array supported')
|
||||||
|
end
|
||||||
|
if ~isempty(r.deformation_fields)
|
||||||
|
assert(any(numel(r.deformation_fields) == [3,6]), 'Deformation field expected as 3x1 or 6x1 cell array')
|
||||||
|
for i = 1:numel( r.deformation_fields)
|
||||||
|
if ~( (isa(r.deformation_fields{i}, 'gpuArray') && strcmp(classUnderlying(r.deformation_fields{i}), 'single')) || ...
|
||||||
|
isa(r.deformation_fields{i}, 'single'))
|
||||||
|
error('Only single precision for deformation fields is supported')
|
||||||
|
end
|
||||||
|
r.deformation_fields{i} = gpuArray(r.deformation_fields{i}); % move on GPU, they are usually small
|
||||||
|
end
|
||||||
|
r.deformation_fields = r.deformation_fields' ; % transpose to that array(:) results in sorted field
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
gpu = gpuDevice();
|
||||||
|
if ~isempty(r.GPU) && gpu.Index ~= r.GPU(1)
|
||||||
|
% switch and !! reset !! GPU
|
||||||
|
if isa(volData, 'gpuArray'), error('Switching GPUs will reset content'); end
|
||||||
|
gpu = gpuDevice(r.GPU(1));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
split = ceil(max(1,split));
|
||||||
|
if ismatrix(volData)
|
||||||
|
split = [split([1, min(2,end)]),1];
|
||||||
|
assert(all(size(volData)==[cfg.iVolX,cfg.iVolY]), 'Wrong inputs size')
|
||||||
|
else
|
||||||
|
assert(all(size(volData)==[cfg.iVolX,cfg.iVolY,cfg.iVolZ]), 'Wrong inputs size')
|
||||||
|
end
|
||||||
|
|
||||||
|
keep_on_GPU = isa(volData, 'gpuArray') || r.keep_on_GPU;
|
||||||
|
|
||||||
|
%% backprojector that allows to split the full volume into smaller pieces
|
||||||
|
assert(all(size(vectors,2)==12), 'Wrong "vectors" size')
|
||||||
|
assert(~isempty(vectors), 'Empty input "vectors"')
|
||||||
|
assert(cfg.iVolX*cfg.iVolY*cfg.iVolZ > 0, 'Inputs volume is empty');
|
||||||
|
assert(cfg.iProjU*cfg.iProjV*cfg.iProjAngles > 0, 'Projections are empty');
|
||||||
|
|
||||||
|
% be sure that ASTRA wrapper is feeded by doubles !!
|
||||||
|
for i = fieldnames(cfg)'
|
||||||
|
cfg.(i{1}) = double(cfg.(i{1}));
|
||||||
|
end
|
||||||
|
vectors = double(vectors);
|
||||||
|
split=double(split);
|
||||||
|
|
||||||
|
|
||||||
|
cfg.iProjAngles = size(vectors,1);
|
||||||
|
|
||||||
|
assert(cfg.iProjAngles > 1, 'Number of processed angles must be > 1')
|
||||||
|
|
||||||
|
|
||||||
|
% fix if the number of projections is > 1024, or arrays are too large
|
||||||
|
Nproj_groups = max(1,ceil(max([cfg.iProjAngles/1024, ... % ASTRA constant memory limit
|
||||||
|
cfg.iProjU*cfg.iProjV*cfg.iProjAngles*4 / gpu.AvailableMemory, ... % availible memory limit
|
||||||
|
cfg.iProjU * cfg.iProjV * cfg.iProjAngles / double(intmax('int32'))]))); % maximal array size allowed by CUDA limit
|
||||||
|
if length(split) > 3
|
||||||
|
Nproj_groups = max(split(4), Nproj_groups);
|
||||||
|
end
|
||||||
|
|
||||||
|
if all(split == 1) && Nproj_groups == 1
|
||||||
|
if numel(volData)*4 > 1024e6 % exceeded texture memory
|
||||||
|
nsubVol = ceil(numel(volData)*4 / 1024e6);
|
||||||
|
nsubVol = 2^nextpow2(nsubVol);
|
||||||
|
% split = ceil([sqrt(nsubVol),sqrt(nsubVol),1]);
|
||||||
|
split = [1,1,nsubVol];
|
||||||
|
if r.verbose>0; disp(['Volume array is larger than 1024MB, auto-splitting ', num2str(split)]); end
|
||||||
|
else
|
||||||
|
%% in the simple case call ASTRA_GPU_wrapper directly
|
||||||
|
volData = gpuArray(volData);
|
||||||
|
% call ASTRA
|
||||||
|
projData = astra.ASTRA_GPU_wrapper('fp',volData, cfg, vectors,[],r.deformation_fields{:});
|
||||||
|
clear volData
|
||||||
|
if gpu.AvailableMemory < 4*numel(projData)
|
||||||
|
projData = gather(projData); % prevent out of memory errors during next step
|
||||||
|
end
|
||||||
|
projData = astra2matlab(projData);
|
||||||
|
if ~keep_on_GPU; projData = gather(projData); end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% otherwise prepare data for split and call ASTRA_GPU_wrapper on subvolumes
|
||||||
|
|
||||||
|
|
||||||
|
if isscalar(split)
|
||||||
|
split = split .* ones(ndims(volData),1);
|
||||||
|
end
|
||||||
|
assert(numel(volData)*4/prod(split) <= 1024e6, 'Volume array exceeded 1024MB, use more splitting')
|
||||||
|
|
||||||
|
Nvol_full = size(volData);
|
||||||
|
if numel(Nvol_full)<3
|
||||||
|
Nvol_full(3)=1;
|
||||||
|
end
|
||||||
|
Nvol_sub = Nvol_full'./reshape(split(1:3),[],1);
|
||||||
|
|
||||||
|
assert(all(mod(Nvol_sub,1)==0), sprintf('Volume size %ix%ix%i is not dividable by split %ix%ix%i',size(volData),split(1:3)))
|
||||||
|
|
||||||
|
|
||||||
|
if ismatrix(volData)
|
||||||
|
split(3) = 1;
|
||||||
|
Nvol_sub(3) = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
cfg.iVolX = cfg.iVolX/split(1);
|
||||||
|
cfg.iVolY = cfg.iVolY/split(2);
|
||||||
|
cfg.iVolZ = cfg.iVolZ/split(3);
|
||||||
|
|
||||||
|
cfg_orig = cfg;
|
||||||
|
|
||||||
|
if Nproj_groups > 1
|
||||||
|
% split the projections along the angles
|
||||||
|
for i = 1:Nproj_groups
|
||||||
|
ind = (1+(i-1)*ceil(cfg.iProjAngles/Nproj_groups)):i*ceil(cfg.iProjAngles/Nproj_groups);
|
||||||
|
ind = ind(ind <= cfg.iProjAngles);
|
||||||
|
vectors_tmp{i} = vectors(ind,:);
|
||||||
|
cfg_tmp{i} = cfg;
|
||||||
|
cfg_tmp{i}.iProjAngles = length(ind);
|
||||||
|
end
|
||||||
|
cfg = cfg_tmp; vectors = vectors_tmp;
|
||||||
|
else
|
||||||
|
Nproj_groups = 1;
|
||||||
|
cfg = {cfg};
|
||||||
|
vectors = {vectors};
|
||||||
|
end
|
||||||
|
clear ind
|
||||||
|
|
||||||
|
|
||||||
|
if r.verbose > 1
|
||||||
|
fprintf('Size of the full volume: %i %i %i\n', size(volData))
|
||||||
|
fprintf('Size of the subvolume: %i %i %i\n', Nvol_sub)
|
||||||
|
fprintf('Size of the one sinogram block: %i %i %i\n', cfg{1}.iProjU, cfg{1}.iProjV, cfg{1}.iProjAngles)
|
||||||
|
end
|
||||||
|
|
||||||
|
%%!!!! note that in rare cases astra my fail if sinogram width is too small
|
||||||
|
|
||||||
|
assert(prod(Nvol_sub) * 4 <= 1024e6, 'Volume exceeded maximal size of texture 1024MB')
|
||||||
|
|
||||||
|
% estimate required memory + (use only if 2x more memory is available)
|
||||||
|
required_mem = 2*(prod(Nvol_sub)*(2+~isa(volData, 'gpuArray')) + cfg_orig.iProjU * cfg_orig.iProjV * cfg_orig.iProjAngles )*4;
|
||||||
|
% keep projections on GPU only of there is enough memory
|
||||||
|
keep_projections_on_GPU = Nproj_groups == 1 || gpu.AvailableMemory > required_mem;
|
||||||
|
|
||||||
|
if cfg{1}.iProjU * cfg{1}.iProjV * cfg{1}.iProjAngles > intmax('int32')
|
||||||
|
error('Projection size exceeded maximum size allowed on GPU')
|
||||||
|
end
|
||||||
|
if (keep_on_GPU || prod(split(1:3)) == 1) && numel(volData) < intmax('int32') % keep volume on GPU
|
||||||
|
volData = gpuArray(volData);
|
||||||
|
end
|
||||||
|
|
||||||
|
inParpool = ~isempty(getCurrentTask());
|
||||||
|
iter = 1;
|
||||||
|
for m = 1:Nproj_groups
|
||||||
|
% split angularly (solve smaller groups of angles)
|
||||||
|
% allocate memory for the projections
|
||||||
|
projData{m} = gpuArray.zeros(cfg{m}.iProjU, cfg{m}.iProjV, cfg{m}.iProjAngles, 'single');
|
||||||
|
% split into volume cubes
|
||||||
|
for i = 1:split(1)
|
||||||
|
for j = 1:split(2)
|
||||||
|
for k = 1:split(3)
|
||||||
|
if r.verbose > 0
|
||||||
|
progressbar(iter, prod(split(1:3))*Nproj_groups+1, 20);
|
||||||
|
end
|
||||||
|
pos = [i,j,k];
|
||||||
|
for n = 1:3
|
||||||
|
ind{n} = (1+(pos(n)-1)*Nvol_sub(n)):(pos(n)*Nvol_sub(n));
|
||||||
|
%% find optimal shift of the subvolume
|
||||||
|
if mod(split(n),2)==1 %% odd
|
||||||
|
shift(n) = (pos(n) - ceil(split(n)/2))*Nvol_sub(n);
|
||||||
|
else
|
||||||
|
shift(n) = (pos(n) - ceil(split(n)/2)-1/2)*Nvol_sub(n);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% extract subvolume to be processed
|
||||||
|
if any(split(1:3)~=1) && isa(volData, 'gpuArray')
|
||||||
|
vol_small = volData(ind{:}); % take only small subvolume
|
||||||
|
elseif any(split(1:3)~=1)
|
||||||
|
vol_small = zeros(Nvol_sub','single');
|
||||||
|
utils.get_from_3D_projection(vol_small,volData,[ind{1}(1),ind{2}(1)]-1,ind{3});
|
||||||
|
else
|
||||||
|
vol_small = volData; % avoid data copying of possible
|
||||||
|
end
|
||||||
|
vol_small = gpuArray(vol_small);
|
||||||
|
|
||||||
|
% split deformation field for nonrigid tomography
|
||||||
|
if ~isempty(r.deformation_fields)
|
||||||
|
for ii = 1:3
|
||||||
|
N_deform = size(r.deformation_fields{ii}) ./ reshape(split(1:3),[],1)';
|
||||||
|
for jj = 1:3
|
||||||
|
ind_def{jj} = linspace(1+(pos(jj)-1)*N_deform(jj), pos(jj)*N_deform(jj), size(r.deformation_fields{ii},jj));
|
||||||
|
end
|
||||||
|
[X,Y,Z]= meshgrid(ind_def{:});
|
||||||
|
deformation_fields_sub{ii} = interp3(r.deformation_fields{ii},X,Y,Z);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
deformation_fields_sub = {};
|
||||||
|
end
|
||||||
|
|
||||||
|
vec = vectors{m};
|
||||||
|
vec(:,4:6) = bsxfun(@minus, vec(:,4:6), shift);
|
||||||
|
|
||||||
|
req_mem = 2*numel(vol_small)*4 ;
|
||||||
|
if gpu.AvailableMemory < req_mem
|
||||||
|
!nvidia-smi
|
||||||
|
whos
|
||||||
|
error('Too low GPU memory, avail: %3.2gGB / req: %3.2gGB, GPU %i/%i, projection group %i/%i, keep_proj_on_GPU=%i', gpu.AvailableMemory/1e9,req_mem/1e9, gpu.Index, gpuDeviceCount, m , Nproj_groups, keep_projections_on_GPU)
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
% avoid memory allocation, write directly to projData{m} -> no output arguments are needed
|
||||||
|
astra.ASTRA_GPU_wrapper('fp',vol_small, cfg{m}, vec,projData{m}, deformation_fields_sub{:});
|
||||||
|
vol_small = []; % soft mem clean
|
||||||
|
catch err
|
||||||
|
if strcmpi(err.identifier,'parallel:gpu:array:OOM')
|
||||||
|
warning('Out of memory on GPU %i, try reset GPU or split the array onto smaller blocks', gpu.Index)
|
||||||
|
gpuDevice
|
||||||
|
reset(gpuDevice)
|
||||||
|
end
|
||||||
|
|
||||||
|
rethrow(err)
|
||||||
|
end
|
||||||
|
|
||||||
|
iter = iter+1;
|
||||||
|
if r.verbose>0
|
||||||
|
progressbar(iter, prod(split(1:3))*Nproj_groups+1, 20);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ~keep_projections_on_GPU
|
||||||
|
projData{m} = gather(projData{m});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
clear volData vol_small
|
||||||
|
|
||||||
|
|
||||||
|
% permute / concatenate
|
||||||
|
if gpu.AvailableMemory < 4*numel(projData{1})*max(2,Nproj_groups)
|
||||||
|
projData = gather_all(projData);
|
||||||
|
end
|
||||||
|
|
||||||
|
projData = astra2matlab(projData);
|
||||||
|
|
||||||
|
if gpu.AvailableMemory < 8*numel(projData{1})*Nproj_groups
|
||||||
|
projData = gather_all(projData);
|
||||||
|
end
|
||||||
|
% concatenate the projected data align the angular (3rd) axis
|
||||||
|
projData = merge_projections(projData);
|
||||||
|
|
||||||
|
if ~keep_on_GPU
|
||||||
|
projData = gather(projData);
|
||||||
|
elseif numel(projData) < intmax('int32') && gpu.AvailableMemory < 4*numel(projData)
|
||||||
|
% return to GPU if requested by 'keep_on_GPU' parameter
|
||||||
|
projData = gpuArray(projData);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function x = gather_all(x)
|
||||||
|
for i = 1:length(x)
|
||||||
|
x{i} = gather(x{i});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function projData = merge_projections(projData_blocks)
|
||||||
|
Nblocks = length(projData_blocks);
|
||||||
|
if Nblocks > 1
|
||||||
|
if isa(projData_blocks{1}, 'gpuArray')
|
||||||
|
projData = cat(3, projData_blocks{:});
|
||||||
|
else
|
||||||
|
% faster and more memory efficient version
|
||||||
|
proj_size = [size(projData_blocks{1},1),size(projData_blocks{1},2),sum(cellfun(@(x)size(x,3), projData_blocks))];
|
||||||
|
for ii = 1:10
|
||||||
|
try
|
||||||
|
projData = zeros(proj_size, 'single');
|
||||||
|
break
|
||||||
|
catch err
|
||||||
|
end
|
||||||
|
pause(1)
|
||||||
|
end
|
||||||
|
if ii == 10
|
||||||
|
warning('Unsufficient memory to allocate %3.2gGB RAM', prod(proj_size)*4/1e9)
|
||||||
|
utils.check_available_memory
|
||||||
|
rethrow(err)
|
||||||
|
end
|
||||||
|
offset = 0;
|
||||||
|
for ii = 1:Nblocks
|
||||||
|
tomo.set_to_array(projData, projData_blocks{ii}, offset);
|
||||||
|
offset = offset + size(projData_blocks{ii},3);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
projData = projData_blocks{1};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
% example script for ASTRA wrappers
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%
|
||||||
|
% recompile commands
|
||||||
|
% (Linux, GCC 4.8.5) mexcuda -outdir private ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper/util3d.cu ASTRA_GPU_wrapper/par3d_fp.cu ASTRA_GPU_wrapper/par3d_bp.cu
|
||||||
|
% (Windows) mexcuda -outdir private ASTRA_GPU_wrapper\ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper\util3d.cu ASTRA_GPU_wrapper\par3d_fp.cu ASTRA_GPU_wrapper\par3d_bp.cu
|
||||||
|
|
||||||
|
|
||||||
|
% volume settings
|
||||||
|
Npix_vol = [300, 300, 100] ;
|
||||||
|
Nangles = 400;
|
||||||
|
Npix_proj = [400, 400];
|
||||||
|
|
||||||
|
% create "data"
|
||||||
|
angles = linspace(0, 360, Nangles);
|
||||||
|
lamino_angle = 60;
|
||||||
|
volData = ones(Npix_vol, 'single');
|
||||||
|
|
||||||
|
% generate geometry
|
||||||
|
[cfg, vectors] = astra.ASTRA_initialize(Npix_vol, Npix_proj, angles, lamino_angle);
|
||||||
|
% find optimal split, for small volumes below 600^3 no split is needed
|
||||||
|
split = astra.ASTRA_find_optimal_split(cfg);
|
||||||
|
|
||||||
|
% generate projections
|
||||||
|
projData = astra.Ax_partial(volData, cfg, vectors, split);
|
||||||
|
|
||||||
|
figure(1)
|
||||||
|
% plot the projections
|
||||||
|
subplot(1,2,1)
|
||||||
|
plotting.imagesc3D(projData); axis off image; colormap bone
|
||||||
|
title('Angular geometry')
|
||||||
|
|
||||||
|
% do backprojection projections !!! not FBP !!!
|
||||||
|
backprojData = astra.Atx_partial(projData, cfg, vectors, split);
|
||||||
|
|
||||||
|
|
||||||
|
% generate rotation matrix, note that the expected angles needs to be
|
||||||
|
% adjusted to provide same results are the previous example
|
||||||
|
R3 = utils.get_rotation_matrix_3D((90-lamino_angle)*ones(Nangles,1), -angles, zeros(Nangles,1));
|
||||||
|
|
||||||
|
% generate geometry
|
||||||
|
[cfgR, vectorsR] = astra.ASTRA_initialize(Npix_vol, Npix_proj, R3);
|
||||||
|
|
||||||
|
% generate projections
|
||||||
|
projDataR = astra.Ax_partial(volData, cfgR, vectorsR, split);
|
||||||
|
|
||||||
|
figure(1)
|
||||||
|
% plot the projections
|
||||||
|
subplot(1,2,2)
|
||||||
|
% plot the projections
|
||||||
|
plotting.imagesc3D(projDataR); axis off image; colormap bone
|
||||||
|
title('Rotation matrix geometry')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
% IRADON_GPU_WRAPPER back projector that allows to split the full volume
|
||||||
|
% into smaller pieces, tomography projector is based on ASTRA toolbox can be used
|
||||||
|
% either for data in RAM or on GPU (automatically decided from class of volData)
|
||||||
|
%
|
||||||
|
% vol = iradon_gpu_wrapper(sinogram, cfg, vectors)
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% **projData - array Nlayers x width_sinogram x Nangles of back-projected data
|
||||||
|
% **cfg - config structure generated by ASTRA_initialize
|
||||||
|
% **vectors - orientation of projections generated by ASTRA_initialize
|
||||||
|
% Outputs:
|
||||||
|
% ++vol - backprojected volume
|
||||||
|
%
|
||||||
|
% recompile commands
|
||||||
|
% (Linux) mexcuda -largeArrayDims -outdir private ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper/util3d.cu ASTRA_GPU_wrapper/par3d_fp.cu ASTRA_GPU_wrapper/par3d_bp.cu
|
||||||
|
% (Windows) mexcuda -largeArrayDims -outdir private ASTRA_GPU_wrapper\ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper\util3d.cu ASTRA_GPU_wrapper\par3d_fp.cu ASTRA_GPU_wrapper\par3d_bp.cu
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function vol = iradon_gpu_wrapper(sinogram, cfg, vectors)
|
||||||
|
vol = ASTRA_GPU_wrapper('bp', sinogram, cfg, vectors);
|
||||||
|
end
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
% FUNCTION full_array = add_to_3D(full_array, small_array, position)
|
||||||
|
% add one small 3D block into large 3D array
|
||||||
|
% Inputs:
|
||||||
|
% full_array
|
||||||
|
% small_array
|
||||||
|
% position - offset from (1,1,1) coordinate in pixels
|
||||||
|
|
||||||
|
% *-----------------------------------------------------------------------*
|
||||||
|
% | |
|
||||||
|
% | Except where otherwise noted, this work is licensed under a |
|
||||||
|
% | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
% | International (CC BY-NC-SA 4.0) license. |
|
||||||
|
% | |
|
||||||
|
% | Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
% | |
|
||||||
|
% | Author: CXS group, PSI |
|
||||||
|
% *-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
%
|
||||||
|
%
|
||||||
|
%
|
||||||
|
function full_array = add_to_3D(full_array, small_array, position)
|
||||||
|
|
||||||
|
position = round(position);
|
||||||
|
N_f = size(full_array);
|
||||||
|
N_s = size(small_array);
|
||||||
|
|
||||||
|
for i = 1:ndims(full_array)
|
||||||
|
ind_f{i} = unique(min(N_f(i),max(1,position(i)+(1:N_s(i)))));
|
||||||
|
ind_s{i} = unique(min(N_s(i),max(1,ind_f{i}-position(i))));
|
||||||
|
end
|
||||||
|
|
||||||
|
full_array(ind_f{:}) = full_array(ind_f{:}) + small_array(ind_s{:});
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
% FUNCTION sinogram = astra2matlab(sinogram)
|
||||||
|
% simple function to reshape sinogram from ASTRA (C++) order to Matlab (FORTRAN) order
|
||||||
|
% Inputs:
|
||||||
|
% sinogram - real value sinogram
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
%
|
||||||
|
|
||||||
|
function sinogram = astra2matlab(sinogram)
|
||||||
|
% simple function to reshape sinogram from ASTRA (C++) order to Matlab (FORTRAN) order
|
||||||
|
|
||||||
|
if isnumeric(sinogram)
|
||||||
|
[U,V,A] = size(sinogram);
|
||||||
|
sinogram = permute(reshape(sinogram, [U,A,V]), [3,1,2]);
|
||||||
|
elseif iscell(sinogram)
|
||||||
|
for ii = 1:length(sinogram)
|
||||||
|
sinogram{ii} = astra2matlab(sinogram{ii});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
% FUNCTION sinogram = astra2matlab(sinogram)
|
||||||
|
% simple function to reshape sinogram from Matlab (FORTRAN) order to ASTRA (C++) order
|
||||||
|
% Inputs:
|
||||||
|
% sinogram - real value sinogram
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
%
|
||||||
|
|
||||||
|
|
||||||
|
function sinogram = matlab2astra(sinogram)
|
||||||
|
|
||||||
|
if isnumeric(sinogram)
|
||||||
|
[U,V,A] = size(sinogram);
|
||||||
|
sinogram = reshape(permute(sinogram, [2,3,1]),[U,V,A]);
|
||||||
|
elseif iscell(sinogram)
|
||||||
|
for ii = 1:length(sinogram)
|
||||||
|
sinogram{ii} = matlab2astra(sinogram{ii});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
% OMNY_get_scan_numbers( OMNY_angles_file, scannums )
|
||||||
|
% OMNY_angles_file - File with Scan number, angle target, angle readout
|
||||||
|
% tomo_id - Index specifying the range of scan numbers
|
||||||
|
%
|
||||||
|
% out - returns scan numbers for tomo_id
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ out ] = OMNY_get_scan_numbers( OMNY_angles_file, tomo_id )
|
||||||
|
|
||||||
|
fid = fopen(OMNY_angles_file);
|
||||||
|
|
||||||
|
ln = fgetl(fid);
|
||||||
|
if numel(strsplit(ln, ' '))<=6
|
||||||
|
error('OMNY file does contain tomo_ids')
|
||||||
|
end
|
||||||
|
|
||||||
|
outmat = textscan(fid,'%f %f %f %f %f %f %s');
|
||||||
|
fclose(fid);
|
||||||
|
|
||||||
|
|
||||||
|
ind = find(outmat{4}==tomo_id);
|
||||||
|
out = outmat{1}(ind);
|
||||||
|
out = out';
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,229 @@
|
|||||||
|
% Call function without arguments for a detailed explanation of its use
|
||||||
|
|
||||||
|
% Filename: $RCSfile: beamstop_mask.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.8 $ $Date: 2011/08/23 17:17:53 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% remove a polygonic region from the valid pixel mask
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% This is a template. The coordinates of the polygon have to be manually
|
||||||
|
% edited.
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% May 19th 2010:
|
||||||
|
% add XyCoord and xCoord, yCoord command line parameters
|
||||||
|
%
|
||||||
|
% May 9th 2008: 1st documented version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ bmask_ind ] = beamstop_mask(filename,varargin)
|
||||||
|
import beamline.pilatus_valid_pixel_roi
|
||||||
|
import beamline.prep_valid_mask
|
||||||
|
import io.image_read
|
||||||
|
import plotting.display_valid_mask
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
% valid pixel mask
|
||||||
|
filename_valid_mask = '~/Data10/analysis/data/pilatus_valid_mask.mat';
|
||||||
|
% do not update the valid pixel mask
|
||||||
|
save_data = 0;
|
||||||
|
% figure number for display
|
||||||
|
fig_no = 220;
|
||||||
|
% mask corners
|
||||||
|
xy_coord = []; %#ok<NASGU>
|
||||||
|
x_coord = [];
|
||||||
|
y_coord = [];
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
display_help(filename_valid_mask,save_data,fig_no);
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
display_help(filename_valid_mask,save_data,fig_no);
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'SaveData'
|
||||||
|
save_data = value;
|
||||||
|
case 'FilenameValidMask'
|
||||||
|
filename_valid_mask = value;
|
||||||
|
case 'xyCoord'
|
||||||
|
xy_coord = value;
|
||||||
|
x_coord = xy_coord(:,1);
|
||||||
|
y_coord = xy_coord(:,2);
|
||||||
|
case 'xCoord'
|
||||||
|
x_coord = value;
|
||||||
|
case 'yCoord'
|
||||||
|
y_coord = value;
|
||||||
|
otherwise
|
||||||
|
vararg_remain{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg_remain{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% read file for test display
|
||||||
|
frame = image_read(filename,vararg_remain);
|
||||||
|
frame.data = double(frame.data);
|
||||||
|
dimensions = size(frame.data);
|
||||||
|
if (numel(dimensions) > 2)
|
||||||
|
frame.data = mean(frame.data,3);
|
||||||
|
dimensions = size(frame.data);
|
||||||
|
end
|
||||||
|
|
||||||
|
% get indices to pixels within beam stop
|
||||||
|
if ((isempty(x_coord)) || (isempty(y_coord)))
|
||||||
|
bmask_ind = 1:(dimensions(1)*dimensions(2));
|
||||||
|
else
|
||||||
|
[bmask] = uint8(1 - roipoly( dimensions(1), dimensions(2), x_coord, y_coord ));
|
||||||
|
bmask_ind = find(bmask == 0);
|
||||||
|
end
|
||||||
|
|
||||||
|
% plot the result
|
||||||
|
figure(5);
|
||||||
|
frame_plot = frame.data;
|
||||||
|
frame_plot(frame_plot < 1) = 1;
|
||||||
|
% plot the masked region with lower intensity
|
||||||
|
frame_plot(bmask_ind) = 0.1 * frame_plot(bmask_ind);
|
||||||
|
imagesc(log10(frame_plot));
|
||||||
|
axis xy;
|
||||||
|
axis equal;
|
||||||
|
axis tight;
|
||||||
|
colorbar;
|
||||||
|
title('beamstop mask shape');
|
||||||
|
|
||||||
|
% show the current valid pixel mask
|
||||||
|
display_valid_mask('FilenameValidMask',filename_valid_mask,'FigNo',fig_no+1,...
|
||||||
|
'NoHelp',1);
|
||||||
|
title('current valid pixel mask');
|
||||||
|
|
||||||
|
% load ind_valid, the indices of the valid pixels
|
||||||
|
fprintf('loading %s\n',filename_valid_mask);
|
||||||
|
load(filename_valid_mask);
|
||||||
|
% cut out the current region of interest
|
||||||
|
valid_mask = pilatus_valid_pixel_roi(valid_mask,'RoiSize',size(frame.data));
|
||||||
|
|
||||||
|
% remove beam-stop pixels from it
|
||||||
|
valid_mask.indices = setdiff(valid_mask.indices,bmask_ind); %#ok<NODEF>
|
||||||
|
|
||||||
|
if (save_data)
|
||||||
|
% create a backup of the mask
|
||||||
|
if (exist(filename_valid_mask,'file'))
|
||||||
|
filename_valid_mask_backup = [ filename_valid_mask '.bak' ];
|
||||||
|
fprintf('Copying the current mask %s to %s\n',filename_valid_mask,...
|
||||||
|
filename_valid_mask_backup);
|
||||||
|
copyfile(filename_valid_mask,filename_valid_mask_backup);
|
||||||
|
end
|
||||||
|
|
||||||
|
% save the updated mask
|
||||||
|
fprintf('saving updated mask %s\n',filename_valid_mask);
|
||||||
|
save(filename_valid_mask,'valid_mask');
|
||||||
|
|
||||||
|
% display the new mask
|
||||||
|
display_valid_mask('FilenameValidMask',filename_valid_mask,'FigNo',fig_no+2,...
|
||||||
|
'NoHelp',1);
|
||||||
|
else
|
||||||
|
% mark the valid pixels as 1, leave the invalid at 0
|
||||||
|
pframe = zeros(valid_mask.framesize);
|
||||||
|
pframe(valid_mask.indices) = 1;
|
||||||
|
|
||||||
|
% plot the result
|
||||||
|
figure(fig_no+2);
|
||||||
|
imagesc(pframe);
|
||||||
|
axis xy;
|
||||||
|
axis equal;
|
||||||
|
axis tight;
|
||||||
|
colorbar;
|
||||||
|
title('valid pixels');
|
||||||
|
title('updated valid pixel mask (not saved!)');
|
||||||
|
set(gcf,'Name','valid pixels');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [] = display_help(filename_valid_mask,save_data,fig_no)
|
||||||
|
|
||||||
|
fprintf('Usage:\n');
|
||||||
|
fprintf('%s(filename_for_display, [[<name>,<value>],...]);\n',mfilename)
|
||||||
|
fprintf('The specified file is used to display the beamstop mask with reduced intensity.\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''xyCoord'',[ x1 y1; x2 y2; ...] coordinates of the beamstop mask\n');
|
||||||
|
fprintf('''xCoord'',[ x1 x2 ...] x-coordinates of the beamstop mask, alternative to specifying xy pairs, may be useful if roipoly is used\n');
|
||||||
|
fprintf('''yCoord'',[ y1 y2 ...] y-coordinates of the beamstop mask, alternative to specifying xy pairs, may be useful if roipoly is used\n');
|
||||||
|
fprintf('''FilenameValidMask'',<path and filename> Matlab file with the valid pixel indices ind_valid,\n');
|
||||||
|
fprintf(' default is %s\n',filename_valid_mask);
|
||||||
|
fprintf('''SaveData'',<0-no,1-yes> 0 for displaying the result without updating the mask, default is %d\n',...
|
||||||
|
save_data);
|
||||||
|
fprintf('''FigNo'',<integer> number of the figure in which the result is displayed, default is %d\n',...
|
||||||
|
fig_no);
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('A valid pixel mask can be created using the macro prep_valid_mask.\n')
|
||||||
|
fprintf('You will find a valid pixel mask in %s but you may consider to measure a new one.\n',...
|
||||||
|
filename_valid_mask);
|
||||||
|
fprintf('\n');
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
% [mask_coord,bmask_ind] = choose_beamstop_mask(filename,varargin)
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [mask_coord,bmask_ind] = choose_beamstop_mask(filename,varargin)
|
||||||
|
import beamline.beamstop_mask
|
||||||
|
import plotting.image_show
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
% File with mask coordinates
|
||||||
|
filename_coord = '~/Data10/analysis/data/mask_coordinates.mat';
|
||||||
|
% border size
|
||||||
|
border = 3;
|
||||||
|
% save coordinates
|
||||||
|
save_coord = 1;
|
||||||
|
% select corrdinates
|
||||||
|
select_points = 1;
|
||||||
|
% do not read prevously saved coordinates
|
||||||
|
read_coord = 1;
|
||||||
|
% start with an empty set of coordinates
|
||||||
|
mask_coord = [];
|
||||||
|
bmask_ind = [];
|
||||||
|
% figure number for display
|
||||||
|
fig_no_sel = 555 ;
|
||||||
|
% run 'beamstop_mask' at the end
|
||||||
|
create_mask = 1;
|
||||||
|
% Arguments to be passed to imageshow
|
||||||
|
imageshow_args = {};
|
||||||
|
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('Usage:\n');
|
||||||
|
fprintf('%s(filename,[[<name>,<value>],...]);\n',mfilename);
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''Border'', size of the ''sticky'' edge border, default is %d, 0 to disable\n',border);
|
||||||
|
fprintf('''SaveCoord'',<0-no,1-yes> 1 for saving the coordinates, default is %d\n',save_coord);
|
||||||
|
fprintf('''FilenameCoord'',<path and filename> Matlab file with the mask coordinates,\n');
|
||||||
|
fprintf(' default is %s\n',filename_coord);
|
||||||
|
fprintf('''SelectPoints'',<0-no,1-yes> 1 for selecting the points in the image, default is %d\n',select_points);
|
||||||
|
fprintf(' if 0, points should be either read from the file or \n');
|
||||||
|
fprintf(' supplied as options for ''beamstop_mask'' function\n');
|
||||||
|
fprintf('''ReadCoord'',<0-no,1-yes> 1 for reading the coordinates from the file, default is %d\n',read_coord);
|
||||||
|
fprintf('''CreateMask'',<0-no,1-yes> 1 for running ''beamstop_mask'', default is %d\n',create_mask);
|
||||||
|
fprintf('''FigNoSel'',<integer> number of the figure in which the coordinates are selected, default is %d\n',...
|
||||||
|
fig_no_sel);
|
||||||
|
fprintf('''ImageShowArgs'', cell additional parameters to be passed to image_show, default is an empty cell {} \n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('Additional <name>,<value> pairs recognized by ''beamstop_mask'' can be specified.\n');
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
display_help(filename_coord,save_coord,create_mask,select_points,border,read_coord,fig_no_sel);
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'SaveCoord'
|
||||||
|
save_coord = value;
|
||||||
|
case 'Border'
|
||||||
|
border = value;
|
||||||
|
case 'SelectPoints'
|
||||||
|
select_points = value;
|
||||||
|
case 'ReadCoord'
|
||||||
|
read_coord = value;
|
||||||
|
case 'FilenameCoord'
|
||||||
|
filename_coord = value;
|
||||||
|
case 'FigNoSel'
|
||||||
|
fig_no_sel = value;
|
||||||
|
case 'xyCoord'
|
||||||
|
mask_coord = value;
|
||||||
|
case 'CreateMask'
|
||||||
|
create_mask = value;
|
||||||
|
case 'ImageShowArgs'
|
||||||
|
imageshow_args = value;
|
||||||
|
otherwise
|
||||||
|
vararg_remain{end+1} = name;
|
||||||
|
vararg_remain{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% Read the coordinates from the file
|
||||||
|
if (read_coord == 1)
|
||||||
|
if (exist(filename_coord,'file'))
|
||||||
|
load(filename_coord);
|
||||||
|
% don't use if there are less than two points in the mask
|
||||||
|
% makes it impossible to add new points
|
||||||
|
if size(mask_coord,1) < 2
|
||||||
|
mask_coord = [];
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fprintf('Mask coordinates file %s was not found.\n',filename_coord);
|
||||||
|
fprintf('Continuing with no starting mask.\n');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% select/change the mask coordinates in the image
|
||||||
|
if (select_points == 1)
|
||||||
|
|
||||||
|
[qq] = image_show(filename,'FigNo',fig_no_sel, imageshow_args{:});
|
||||||
|
|
||||||
|
% h=impoly(gca,mask_coord);
|
||||||
|
% mask_coord=getPosition(h);
|
||||||
|
% addNewPositionCallback(h,@(pos)eval('mask_coord=pos;'));
|
||||||
|
% % wait for the changes while the image is open
|
||||||
|
% waitfor(fig_no_sel)
|
||||||
|
msgbox({'Instructions:', '1) Create a closed polygon around the beamstop (don''t double-click when you finish)'...
|
||||||
|
, '2) Adjust the corners of polygon if needed',...
|
||||||
|
'3) Double-click on polygon to finish'},'Choose beamstop mask');
|
||||||
|
h = impoly(gca,mask_coord);
|
||||||
|
mask_coord = wait(h);
|
||||||
|
|
||||||
|
% move points to the edge
|
||||||
|
if border
|
||||||
|
im_dim(1) = size(qq.data,2);
|
||||||
|
im_dim(2) = size(qq.data,1);
|
||||||
|
|
||||||
|
for jj = 1:size(mask_coord,1)
|
||||||
|
for kk = 1:2
|
||||||
|
|
||||||
|
if mask_coord(jj,kk) < border
|
||||||
|
mask_coord(jj,kk) = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if abs(mask_coord(jj,kk) - im_dim(kk)) < border
|
||||||
|
mask_coord(jj,kk) = im_dim(kk);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% mask coordinates should be integers
|
||||||
|
mask_coord = round(mask_coord);
|
||||||
|
end
|
||||||
|
|
||||||
|
% save the mask coordinates file, if specified
|
||||||
|
if save_coord
|
||||||
|
% create a backup of the mask coordinates file
|
||||||
|
if (exist(filename_coord,'file'))
|
||||||
|
filename_coord_backup = [ filename_coord '.bak' ];
|
||||||
|
fprintf('Copying the current mask coordinates file %s to %s\n',filename_coord,...
|
||||||
|
filename_coord_backup);
|
||||||
|
copyfile(filename_coord,filename_coord_backup);
|
||||||
|
end
|
||||||
|
fprintf('saving updated mask coordinates file %s\n',filename_coord);
|
||||||
|
save(filename_coord,'mask_coord');
|
||||||
|
end
|
||||||
|
|
||||||
|
% run the beamstop_mask function, if specified
|
||||||
|
if create_mask
|
||||||
|
vararg_remain{end+1} = 'xyCoord';
|
||||||
|
vararg_remain{end+1} = mask_coord;
|
||||||
|
bmask_ind = beamstop_mask(filename,vararg_remain{:},imageshow_args{:});
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
%CREATE_MASK
|
||||||
|
% create a binary mask for the current figure
|
||||||
|
% The following arguments have to be given as name/value pairs. However,
|
||||||
|
% they can also be set within the GUI.
|
||||||
|
%
|
||||||
|
% *optional*
|
||||||
|
% ** mask initial mask; either a file, an array or a structure (indicies + asize)
|
||||||
|
% ** fig pass figure handle; default: current figure
|
||||||
|
% ** ind convert mask to indicies
|
||||||
|
% ** file save mask to disk; specify path + filename
|
||||||
|
%
|
||||||
|
% returns:
|
||||||
|
% ++ out 2D binary mask or structure containing the asize and the indicies
|
||||||
|
%
|
||||||
|
% EXAMPLE:
|
||||||
|
% img = io.image_read('~/Data10/pilatus_1/S00000-00999/S00170/*.cbf'); % load image stack
|
||||||
|
% plotting.imagesc3D(log10(img.data)); axis equal tight xy; % plot image stack
|
||||||
|
% beamline.create_mask(); % open the GUI and create the mask
|
||||||
|
%
|
||||||
|
% see also: beamline.mask2ind
|
||||||
|
|
||||||
|
% Academic License Agreement
|
||||||
|
%
|
||||||
|
% Source Code
|
||||||
|
%
|
||||||
|
% Introduction
|
||||||
|
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||||
|
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||||
|
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||||
|
%
|
||||||
|
% Terms and Conditions of the LICENSE
|
||||||
|
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||||
|
% hereinafter set out and until termination of this license as set forth below.
|
||||||
|
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||||
|
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||||
|
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||||
|
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||||
|
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||||
|
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||||
|
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||||
|
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||||
|
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||||
|
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||||
|
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||||
|
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||||
|
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||||
|
% another computing language:
|
||||||
|
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||||
|
% Scherrer Institut, Switzerland."
|
||||||
|
%
|
||||||
|
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||||
|
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||||
|
% (doi: 10.1126/science.1158573),
|
||||||
|
% for maximum likelihood:
|
||||||
|
% P. Thibault and M. Guizar-Sicairos, Maximum-likelihood refinement for coherent diffractive imaging, New J. Phys. 14, 063004 (2012).
|
||||||
|
% (doi: 10.1088/1367-2630/14/6/063004),
|
||||||
|
% for mixed coherent modes:
|
||||||
|
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||||
|
% and/or for multislice:
|
||||||
|
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||||
|
% (doi: 10.1364/OE.24.029089).
|
||||||
|
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||||
|
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||||
|
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||||
|
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||||
|
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||||
|
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||||
|
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||||
|
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||||
|
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||||
|
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||||
|
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||||
|
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||||
|
% the courts of Zürich, Switzerland.
|
||||||
|
|
||||||
|
function [out] = create_mask(varargin)
|
||||||
|
|
||||||
|
check_input_mask = @(x) ischar(x) || (isnumeric(x)|| islogical(x)) || isstruct(x);
|
||||||
|
|
||||||
|
par = inputParser;
|
||||||
|
par.addParameter('mask', [], check_input_mask)
|
||||||
|
par.addParameter('fig', [], @ishandle)
|
||||||
|
par.addParameter('ind', false, @islogical)
|
||||||
|
par.addParameter('file', [], @ischar)
|
||||||
|
par.parse(varargin{:})
|
||||||
|
vars = par.Results;
|
||||||
|
|
||||||
|
% Check screen size
|
||||||
|
try
|
||||||
|
scrsz = get(0,'ScreenSize');
|
||||||
|
catch
|
||||||
|
scrsz = [1 1 2560 1024];
|
||||||
|
end
|
||||||
|
|
||||||
|
% get fig
|
||||||
|
if isempty(vars.fig)
|
||||||
|
fig = gcf;
|
||||||
|
end
|
||||||
|
|
||||||
|
current_pos = fig.Position;
|
||||||
|
new_fig_pos(2:4) = current_pos(2:4);
|
||||||
|
|
||||||
|
if current_pos(1)+current_pos(3)/2 - scrsz(3)/2 > 0
|
||||||
|
% figure to the left
|
||||||
|
new_fig_pos(1) = current_pos(1)-current_pos(3);
|
||||||
|
else
|
||||||
|
% figure to the right
|
||||||
|
new_fig_pos(1) = current_pos(1)+current_pos(3);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% get axis
|
||||||
|
ax = gca;
|
||||||
|
% get current data size
|
||||||
|
if ~isempty(ax.Children)
|
||||||
|
asize = size(ax.Children.CData);
|
||||||
|
else
|
||||||
|
fig = gcf;
|
||||||
|
close(fig)
|
||||||
|
error('Failed to connect to figure instance.')
|
||||||
|
end
|
||||||
|
|
||||||
|
% prepare mask
|
||||||
|
if isempty(vars.mask)
|
||||||
|
mask = ones(asize);
|
||||||
|
else
|
||||||
|
if ischar(vars.mask)
|
||||||
|
% load a mask from disk
|
||||||
|
try
|
||||||
|
f = load(vars.mask);
|
||||||
|
mask = f.mask;
|
||||||
|
clear f
|
||||||
|
catch
|
||||||
|
fprintf('Failed to load mask. Using empty mask instead.\n')
|
||||||
|
mask = ones(asize);
|
||||||
|
end
|
||||||
|
elseif isnumeric(vars.mask) || islogical(vars.mask)
|
||||||
|
mask = vars.mask;
|
||||||
|
elseif isstruct(vars.mask)
|
||||||
|
mask = beamline.ind2mask(vars.mask);
|
||||||
|
else
|
||||||
|
error('Unknown mask data format.')
|
||||||
|
end
|
||||||
|
assert(all(size(mask)==asize), 'Mask size and data size does not match')
|
||||||
|
|
||||||
|
end
|
||||||
|
pause(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
% apply mask
|
||||||
|
CData_orig = ax.Children.CData;
|
||||||
|
if ax.isprop('img')
|
||||||
|
img_orig = ax.img;
|
||||||
|
ax.img = ax.img .* mask;
|
||||||
|
mask_dims = ndims(img_orig);
|
||||||
|
if mask_dims==3
|
||||||
|
mask3D = true;
|
||||||
|
else
|
||||||
|
mask3D = false;
|
||||||
|
end
|
||||||
|
mask_dims = size(img_orig,3);
|
||||||
|
else
|
||||||
|
mask3D = false;
|
||||||
|
mask_dims = 1;
|
||||||
|
end
|
||||||
|
ax.Children.CData = ax.Children.CData .* mask;
|
||||||
|
|
||||||
|
s = create_mask_GUI_export('mask', mask, 'mask3D', mask3D, 'mask_dims', mask_dims);
|
||||||
|
s.figure1.UserData.ax = ax;
|
||||||
|
s.figure1.UserData.fig = fig;
|
||||||
|
s.figure1.UserData.asize = asize;
|
||||||
|
s.figure1.UserData.CData = CData_orig;
|
||||||
|
if ax.isprop('img')
|
||||||
|
s.figure1.UserData.img_orig = img_orig;
|
||||||
|
if s.figure1.UserData.mask3D
|
||||||
|
orig_fig_listener = s.figure1.UserData.ax.slider_handle.listener('Value','PostSet',@(src, evnt)orig_fig_slice_update(s));
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
while ~s.figure1.UserData.done
|
||||||
|
mask = s.figure1.UserData.mask;
|
||||||
|
pause(0.1)
|
||||||
|
end
|
||||||
|
|
||||||
|
set(groot,'CurrentFigure',fig);
|
||||||
|
ax.Children.CData = CData_orig;
|
||||||
|
if ax.isprop('img')
|
||||||
|
ax.img = img_orig;
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
if ~isprop(s, 'figure1')
|
||||||
|
fprintf('Lost connection to GUI.\n')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
if s.figure1.UserData.mask3D
|
||||||
|
delete(orig_fig_listener)
|
||||||
|
end
|
||||||
|
delete(s.figure1)
|
||||||
|
catch
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% if needed, convert 2D mask to indicies
|
||||||
|
if vars.ind
|
||||||
|
out = beamline.mask2ind(mask);
|
||||||
|
else
|
||||||
|
out = mask;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% save to disk
|
||||||
|
if ~isempty(vars.file)
|
||||||
|
valid_mask = out;
|
||||||
|
try
|
||||||
|
utils.savefast_safe(vars.file, 'valid_mask');
|
||||||
|
catch
|
||||||
|
fprintf('Failed to save mask to disk.');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function orig_fig_slice_update(s)
|
||||||
|
val = s.figure1.UserData.ax.slider_handle.Value;
|
||||||
|
set(s.axes1.slider_handle, 'Value', val);
|
||||||
|
set(s.axes1.edit_handle, 'String', num2str(val));
|
||||||
|
s.axes1.update_fig(s.axes1);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
% function mark = energy2mark(E,calib_file)
|
||||||
|
% After calibrating using beamline.mark_interpolation_setup you can use
|
||||||
|
% this function to input a desired energy and a linear interpolation will
|
||||||
|
% determine and give you the mark
|
||||||
|
% Inputs
|
||||||
|
% E Array of energies in keV
|
||||||
|
% calib_file Name of the file with the calibration
|
||||||
|
%
|
||||||
|
% Outputs
|
||||||
|
% mark Array of marks corresponding to input energies
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function mark = energy2mark(E,calib_file)
|
||||||
|
|
||||||
|
if ~nargin<2
|
||||||
|
calib_file = 'mark_calib.mat';
|
||||||
|
end
|
||||||
|
|
||||||
|
calib = load(calib_file);
|
||||||
|
|
||||||
|
mark = interp1(calib.E,calib.marks,E,'linear');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
% [varargout] = find_capillary(varargin)
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [varargout] = find_capillary(varargin)
|
||||||
|
import io.spec_read
|
||||||
|
|
||||||
|
vararg = varargin;
|
||||||
|
vararg{end+1} = 'UnhandledParError';
|
||||||
|
vararg{end+1} = 0;
|
||||||
|
[S] = spec_read(vararg{1},vararg{2:end});
|
||||||
|
vararg = vararg(2:end);
|
||||||
|
for jj = 1:2:length(vararg)
|
||||||
|
name = vararg{jj};
|
||||||
|
value = vararg{jj+1};
|
||||||
|
switch name
|
||||||
|
case 'Counter'
|
||||||
|
counter = S.(value);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
arrout = regexp(S.S,' +','split');
|
||||||
|
motor = S.(arrout{4});
|
||||||
|
threshold = .1 * max(counter);
|
||||||
|
|
||||||
|
motor = motor(counter>threshold);
|
||||||
|
counter = counter(counter>threshold);
|
||||||
|
|
||||||
|
|
||||||
|
threshold = .9 * max(counter);
|
||||||
|
i_i = find(counter>threshold,1,'first');
|
||||||
|
i_f = find(counter>threshold,1,'last');
|
||||||
|
|
||||||
|
p = polyfit(motor(counter>threshold),counter(counter>threshold),1);
|
||||||
|
dy = polyval(p,motor)-counter;
|
||||||
|
COM = sum(motor(i_i:i_f).*dy(i_i:i_f))/sum(dy(i_i:i_f));
|
||||||
|
|
||||||
|
do_plot = 0;
|
||||||
|
if (do_plot)
|
||||||
|
figure(1)
|
||||||
|
plot(motor,dy)
|
||||||
|
hold on
|
||||||
|
area(motor(i_i:i_f),dy(i_i:i_f))
|
||||||
|
plot([1 1]*COM,[0 max(dy(i_i:i_f))],'r','LineWidth',2)
|
||||||
|
hold off
|
||||||
|
end
|
||||||
|
|
||||||
|
varargout{1} = COM;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
% this script contains the necessary loop for 'find_capillary.m' to be called
|
||||||
|
% as function of 'spec'
|
||||||
|
% written by (last change: 2011-06-16)
|
||||||
|
% in case of bugs, problems, and suggestions for improvements, please contact
|
||||||
|
% CXS group
|
||||||
|
%
|
||||||
|
% note that EPICS communication works only on local machines at the beamline, i.e.,
|
||||||
|
% NOT on the compute nodes
|
||||||
|
% run this (or related scripts that use EPICS for communication), for instance, on
|
||||||
|
% x12sa-cons-1
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
lastscan = 0;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
scall = sprintf('caget ''X12SA-ES1-DOUBLE-00''');
|
||||||
|
[err,io] = system(scall);
|
||||||
|
arrout = regexp(io,' +','split');
|
||||||
|
scannr = str2double(arrout{2});
|
||||||
|
if (scannr > lastscan)
|
||||||
|
try
|
||||||
|
COM = +beamline.find_capillary('..','ScanNr',scannr,'Counter','diode')
|
||||||
|
catch
|
||||||
|
fprintf('Failed find capillary, pausing 5 sec and retrying\n')
|
||||||
|
pause(5)
|
||||||
|
COM = +beamline.find_capillary('..','ScanNr',scannr,'Counter','diode')
|
||||||
|
end
|
||||||
|
else
|
||||||
|
pause(1);
|
||||||
|
end
|
||||||
|
scall = sprintf('caputq X12SA-ES1-DOUBLE-02 %f',COM);
|
||||||
|
[err,io] = system(scall);
|
||||||
|
scall = sprintf('caputq X12SA-ES1-DOUBLE-01 %d',scannr);
|
||||||
|
[err,io] = system(scall);
|
||||||
|
lastscan = scannr;
|
||||||
|
end
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
% function specDatFile = find_specDatFile(specDatFile)
|
||||||
|
% find location of the spec file in the provided folder / path
|
||||||
|
% if the variable specDatFile is not a complete path to a file
|
||||||
|
% try to guess where a spec data file can be found, by
|
||||||
|
% - look for directories called 'spec' or 'dat-files'
|
||||||
|
% - look for files called '*.dat'
|
||||||
|
% - take the newest one
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function specDatFile = find_specDatFile(specDatFile)
|
||||||
|
while (exist(specDatFile,'file') ~= 2)
|
||||||
|
% if the variable specDatFile is not a complete path to a file
|
||||||
|
% try to guess where a spec data file can be found, by
|
||||||
|
% - look for directories called 'spec' or 'dat-files'
|
||||||
|
% - look for files called '*.dat'
|
||||||
|
% - take the newest one
|
||||||
|
compare_str = specDatFile;
|
||||||
|
fname = dir(specDatFile);
|
||||||
|
if (exist(specDatFile,'dir'))
|
||||||
|
if (specDatFile(end) ~= '/')
|
||||||
|
specDatFile = strcat(specDatFile,'/');
|
||||||
|
end
|
||||||
|
|
||||||
|
for ii=1:numel(fname)
|
||||||
|
if (regexp(fname(ii).name,'.dat$'))
|
||||||
|
specDatFile = strcat(specDatFile,'*.dat');
|
||||||
|
fname = [];
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for ii=1:numel(fname)
|
||||||
|
if (strcmp(fname(ii).name,'dat-files'))
|
||||||
|
specDatFile = strcat(specDatFile,fname(ii).name);
|
||||||
|
fname = [];
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for ii=1:numel(fname)
|
||||||
|
if (strcmp(fname(ii).name,'specES1'))
|
||||||
|
specDatFile = strcat(specDatFile,fname(ii).name);
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
if (strcmp(fname(ii).name,'spec'))
|
||||||
|
specDatFile = strcat(specDatFile,fname(ii).name);
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if (numel(fname)>0)
|
||||||
|
[~,ii] = max(cell2mat({fname.datenum}));
|
||||||
|
specDatFile = regexprep(specDatFile,'\*\.dat$',fname(ii).name);
|
||||||
|
else
|
||||||
|
error('''%s'' cannot be found.', specDatFile);
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (strcmp(specDatFile,compare_str))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~exist(specDatFile, 'file') || exist(specDatFile, 'dir')
|
||||||
|
error('Spec dat file not found in the provided path %s', specDatFile)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,380 @@
|
|||||||
|
import beamline.identify_eaccount
|
||||||
|
import beamline.radial_integ
|
||||||
|
import io.spec_read
|
||||||
|
import utils.get_fil_trans
|
||||||
|
import utils.get_gas_trans
|
||||||
|
import utils.pixel_to_q
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% EDIT HERE:
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
% where the data is saved (Data10, Data20, p-account)
|
||||||
|
raw_data = '~/Data10';
|
||||||
|
e_account = identify_eaccount;
|
||||||
|
%uncomment for using during online analysis in the e-account
|
||||||
|
BasePath = raw_data;
|
||||||
|
%uncomment for using during offline analysis
|
||||||
|
% BasePath= sprintf('%s/%s', raw_data, e_account);
|
||||||
|
%_____________________________________________________________
|
||||||
|
% needed for flux calculation using bim2
|
||||||
|
use_bim2 = 1;
|
||||||
|
% Remember to activate Elletra
|
||||||
|
scan_dark=43; % scan with closed shutter (set offset in Elettra device such that counts are almost zero)
|
||||||
|
scan=44; % scan with open shutter and BIM2 diode in the beam
|
||||||
|
air_path = 10; % air path distance between the exposure box window and the sample in mm
|
||||||
|
Elettra_bitmode = 24;
|
||||||
|
Elettra_range = 2.5e-3; %[A]
|
||||||
|
%_____________________________________________________________
|
||||||
|
% needed for flux calculation using the glassy carbon L14
|
||||||
|
use_GCL14 = 1;
|
||||||
|
%glassy carbon
|
||||||
|
Glassy_carbon=34; % the scan number of glassy carbon
|
||||||
|
%air scattering
|
||||||
|
Air = 42; %scan number of air scattering
|
||||||
|
DB = 42; %direct beam, use air scattering in case there is no direct beam measurement
|
||||||
|
%parameters for calculating the flux
|
||||||
|
DetDist_mm = 2.1397e3; %in mm
|
||||||
|
used_bs = 1; % 1 for diode in the beam stop
|
||||||
|
% 2 for cyberstar diode
|
||||||
|
%_____________________________________________________________
|
||||||
|
% also scale WAXS data?
|
||||||
|
use_WAXS = 0; % 1 to scale the WAXS data, 0 not used
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% calculations
|
||||||
|
if use_bim2
|
||||||
|
% calculation
|
||||||
|
%read the spec files
|
||||||
|
S=spec_read(BasePath,'ScanNr',scan);
|
||||||
|
S_dark=spec_read(BasePath,'ScanNr',scan_dark);
|
||||||
|
|
||||||
|
%read the energy in keV
|
||||||
|
energy = S_dark.mokev;
|
||||||
|
|
||||||
|
%other important parameters
|
||||||
|
epsilon_Si=3.66; % energy required to generate an electron-hole pair in Si [eV]
|
||||||
|
e_charge=1.6e-19; %electron change [C]
|
||||||
|
|
||||||
|
% from http://henke.lbl.gov/optical_constants/filter2.html, considering
|
||||||
|
% mica KAl3Si3O11.8H1.8F0.2 Density=2.76 Thickness= 4. microns
|
||||||
|
% 4 um mica at the exposure box exit
|
||||||
|
[val, ~ ] = get_fil_trans( 'mica', energy, 4);
|
||||||
|
trans_factor_d1 = val(2);
|
||||||
|
|
||||||
|
|
||||||
|
%calculate the transmission of the air path
|
||||||
|
% between the exposure box exit and the sample
|
||||||
|
%from http://henke.lbl.gov/optical_constants/gastrn2.html considering
|
||||||
|
% air N1.562O.42C.0003Ar.0094 Pressure=760 torr. T = 297 K, Path = 1 cm
|
||||||
|
[ val ] = get_gas_trans('air', energy, air_path/10,760, 297 );
|
||||||
|
ap_trans = val(2);
|
||||||
|
|
||||||
|
|
||||||
|
% from http://henke.lbl.gov/optical_constants/filter2.html, considering
|
||||||
|
% Silicon Density=2.33 Thickness= 10. microns
|
||||||
|
% contributes positively to the calculated flux
|
||||||
|
t_d1=10; % thickness Si sensor in microns
|
||||||
|
[ val, ~ ] = get_fil_trans( 'Si', energy, t_d1);
|
||||||
|
trans_si = val(2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%calculate the counts difference between open and closed shutter
|
||||||
|
counts_d1 = mean(S.transd) - mean(S_dark.transd); %photons
|
||||||
|
fprintf('The average counts at the transmission diode is %7.2f photons \n',counts_d1)
|
||||||
|
|
||||||
|
%calculate the current
|
||||||
|
curr_d1 = counts_d1 * Elettra_range/(2^(Elettra_bitmode-1));
|
||||||
|
fprintf('The current at the transmission diode is %7.2f microA \n',curr_d1*1e6)
|
||||||
|
|
||||||
|
%calculate the flux
|
||||||
|
flux_BIM2= ((curr_d1 * epsilon_Si)/(e_charge* (energy*1e3) *(1-trans_si)))*(trans_factor_d1 * ap_trans);
|
||||||
|
fprintf('The flux based on bim2 is %7.2e photons/s \n',flux_BIM2)
|
||||||
|
end
|
||||||
|
|
||||||
|
%%
|
||||||
|
if use_GCL14
|
||||||
|
|
||||||
|
% determination of the flux
|
||||||
|
%thickness of the sample
|
||||||
|
thickness_L14 = 0.1; % in cm for L14
|
||||||
|
|
||||||
|
%calculate the relative transmittance
|
||||||
|
%load the diode value for the air
|
||||||
|
S_air = spec_read(BasePath,'ScanNr',Air);
|
||||||
|
%scale in case the exposure times are different
|
||||||
|
exp_time = S_air.sec(1,1);
|
||||||
|
scale_air = 1/exp_time;
|
||||||
|
|
||||||
|
%read the scep data for the glassy carbon sample
|
||||||
|
S = spec_read(BasePath,'ScanNr',Glassy_carbon);
|
||||||
|
energy = S.mokev; % in kev
|
||||||
|
pixel_size = 0.172; % in mm
|
||||||
|
%normalize the measurement to the correct
|
||||||
|
exp_time = S.sec(1,1);
|
||||||
|
scale_GC = 1/exp_time;
|
||||||
|
|
||||||
|
%calculation of transmittance
|
||||||
|
if used_bs == 1
|
||||||
|
transmittance = (mean(S.diode)/mean(S.bpm4i))/(mean(S_air.diode)/mean(S_air.bpm4i));
|
||||||
|
elseif used_bs == 2
|
||||||
|
transmittance = (mean(S.cyb)/mean(S.bpm4i))/(mean(S_air.cyb)/mean(S_air.bpm4i));
|
||||||
|
else
|
||||||
|
error('Please inform the beam stop used in used_bs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%define the name of the measurement
|
||||||
|
scan_num = Glassy_carbon;
|
||||||
|
if scan_num > 9999
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration/S%05d-%05d/%s_1_%05d_00000_00000_integ.mat', ...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
else
|
||||||
|
filename = sprintf('%s/analysis/radial_integration/%s_1_%05d_00000_00000_integ.mat', ...
|
||||||
|
BasePath, e_account, scan_num);
|
||||||
|
if exist(filename, 'file') ~= 2
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration/S%05d-%05d/%s_1_%05d_00000_00000_integ.mat', ...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Data_GC = importdata(filename);
|
||||||
|
I_GC_m = mean(Data_GC.I_all,3);
|
||||||
|
I_GC_m = sum(I_GC_m.*Data_GC.norm_sum,2)./sum(Data_GC.norm_sum, 2);
|
||||||
|
q_GC_m = pixel_to_q(Data_GC.radius, pixel_size, DetDist_mm, energy);
|
||||||
|
|
||||||
|
|
||||||
|
%estimate the direct beam measurement
|
||||||
|
S_DB = spec_read(BasePath,'ScanNr',DB);
|
||||||
|
%scale in case the exposure times are different
|
||||||
|
exp_time = S_DB.sec(1,1);
|
||||||
|
scale_DB = 1/exp_time;
|
||||||
|
|
||||||
|
|
||||||
|
%plot the measured standard
|
||||||
|
scan_num = DB;
|
||||||
|
if scan_num > 9999
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration/S%05d-%05d/%s_1_%05d_00000_00000_integ.mat', ...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
else
|
||||||
|
filename = sprintf('%s/analysis/radial_integration/%s_1_%05d_00000_00000_integ.mat', ...
|
||||||
|
BasePath, e_account, scan_num);
|
||||||
|
if exist(filename, 'file') ~= 2
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration/S%05d-%05d/%s_1_%05d_00000_00000_integ.mat', ...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Data_DB = importdata(filename);
|
||||||
|
I_DB= mean(Data_DB.I_all,3);
|
||||||
|
I_DB = sum(I_DB.*Data_DB.norm_sum,2)./sum(Data_DB.norm_sum, 2);
|
||||||
|
|
||||||
|
|
||||||
|
%hold on;
|
||||||
|
%q_GC_m = (q_GC_m*10);
|
||||||
|
%normalize by the exposure time
|
||||||
|
I_GC_m = ((((I_GC_m*scale_GC)*1/transmittance )-(I_DB*scale_DB))*1/thickness_L14);
|
||||||
|
|
||||||
|
%compare to calibrated standard
|
||||||
|
%values provided for the calibrated Glassy carbon sample
|
||||||
|
q_GC_c = [0.0120496340976507;0.0125044551874072;0.0129732051637538;0.0134583002623949;0.0139593140871214;0.0144769572942580;0.0150120826715035;0.0155646902169131;0.0161354905862074;0.0167244837770547;0.0173329489709293;0.0179618810858233;0.0186112801185458;0.0192811460656564;0.0199724738441620;0.0206865426336400;0.0214223575088364;0.0221826189635588;0.0229661899401404;0.0237744917475841;0.0246092299570281;0.0254699781665768;0.0263573048941064;0.0272720629196088;0.0282159578107348;0.0291889895567488;0.0301914424089283;0.0312250219314847;0.0322902966359584;0.0333882614266597;0.0345199112062792;0.0356860987444304;0.0368869661524214;0.0381246453778608;0.0393994206591611;0.0407117183640269;0.0420638125635520;0.0434554189640091;0.0448893801546903;0.0463648433112569;0.0478845088842486;0.0494488032221519;0.0510572998839037;0.0527151155326772;0.0544201181456095;0.0561750081476676;0.0579803539937366;0.0598374347869336;0.0617482402768343;0.0637136231591258;0.0657351467748547;0.0678138059336549;0.0699520167405197;0.0721506318538254;0.0744114988336479;0.0767360388361561;0.0791253887439922;0.0815812539462713;0.0841040606468480;0.0867000623577208;0.0893671269066933;0.0921071017413062;0.0949225449342727;0.0978154460147494;0.100787225969034;0.103839874273604;0.106976091018953;0.110196728587036;0.113505339771704;0.116902066242041;0.120391029223623;0.123972796689442;0.127650494872454;0.131426112929190;0.135299792309430;0.139280344160401;0.143364214499320;0.147555239889708;0.151856261927069;0.156270548500290;0.160799093399002;0.165445448584523;0.170213165908177;0.175104375861299;0.180120640330274;0.185266789926598;0.190545381136233;0.195958259692354;0.201509545135676;0.207201793489021;0.213037134240793;0.219023239380533;0.225158684973226;0.231448584401029;0.237896203237904;0.244506227971290;0.251280076107924;0.258222433557780;0.265337275310852;0.272627723322335;0.280098746656204;0.287753608607507;0.290087652062856;0.293304736269482;0.296521618321574;0.299738296022361;0.302954767175882;0.306171029586988;0.309387081061351;0.312602919405477;0.315818542426710;0.319033947933244;0.322249133734126;0.325464097639273;0.328678837459470;0.331893351006389;0.335107636092589;0.338321690531530;0.341535512137577;0.344749098726013;0.347962448113043;0.351175558115807;0.354388426552383;0.357601051241800;0.360813430004044;0.364025560660067;0.367237441031796;0.370449068942139;0.373660442214998;0.376871558675271;0.380082416148865;0.383293012462703;0.386503345444732;0.389713412923933;0.392923212730325;0.396132742694977;0.399342000650017;0.402550984428637;0.405759691865102;0.408968120794761;0.412176269054052;0.415384134480512;0.418591714912783;0.421799008190624;0.425006012154916;0.428212724647670;0.431419143512038;0.434625266592318;0.437831091733966;0.441036616783597;0.444241839589003;0.447446757999153;0.450651369864203;0.453855673035507;0.457059665365622;0.460263344708318;0.463466708918585;0.466669755852640;0.469872483367936;0.473074889323173;0.476276971578300;0.479478727994529;0.482680156434336;0.485881254761478;0.489082020840992;0.492282452539209;0.495482547723759;0.498682304263582;0.501881720028930;0.505080792891380;0.508279520723843;0.511477901400565;0.514675932797143;0.517873612790525;0.521070939259026;0.524267910082328;0.527464523141494;0.530660776318971;0.533856667498600;0.537052194565627;0.540247355406704;0.543442147909900;0.546636569964711;0.549830619462064;0.553024294294327;0.556217592355316;0.559410511540301;0.562603049746017;0.565795204870670;0.568986974813943;0.572178357477005;0.575369350762521;0.578559952574654;0.581750160819079;0.584939973402985;0.588129388235086;0.591318403225627;0.594507016286392;0.597695225330712;0.600883028273470;0.604070423031114;0.607257407521657;0.610443979664689;0.613630137381386;0.616815878594512;0.620001201228432;0.623186103209116;0.626370582464145;0.629554636922725;0.632738264515686;0.635921463175494;0.639104230836259;0.642286565433740;0.645468464905351;0.648649927190174;0.651830950228960;0.655011531964139;0.658191670339828;0.661371363301837;0.664550608797674;0.667729404776558;0.670907749189420;0.674085639988915;0.677263075129425;0.680440052567068;0.683616570259708;0.686792626166954;0.689968218250177;0.693143344472510;0.696318002798857;0.699492191195902;0.702665907632112;0.705839150077748;0.709011916504869;0.712184204887341;0.715356013200841;0.718527339422871;0.721698181532753;0.724868537511648;0.728038405342554;0.731207783010319;0.734376668501645;0.737545059805092;0.740712954911092;0.743880351811948;0.747047248501847;0.750213642976862;0.753379533234962;0.756544917276018;0.759709793101807;0.762874158716023;0.766038012124281;0.769201351334123;0.772364174355027;0.775526479198411;0.778688263877642;0.781849526408042;0.785010264806893;0.788170477093445;0.791330161288921;0.794489315416526;0.797647937501451;0.800806025570882;0.803963577654003;0.807120591782006;0.810277065988094;0.813432998307490;0.816588386777444;0.819743229437236;0.822897524328184;0.826051269493653;0.829204462979055;0.832357102831862;0.83550Line truncated
|
||||||
|
I_GC_c = [37.4996383921856;37.2548332078092;36.4283288124236;36.2171017455181;36.0594526535833;35.9115039243978;35.7206516758486;35.5457687526235;35.4645745008631;35.3593982858726;35.2646446480797;34.5439024389316;34.4496042048382;34.3367536550321;34.2494160725991;34.1552878382091;34.0225318267624;33.8700294479800;33.7322197521813;33.6578192244874;33.5595559196515;33.4289145601177;33.3042268238371;33.1786408925464;33.0235231925436;32.9220890682906;32.7933488016634;32.0956203754132;32.0134149698111;31.9402817946214;31.7996141727154;31.7154953296368;31.6228560667772;31.5414505004883;31.4524481113140;31.3508797425490;31.2854652404785;31.1914306053749;31.1408305534950;31.0959938489474;31.0430858318622;31.0641636481652;30.9690412374643;30.8992959536039;30.8582724791307;30.8052206773024;30.7651990010188;30.7142602480375;30.6480002036461;30.5753599313589;30.5380638562716;30.4429228856013;30.3636076266949;30.2560176849365;30.1547018931462;30.0181754919199;29.8537241862370;29.6561602812547;29.4377786196195;29.1376347175011;28.8615410878108;28.5411135600163;28.1562579961923;28.2315394618897;27.2097022716816;27.2126863964973;26.6591948256764;26.0754377785032;25.4554875012226;24.7569221427885;24.0479588379221;23.2468096224346;22.4772266670018;21.6680129830842;20.8113131927969;19.9163549442443;19.0327712249840;18.0965621637316;17.2038128508614;16.2679657267658;15.3605304774854;14.4543927151244;13.5951173112066;12.6881058999300;11.8622364660335;10.8011194375845;10.2782222618139;9.52750501741191;8.61494293579688;7.93357564852788;7.30044454794664;6.77625944064214;6.16035426579989;5.64497525875385;5.16162362465492;4.72441913531377;4.31454612658574;3.95227755033053;3.59874264093546;3.29018119665293;3.00322911372552;2.74924242496490;2.67832939744743;2.58007078333710;2.49067190473411;2.39487275388869;2.34205549260251;2.25324465762885;2.17310866891045;2.08711825841638;2.01926423902903;1.94911575979623;1.88229705191627;1.82389184767408;1.76412613413988;1.71169094593207;1.65296411902820;1.60233168550444;1.55217055879365;1.50621289274187;1.46380628112730;1.41082620607445;1.37340160284771;1.33974584799371;1.29936150512739;1.26254058638749;1.21817236723899;1.18855787548849;1.15051551711141;1.13178209580990;1.09564126963491;1.05689699918740;1.03223779321436;1.00921412322167;0.982011108924821;0.954196649142988;0.933257621487925;0.910027226521827;0.889860352287722;0.862006058599062;0.838316685025028;0.818082680760775;0.797788343684465;0.782549083868602;0.761265928948320;0.739661568945698;0.730028877798775;0.713922496518267;0.695299867344911;0.678843048156554;0.660838460326802;0.649057366696747;0.629896406621617;0.617109000418718;0.603455210139803;0.589989001697014;0.580678570990164;0.567285610839356;0.557683612799142;0.542622027987168;0.532108400474406;0.518258635461546;0.509293319512140;0.497352793118331;0.488202205124504;0.478828182354006;0.468886500917918;0.460221030314538;0.448104587202362;0.441216649094231;0.432536416075870;0.425109193866992;0.417060076396248;0.408307219708715;0.401393103801021;0.394546945404697;0.385522557899928;0.380612106178446;0.372607525564145;0.366296726081248;0.361762870734754;0.352927542887272;0.347774303544552;0.340362363686539;0.336202140636285;0.327517845542412;0.323161000427133;0.318350108024248;0.312773068088334;0.308253896940966;0.303326886374816;0.298524243296601;0.294257140015375;0.289435833533733;0.284379271618311;0.279920089267782;0.275588732481385;0.272275805408322;0.265975135649143;0.263913217302554;0.260995613065508;0.256283712638261;0.252464453872433;0.249572932713027;0.245678091117762;0.241957725947313;0.239883404681421;0.234639557559059;0.232384547125292;0.227869074445529;0.225798291447451;0.222371988936042;0.219979802092999;0.217518861184104;0.214980917512402;0.211843541970048;0.208961118292305;0.205994100051124;0.203824360208272;0.201058749381979;0.198683961225536;0.196581103304325;0.194255444598214;0.190596526903666;0.188467527386347;0.186598882088540;0.184907665108340;0.182435297445616;0.181351841464676;0.178632855644918;0.177518067175766;0.175030999770603;0.172310029478859;0.170335199522834;0.168928597141419;0.166885872093665;0.165378744039184;0.162626121329917;0.161118313665291;0.160414100848547;0.158590051316222;0.156832935400278;0.156720543960870;0.153592032136451;0.152817084573196;0.151441497989464;0.150090135985959;0.147760548925723;0.146990053306342;0.145922931001558;0.144860247120584;0.142764303904499;0.141755847632909;0.139879437827240;0.139006281832558;0.137331368086629;0.136060935867709;0.135112276901657;0.133737412181438;0.132116486936951;0.131524506276471;0.129908938183876;0.129735945273417;0.128738876495355;0.127101736233621;0.125510445428119;0.124532502369922;0.123586137299227;0.123161959455318;0.121932384227846;0.121726636603451;0.120038483099947;0.119580595712703;0.118836345839512;0.118875274780644;0.117957003927912;0.117231934438890;0.117059080942472;0.115178614399837;0.115408995761404;0.114051913989668;0.112516650678456;0.112578676816154;0.111024072389246;0.11078Line truncated
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%determine the factor to scale the intensity in absolute scale
|
||||||
|
C = [];
|
||||||
|
%create a vector to fit the region from q 0.07 to 0.08 A
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
q_range = [q_GC_c(1):0.01:q_GC_m(end-1000)]; %good region for 2 and 7 m flight tube
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
for i = 1:length(q_range)
|
||||||
|
[~, index_m] = min(abs(q_GC_m - q_range(i)));
|
||||||
|
[~, index_c] = min(abs(q_GC_c - q_range(i)));
|
||||||
|
C = [C I_GC_c(index_c)/I_GC_m(index_m)]; %determined in cm/s
|
||||||
|
end
|
||||||
|
dev_SAXS = std(C);
|
||||||
|
C_SAXS = mean(C);
|
||||||
|
calibration_factor_SAXS = C_SAXS; %in s/photons
|
||||||
|
|
||||||
|
|
||||||
|
if (use_WAXS)
|
||||||
|
scan_num = Glassy_carbon;
|
||||||
|
if scan_num > 9999
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat',...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
else
|
||||||
|
filename = sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat',...
|
||||||
|
BasePath, e_account, scan_num);
|
||||||
|
if exist(filename, 'file') ~= 2
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat',...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
WAXS_GC = importdata(filename);
|
||||||
|
I_GC_WAXS= median(squeeze(WAXS_GC.I_all),2);
|
||||||
|
scan_num = DB;
|
||||||
|
if scan_num > 9999
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat',...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
else
|
||||||
|
filename = sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat',...
|
||||||
|
BasePath, e_account, scan_num);
|
||||||
|
if exist(filename, 'file') ~= 2
|
||||||
|
init = floor(scan_num/10000)*10000;
|
||||||
|
last_number = init+9999;
|
||||||
|
filename = sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat',...
|
||||||
|
BasePath, init, last_number, e_account, scan_num);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Data_DB_WAXS= importdata(filename);
|
||||||
|
I_DB_WAXS = median(squeeze(Data_DB_WAXS.I_all),2);
|
||||||
|
q_GC_WAXS = WAXS_GC.q;
|
||||||
|
I_GC_WAXS = ((((I_GC_WAXS*scale_GC)*1/transmittance )-(I_DB_WAXS*scale_DB))*1/thickness_L14);
|
||||||
|
|
||||||
|
%determine the factor to scale the intensity in absolute scale
|
||||||
|
C=[];
|
||||||
|
%create a vector to fit the region from q 0.07 to 0.08 A
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
q_range = [q_GC_WAXS(1):0.01:q_GC_WAXS(300) ]; %good region for 2 and 7 m flight tube
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
for i = 1:length(q_range)
|
||||||
|
[~, index_m] = min(abs(q_GC_WAXS - q_range(i)));
|
||||||
|
[~, index_c] = min(abs(q_GC_c - q_range(i)));
|
||||||
|
C = [C I_GC_c(index_c)/I_GC_WAXS(index_m)]; %determined in cm/s
|
||||||
|
end
|
||||||
|
dev_WAXS = std(C);
|
||||||
|
C_WAXS = mean(C);
|
||||||
|
calibration_factor_WAXS = C_WAXS; %in s/photons
|
||||||
|
else
|
||||||
|
calibration_factor_WAXS=1;
|
||||||
|
dev_WAXS = 0;
|
||||||
|
C_WAXS = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%calculate the efficiency of the detector
|
||||||
|
% from http://henke.lbl.gov/optical_constants/filter2.html, considering
|
||||||
|
%silicon Si Density=2.33 Thickness=320. microns
|
||||||
|
[ val, ~ ] = get_fil_trans( 'Si', energy, 320);
|
||||||
|
TransmissionSi1 = val(2);
|
||||||
|
p = 1-(TransmissionSi1);
|
||||||
|
|
||||||
|
%contribution from the FT windows to the flux
|
||||||
|
% from http://henke.lbl.gov/optical_constants/filter2.html, considering
|
||||||
|
% mica KAl3Si3O11.8H1.8F0.2 Density=2.76 Thickness= 7. microns
|
||||||
|
[ val, ~ ] = get_fil_trans( 'mica', energy, 7);
|
||||||
|
mica = val(2);
|
||||||
|
|
||||||
|
%from http://henke.lbl.gov/optical_constants/filter2.html, considering
|
||||||
|
% mylar C10H8O4 Density=1.43 Thickness=300. microns
|
||||||
|
[ val, ~ ] = get_fil_trans( 'mylar', energy, 300);
|
||||||
|
mylar = val(2);
|
||||||
|
|
||||||
|
% define the length of the air path in mm
|
||||||
|
% remove the air path in vacuum from the DetDist_mm
|
||||||
|
% values from https://intranet.psi.ch/CSAXS/NewFlightTube
|
||||||
|
if DetDist_mm < 5e3
|
||||||
|
air_path = DetDist_mm - 2051.5; %for 2m flight tube in mm
|
||||||
|
else
|
||||||
|
air_path = DetDist_mm - 7030.2; %for 3m flight tube in mm
|
||||||
|
end
|
||||||
|
|
||||||
|
%calculate the transmission of the air path
|
||||||
|
|
||||||
|
%from http://henke.lbl.gov/optical_constants/gastrn2.html considering
|
||||||
|
%N1.562O.42C.0003Ar.0094 Pressure=760. T = 297 K, Path = 1 cm
|
||||||
|
% air N1.562O.42C.0003Ar.0094 Pressure=760 torr. T = 297 K, Path = 1 cm
|
||||||
|
[ val ] = get_gas_trans('air', energy, air_path/10,760, 297 );
|
||||||
|
ap_trans = val(2);
|
||||||
|
|
||||||
|
|
||||||
|
%define the solid angle: we consider the first pixel close to the beam stop
|
||||||
|
%as it would have the highest intensity
|
||||||
|
angle = (atan(pixel_size/DetDist_mm)); %in radians
|
||||||
|
sol_angle = angle^2; %in steradian (sr): square radians
|
||||||
|
|
||||||
|
%plot the comparison
|
||||||
|
loglog(q_GC_c, I_GC_c,'k', 'LineWidth', 4);
|
||||||
|
hold on
|
||||||
|
I_GC_m = I_GC_m*calibration_factor_SAXS; % in cm-1
|
||||||
|
loglog(q_GC_m, I_GC_m, 'r', 'LineWidth', 2);
|
||||||
|
|
||||||
|
if (use_WAXS)
|
||||||
|
loglog(q_GC_WAXS, I_GC_WAXS*C_WAXS, 'LineWidth', 2);
|
||||||
|
end
|
||||||
|
|
||||||
|
xlabel('Scattering vector q (A^{-1})');
|
||||||
|
ylabel('Differential scattering cross section (cm^{-1})');
|
||||||
|
axis tight
|
||||||
|
grid on;
|
||||||
|
|
||||||
|
if (use_WAXS)
|
||||||
|
legend('Standard GCL14', sprintf('Corrected SAXS GCL14 x %.2d',C_SAXS ), ...
|
||||||
|
sprintf('Corrected WAXS GCL14 x %.2d',C_WAXS ), 'Location','southwest')
|
||||||
|
else
|
||||||
|
legend('Standard GCL14', sprintf('Corrected SAXS GCL14 x %.2d',C_SAXS ),...
|
||||||
|
'Location','southwest')
|
||||||
|
end
|
||||||
|
|
||||||
|
set(gca,'fontsize',12)
|
||||||
|
|
||||||
|
%calculate the flux
|
||||||
|
positive_cont = (mica * mylar * ap_trans * p);
|
||||||
|
flux_GC = 1/(calibration_factor_SAXS*sol_angle * positive_cont); %flux in photons/s
|
||||||
|
|
||||||
|
|
||||||
|
%display the results
|
||||||
|
fprintf('The approximated flux from GCL14 is %5.2e photons/s \n', flux_GC);
|
||||||
|
fprintf('The calibration factor for corrected intensity is C_{SAXS} = %.2d ± %.2d. \n ', calibration_factor_SAXS, dev_SAXS);
|
||||||
|
if (use_WAXS)
|
||||||
|
fprintf('The calibration factor for corrected intensity is C_{WAXS} = %.2d ± %.2d. \n ', calibration_factor_WAXS, dev_WAXS);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
% Return the current e-account user name in case this function is executed
|
||||||
|
% at the X12SA beamline, [] otherwise.
|
||||||
|
|
||||||
|
% Filename: $RCSfile: identify_eaccount.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.1 $ $Date: 2010/04/28 18:00:56 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Return the current e-account user name in case this function is executed
|
||||||
|
% at the X12SA beamline, [] otherwise.
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% none
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% identify_system.m
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% April 28th, 2010: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [return_user_name] = identify_eaccount()
|
||||||
|
import utils.identify_system
|
||||||
|
|
||||||
|
persistent user_name;
|
||||||
|
|
||||||
|
if (isempty(user_name))
|
||||||
|
user_name = [];
|
||||||
|
% at the cSAXS beamline return the name of the current user as
|
||||||
|
% e-account name
|
||||||
|
sys_id = identify_system();
|
||||||
|
if (strcmp(sys_id,'X12SA'))
|
||||||
|
[st,un] = system('echo $USER');
|
||||||
|
if ((st == 0) && (length(un) > 1))
|
||||||
|
user_name = un(1:end-1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return_user_name = user_name;
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
%IND2MASK
|
||||||
|
% convert mask structure (indices + framesize) to a 2D binary mask
|
||||||
|
%
|
||||||
|
% ** s mask structure; must contain s.indices and s.framesize
|
||||||
|
%
|
||||||
|
% returns:
|
||||||
|
% ++ mask 2D binary mask
|
||||||
|
%
|
||||||
|
% see also: beamline.mask2ind
|
||||||
|
|
||||||
|
% Academic License Agreement
|
||||||
|
%
|
||||||
|
% Source Code
|
||||||
|
%
|
||||||
|
% Introduction
|
||||||
|
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||||
|
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||||
|
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||||
|
%
|
||||||
|
% Terms and Conditions of the LICENSE
|
||||||
|
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||||
|
% hereinafter set out and until termination of this license as set forth below.
|
||||||
|
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||||
|
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||||
|
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||||
|
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||||
|
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||||
|
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||||
|
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||||
|
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||||
|
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||||
|
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||||
|
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||||
|
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||||
|
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||||
|
% another computing language:
|
||||||
|
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||||
|
% Scherrer Institut, Switzerland."
|
||||||
|
%
|
||||||
|
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||||
|
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||||
|
% (doi: 10.1126/science.1158573),
|
||||||
|
% for maximum likelihood:
|
||||||
|
% P. Thibault and M. Guizar-Sicairos, Maximum-likelihood refinement for coherent diffractive imaging, New J. Phys. 14, 063004 (2012).
|
||||||
|
% (doi: 10.1088/1367-2630/14/6/063004),
|
||||||
|
% for mixed coherent modes:
|
||||||
|
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||||
|
% and/or for multislice:
|
||||||
|
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||||
|
% (doi: 10.1364/OE.24.029089).
|
||||||
|
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||||
|
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||||
|
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||||
|
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||||
|
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||||
|
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||||
|
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||||
|
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||||
|
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||||
|
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||||
|
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||||
|
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||||
|
% the courts of Zürich, Switzerland.
|
||||||
|
|
||||||
|
function [mask] = ind2mask(s)
|
||||||
|
|
||||||
|
if ~isfield(s, 'framesize')
|
||||||
|
error('Please specify your frame size.')
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isfield(s, 'indices')
|
||||||
|
error('Please specify the indices.')
|
||||||
|
end
|
||||||
|
|
||||||
|
mask = reshape(zeros(s.framesize),1,[]);
|
||||||
|
mask(s.indices) = 1;
|
||||||
|
mask = reshape(mask, s.framesize);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: integrate_range.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.7 $ $Date: 2012/09/02 15:13:04 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% azimuthal integration of a range of scans
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
% The integration masks need to be prepared first using prep_integ_masks.m
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - compile_x12sa_filename
|
||||||
|
% - find_files
|
||||||
|
% - radial_integ
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% May 19th 2010: 1st documented version
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [] = integrate_range(scan_no_from,scan_no_to,scan_no_step,varargin)
|
||||||
|
import beamline.prep_integ_masks
|
||||||
|
import beamline.radial_integ
|
||||||
|
import utils.compile_x12sa_filename
|
||||||
|
import utils.find_files
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
% select PILATUS 2M
|
||||||
|
pilatus_det_no = 1;
|
||||||
|
% writing cbf files
|
||||||
|
file_extension = 'cbf';
|
||||||
|
save_format = '-v6';
|
||||||
|
|
||||||
|
if (nargin < 2)
|
||||||
|
fprintf('\nUsage:\n');
|
||||||
|
fprintf('%s(scan_no_from,scan_no_to,scan_no_step [[,<name>,<value>] ...]);\n',mfilename);
|
||||||
|
fprintf('integrates the scans within the range [scan_no_from, scan_no_to].\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''PilatusDetNo'',<number> Detector number, 1 for 2M, default is %d\n',pilatus_det_no);
|
||||||
|
fprintf('''FileExtension'',<extension string> default is %s\n',file_extension);
|
||||||
|
fprintf('''SaveFormat'',<format string> default is %s\n',save_format);
|
||||||
|
fprintf('Example:\n');
|
||||||
|
fprintf('%s(100,500);\n',mfilename);
|
||||||
|
fprintf('Additional <name>,<value> pairs recognized by radial_integ can be specified.\n');
|
||||||
|
error('At least the scan number range has to be specified as input argument.');
|
||||||
|
end
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 4)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% parse the variable input arguments:
|
||||||
|
% initialize the list of unhandled parameters
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'PilatusDetNo'
|
||||||
|
pilatus_det_no = value;
|
||||||
|
case 'SaveFormat'
|
||||||
|
save_format = value;
|
||||||
|
case 'FileExtension'
|
||||||
|
file_extension = value;
|
||||||
|
vararg_remain{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg_remain{end+1} = value; %#ok<AGROW>
|
||||||
|
otherwise
|
||||||
|
vararg_remain{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg_remain{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vararg_remain{end+1} = 'UnhandledParError';
|
||||||
|
vararg_remain{end+1} = 0;
|
||||||
|
|
||||||
|
vararg_remain_x12sa_filename = vararg_remain;
|
||||||
|
vararg_remain_x12sa_filename{end+1} = 'DetectorNumber';
|
||||||
|
vararg_remain_x12sa_filename{end+1} = pilatus_det_no;
|
||||||
|
|
||||||
|
vararg_remain_x12sa_filename_wildcard = vararg_remain_x12sa_filename;
|
||||||
|
vararg_remain_x12sa_filename_wildcard{end+1} = 'PointWildcard';
|
||||||
|
vararg_remain_x12sa_filename_wildcard{end+1} = 1;
|
||||||
|
vararg_remain_x12sa_filename_wildcard{end+1} = 'SubExpWildcard';
|
||||||
|
vararg_remain_x12sa_filename_wildcard{end+1} = 1;
|
||||||
|
|
||||||
|
|
||||||
|
% highest number of an existing scan
|
||||||
|
scan_no_exists = scan_no_from -1;
|
||||||
|
scan_no_check = scan_no_from;
|
||||||
|
|
||||||
|
for scan_no = scan_no_from:scan_no_step:scan_no_to
|
||||||
|
% wait until the first file of the next scan is available
|
||||||
|
while (scan_no >= scan_no_exists)
|
||||||
|
scan_no_check = scan_no_check +1;
|
||||||
|
if (scan_no_check > scan_no + 100)
|
||||||
|
scan_no_check = scan_no +1;
|
||||||
|
fprintf('Pausing for 1 minute.\n');
|
||||||
|
pause(60);
|
||||||
|
|
||||||
|
% check if the data directory and first file exists
|
||||||
|
filename_mask = compile_x12sa_filename(scan_no,0,vararg_remain_x12sa_filename);
|
||||||
|
[ddir fnames] = find_files(filename_mask);
|
||||||
|
if (~isempty(fnames))
|
||||||
|
% integrate all data available until now
|
||||||
|
filename_mask = [ compile_x12sa_filename(scan_no,-1,vararg_remain_x12sa_filename) '*_' num2str(pilatus_det_no) '_' ['*' file_extension] ];
|
||||||
|
radial_integ(filename_mask,vararg_remain);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
filename_next = compile_x12sa_filename(scan_no_check,0,vararg_remain_x12sa_filename);
|
||||||
|
[ddir fnames] = find_files(filename_next);
|
||||||
|
if (~isempty(fnames))
|
||||||
|
scan_no_exists = scan_no_check;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% integrate scan if a following scan has been started, i.e.,
|
||||||
|
% if the current one must be finished
|
||||||
|
if (scan_no < scan_no_exists)
|
||||||
|
% check if the data directory and first file exists
|
||||||
|
filename_mask = compile_x12sa_filename(scan_no,0,vararg_remain_x12sa_filename);
|
||||||
|
[ddir fnames] = find_files(filename_mask);
|
||||||
|
if (isempty(fnames))
|
||||||
|
fprintf('Skipping scan no %d: no data found\n',scan_no);
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
% integrate all data, i.e., all points and sub exposures
|
||||||
|
filename_mask = [ compile_x12sa_filename(scan_no,0,vararg_remain_x12sa_filename_wildcard) ];
|
||||||
|
radial_integ(filename_mask,vararg_remain);
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
% Description:
|
||||||
|
% Return beam intensity in photons / sec based on calibration with
|
||||||
|
% a glassy carbon sample and and air
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% spec_read
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSA% Description:
|
||||||
|
% Return beam intensity in photons / sec based on calibration with
|
||||||
|
% a glassy carbon sample and and air
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% spec_readXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ diodescale ] = intensity_calibration(specfile, air_scanno, gc_scanno, det_dist_mm, varargin)
|
||||||
|
import io.spec_read
|
||||||
|
import utils.find_files
|
||||||
|
|
||||||
|
pixel_size_mm = 0.172;
|
||||||
|
gc_file = 'glassycarbon_L14_xsection.dat';
|
||||||
|
binned_path = '~/Data10/analysis/radial_integration/';
|
||||||
|
|
||||||
|
if (nargin < 4)
|
||||||
|
fprintf('\nUsage:\n');
|
||||||
|
fprintf('%s(specfile, air_scanno, gc_scanno, det_dist_mm, [[,<name>,<value>] ...]);\n\n',mfilename);
|
||||||
|
fprintf('specfile is the full path to the SPEC dat-file.\n');
|
||||||
|
fprintf('air_scanno and gc_scanno are SPEC scan numbers for empty and Glassy Carbon L14 measurements.\n');
|
||||||
|
fprintf('det_dist_mm is the sample to detector distance in mm.\n');
|
||||||
|
fprintf('\nThe optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''PixelSize_mm'', <value in mm> Size of detector pixel in mm, default is %s\n', pixel_size_mm);
|
||||||
|
fprintf('''CrossSectionFile'', <filename> Full path to file containing the cross section of the standard, default is ''%s''\n', gc_file);
|
||||||
|
fprintf('''BinnedPath'', <filepath> Directory containing the radially binned detector frames, default is ''%s''\n', binned_path);
|
||||||
|
fprintf('\n');
|
||||||
|
error('Not enough input arguments.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 5)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 0)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'PixelSize_mm'
|
||||||
|
pixel_size_mm = value;
|
||||||
|
case 'CrossSectionFile'
|
||||||
|
gc_file = value;
|
||||||
|
case 'BinnedPath'
|
||||||
|
binned_path= value;
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
s_air = spec_read(specfile, 'ScanNr', air_scanno);
|
||||||
|
s_gc = spec_read(specfile, 'ScanNr', gc_scanno);
|
||||||
|
|
||||||
|
[dd, air_intfile] = find_files(sprintf(strcat(binned_path, 'e*_1_%05d_00000_00000_integ.mat'), air_scanno));
|
||||||
|
airint = load(strcat(dd, air_intfile.name));
|
||||||
|
[dd, gc_intfile] = find_files(sprintf(strcat(binned_path, 'e*_1_%05d_00000_00000_integ.mat'), gc_scanno));
|
||||||
|
gcint = load(strcat(dd, gc_intfile.name));
|
||||||
|
|
||||||
|
lambda = 12.39852 / s_gc.mokev;
|
||||||
|
q_gc = 4*pi * sin(0.5*atan(gcint.radius*pixel_size_mm/det_dist_mm)) / lambda;
|
||||||
|
gc_transmission = (sum(s_gc.diode)/sum(s_gc.sec)) / (sum(s_air.diode)/sum(s_air.sec));
|
||||||
|
gc_time = sum(s_gc.sec);
|
||||||
|
I_gc = sum(sum(gcint.I_all, 3), 2) - (sum(s_gc.diode)/sum(s_air.diode)) * sum(sum(airint.I_all, 3), 2);
|
||||||
|
Ierr_gc = sqrt(sum(sum(gcint.I_std.^2, 3), 2) + (sum(s_gc.diode)/sum(s_air.diode)).^2 * sum(sum(airint.I_std.^2, 3), 2));
|
||||||
|
|
||||||
|
gc = load(gc_file);
|
||||||
|
qmin = max(q_gc(1), gc(1,1));
|
||||||
|
qmax = min(q_gc(end), gc(end,1));
|
||||||
|
qind = find(qmin < gc(:,1) & gc(:,1) < qmax);
|
||||||
|
q = gc(qind, 1);
|
||||||
|
tth = 2*asin(lambda * q / (4*pi));
|
||||||
|
|
||||||
|
% Cross section per q-bin. Factors for thickness, transmission and solid angle
|
||||||
|
xsection_scale = (1 / 10) * 1/gc_transmission * pixel_size_mm^2 / (4*pi*det_dist_mm^2);
|
||||||
|
gc_xsection = xsection_scale * gc(qind,2);
|
||||||
|
gc_xsection_err = xsection_scale * gc(qind,3);
|
||||||
|
|
||||||
|
% interpolate and scale w. angle dependent pixel solid angle and tilt
|
||||||
|
gc_exp = interp1(q_gc, I_gc, q) ./ (cos(tth).^3);
|
||||||
|
gc_exp_err = interp1(q_gc, Ierr_gc, q) ./ (cos(tth).^3);
|
||||||
|
|
||||||
|
s2 = gc_xsection_err.^2 + gc_exp_err.^2;
|
||||||
|
% Solve for scaling factor, weigh with combined variance^-1
|
||||||
|
wscale = sum(gc_xsection.*gc_exp./s2) / sum(gc_exp.^2 ./ s2);
|
||||||
|
fitchi = sum((gc_xsection - wscale*gc_exp).^2./(gc_xsection_err.^2 + (wscale*gc_exp_err).^2));
|
||||||
|
clf()
|
||||||
|
hold on
|
||||||
|
errband(q, gc_xsection, gc_xsection_err, 'r');
|
||||||
|
errband(q, wscale*gc_exp, wscale*gc_exp_err, 'b');
|
||||||
|
legend('Cross section', ' 1 std', 'Experimental', ' 1 std');
|
||||||
|
hold off
|
||||||
|
|
||||||
|
% scaling without error weighing
|
||||||
|
% scale = gc_exp \ gc_xsection;
|
||||||
|
%semilogy(q, gc_xsection, '*', q, scale*gc_exp)
|
||||||
|
|
||||||
|
% incoming flux (photons/s) determined for each q-channel:
|
||||||
|
%plot((1/gc_time) * gc_exp ./ gc_xsection)
|
||||||
|
inphotons = 1/gc_time * mean(gc_exp./gc_xsection);
|
||||||
|
diodescale = inphotons / (sum(s_gc.diode)/gc_time/gc_transmission);
|
||||||
|
fprintf('Glassy carbon transmission: %g\n', gc_transmission);
|
||||||
|
fprintf('Chi^2 to known cross-section: %g\n', fitchi);
|
||||||
|
fprintf('Flux on sample: %g ph/sec\n', inphotons);
|
||||||
|
fprintf('Scaling factor for diode readings: %g\n', diodescale);
|
||||||
|
|
||||||
|
|
||||||
|
function errband(x, y, yerr, colour);
|
||||||
|
%function errband(x, y, yerr, colour);
|
||||||
|
%
|
||||||
|
% Plot an error band between y-yerr and y+yerr.
|
||||||
|
% The colour defaults to blue.
|
||||||
|
|
||||||
|
if nargin<4
|
||||||
|
colour='b';
|
||||||
|
end
|
||||||
|
|
||||||
|
x = x(:).';
|
||||||
|
y = y(:).';
|
||||||
|
yerr = yerr(:).';
|
||||||
|
|
||||||
|
lower = y-yerr;
|
||||||
|
upper = y+yerr;
|
||||||
|
|
||||||
|
hold on
|
||||||
|
plot(x, y, colour);
|
||||||
|
h = fill([x, fliplr(x)], [upper, fliplr(lower)], colour);
|
||||||
|
alpha(h, 0.5);
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
% out = is_scan_finished(specDatFile,scanno)
|
||||||
|
% Detect 'X# ' in spec file to detect the end of a scan
|
||||||
|
% From spec compile post_scan.mac
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function out = is_scan_finished(specDatFile,scanno)
|
||||||
|
|
||||||
|
specDatFile = beamline.find_specDatFile(specDatFile);
|
||||||
|
|
||||||
|
cmd = sprintf('grep -n ''#X %d'' %s', scanno,specDatFile);
|
||||||
|
[~,sysout] = system(cmd);
|
||||||
|
arrout = regexp(sysout,'[:\n]','split');
|
||||||
|
if any(strcmp(arrout,sprintf('#X %d',scanno)))
|
||||||
|
out = true;
|
||||||
|
else
|
||||||
|
out = false;
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
% out = is_scan_started(specDatFile,scanno)
|
||||||
|
% Detect 'X# ' in spec file to detect the end of a scan
|
||||||
|
% From spec compile post_scan.mac
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function out = is_scan_started(specDatFile,scanno)
|
||||||
|
|
||||||
|
specDatFile = beamline.find_specDatFile(specDatFile);
|
||||||
|
|
||||||
|
cmd = sprintf('grep -n ''#S %d'' %s', scanno,specDatFile);
|
||||||
|
[~,sysout] = system(cmd);
|
||||||
|
arrout = regexp(sysout,'[:\n ]','split');
|
||||||
|
indS = find(strcmp(regexp(sysout,'[:\n ]','split'),'#S')==1); % Indices where #S is found
|
||||||
|
for ii=indS % Loop over all #S found, this is to make sure we dont recognize S# 191 when looking for S# 19
|
||||||
|
if strcmp(arrout(ii+1),sprintf('%d',scanno))
|
||||||
|
out = true;
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
% If not found
|
||||||
|
out = false;
|
||||||
|
return
|
||||||
|
end
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
% If you do scans with different marks for energy you can use this code to
|
||||||
|
% calibrate the marks vs energy
|
||||||
|
% Run this code, it will save a calibration and then you can use
|
||||||
|
% energy2mark function
|
||||||
|
|
||||||
|
% User input
|
||||||
|
scans = [134:163];
|
||||||
|
marks = [0:0.2:5.99];
|
||||||
|
|
||||||
|
data = io.spec_read('~/Data10/','ScanNr',scans);
|
||||||
|
|
||||||
|
clear E
|
||||||
|
for ii = 1:numel(data)
|
||||||
|
E(ii) = data{ii}.mokev;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Remove the last
|
||||||
|
E = E(1:end-1);
|
||||||
|
marks = marks(1:end-1);
|
||||||
|
|
||||||
|
figure(1);
|
||||||
|
plot(E,marks,'o-')
|
||||||
|
xlabel('E (keV)')
|
||||||
|
ylabel('marks')
|
||||||
|
|
||||||
|
save('mark_calib.mat','marks','E');
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
%MASK2IND
|
||||||
|
% convert a 2D binary mask to indices
|
||||||
|
%
|
||||||
|
% ** mask 2D binary mask
|
||||||
|
%
|
||||||
|
% returns:
|
||||||
|
% ++ s mask structure; must contain s.indices and s.framesize
|
||||||
|
%
|
||||||
|
% see also: beamline.ind2mask
|
||||||
|
|
||||||
|
% Academic License Agreement
|
||||||
|
%
|
||||||
|
% Source Code
|
||||||
|
%
|
||||||
|
% Introduction
|
||||||
|
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||||
|
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||||
|
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||||
|
%
|
||||||
|
% Terms and Conditions of the LICENSE
|
||||||
|
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||||
|
% hereinafter set out and until termination of this license as set forth below.
|
||||||
|
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||||
|
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||||
|
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||||
|
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||||
|
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||||
|
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||||
|
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||||
|
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||||
|
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||||
|
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||||
|
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||||
|
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||||
|
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||||
|
% another computing language:
|
||||||
|
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||||
|
% Scherrer Institut, Switzerland."
|
||||||
|
%
|
||||||
|
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||||
|
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||||
|
% (doi: 10.1126/science.1158573),
|
||||||
|
% for maximum likelihood:
|
||||||
|
% P. Thibault and M. Guizar-Sicairos, Maximum-likelihood refinement for coherent diffractive imaging, New J. Phys. 14, 063004 (2012).
|
||||||
|
% (doi: 10.1088/1367-2630/14/6/063004),
|
||||||
|
% for mixed coherent modes:
|
||||||
|
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||||
|
% and/or for multislice:
|
||||||
|
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||||
|
% (doi: 10.1364/OE.24.029089).
|
||||||
|
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||||
|
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||||
|
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||||
|
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||||
|
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||||
|
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||||
|
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||||
|
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||||
|
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||||
|
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||||
|
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||||
|
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||||
|
% the courts of Zürich, Switzerland.
|
||||||
|
|
||||||
|
|
||||||
|
function [s] = mask2ind(mask)
|
||||||
|
|
||||||
|
s.framesize = size(mask);
|
||||||
|
|
||||||
|
s.indices = find(reshape(mask, 1, [])~=0);
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
%NEXT_SCAN_STARTED if the next scan has started, the first return value is
|
||||||
|
% true.
|
||||||
|
% [started, scanNr] = next_scan_started(specDatFile,scanno);
|
||||||
|
%
|
||||||
|
% ** specDatFile path to the SPEC file / spec directory
|
||||||
|
% ** scanno current scan number
|
||||||
|
%
|
||||||
|
% returns:
|
||||||
|
% ++ started true if scanno is not the last scan
|
||||||
|
% ++ nextScanno next scan number
|
||||||
|
% ++ specDatFile specDatFile used to determine if the next scan has started
|
||||||
|
%
|
||||||
|
% see also: beamline.find_specDatFile
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [started, nextScanno, specDatFile] = next_scan_started(dataPath,scanno)
|
||||||
|
|
||||||
|
specDatFile = beamline.find_specDatFile(dataPath);
|
||||||
|
|
||||||
|
cmd = sprintf('grep ''#S '' %s | grep -A 1 ''#S %d '' | tail -1', specDatFile, scanno);
|
||||||
|
[~,sysout] = system(cmd);
|
||||||
|
arrout = regexp(sysout,'[:\n ]','split');
|
||||||
|
nextScanno = str2double(arrout{2});
|
||||||
|
|
||||||
|
if nextScanno>scanno
|
||||||
|
started = true;
|
||||||
|
else
|
||||||
|
started = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: pilatus_valid_pixel_roi.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.5 $ $Date: 2011/05/19 16:44:24 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% cut out of the valid pixel mask for the full detector the one for the
|
||||||
|
% current region of interest
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% The location of the ROI is not stored in the data files. It is deduced
|
||||||
|
% from the known readoiut modes. So far only the 1x2 module mode is
|
||||||
|
% implemented.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% none
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% January 31st 2009: add arbitrary ROIs via named parameters
|
||||||
|
%
|
||||||
|
% May 9th 2008: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [valid_mask] = pilatus_valid_pixel_roi(valid_mask,varargin)
|
||||||
|
|
||||||
|
% sub-detector readout size
|
||||||
|
roi_size = [];
|
||||||
|
|
||||||
|
% alternatively:
|
||||||
|
% from/to row 0 means all rows
|
||||||
|
row_from = 0;
|
||||||
|
row_to = 0;
|
||||||
|
% from/to column 0 means all lines
|
||||||
|
column_from = 0;
|
||||||
|
column_to = 0;
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if ((nargin < 1) || (rem(no_of_in_arg,2) ~= 1))
|
||||||
|
fprintf('Usage:\n')
|
||||||
|
fprintf('%s(valid_mask,[[<name>,<value>], ...]);\n',mfilename);
|
||||||
|
fprintf('The name value pairs are:\n');
|
||||||
|
fprintf('''RoiSize'',[<size-y> <size-x>] size of sub-detector readout ROIs\n');
|
||||||
|
fprintf('Alternatively:\n');
|
||||||
|
fprintf('''RowFrom'',<0-max> region of interest definition, 0 for full frame\n');
|
||||||
|
fprintf('''RowTo'',<0-max> region of interest definition, 0 for full frame\n');
|
||||||
|
fprintf('''ColumnFrom'',<0-max> region of interest definition, 0 for full frame\n');
|
||||||
|
fprintf('''ColumnTo'',<0-max> region of interest definition, 0 for full frame\n');
|
||||||
|
fprintf('''ROI'',s[ <ColumnFrom> <RowFrom> <ColumnTo> <RowTo> ]\n');
|
||||||
|
fprintf(' region of interest definition of all four coordinates together\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'ROI'
|
||||||
|
if (length(value) ~= 4)
|
||||||
|
error('The ROI parameter needs a vector of length four as argument.');
|
||||||
|
end
|
||||||
|
column_from = value(1);
|
||||||
|
row_from = value(2);
|
||||||
|
column_to = value(3);
|
||||||
|
row_to = value(4);
|
||||||
|
case 'RowFrom'
|
||||||
|
row_from = value;
|
||||||
|
roi_size = [];
|
||||||
|
case 'RowTo'
|
||||||
|
row_to = value;
|
||||||
|
roi_size = [];
|
||||||
|
case 'ColumnFrom'
|
||||||
|
column_from = value;
|
||||||
|
roi_size = [];
|
||||||
|
case 'ColumnTo'
|
||||||
|
column_to = value;
|
||||||
|
roi_size = [];
|
||||||
|
case 'RoiSize'
|
||||||
|
roi_size = value;
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% if (valid_mask.framesize ~= [1679 1475])
|
||||||
|
% error('can not handle the source size (%d,%d)',...
|
||||||
|
% valid_mask.framesize(1),valid_mask.framesize(2));
|
||||||
|
% end
|
||||||
|
|
||||||
|
|
||||||
|
if (isempty(roi_size))
|
||||||
|
if (row_from < 1)
|
||||||
|
row_from = 1;
|
||||||
|
end
|
||||||
|
if (row_to < 1)
|
||||||
|
row_to = valid_mask.framesize(1);
|
||||||
|
end
|
||||||
|
if (column_from < 1)
|
||||||
|
column_from = 1;
|
||||||
|
end
|
||||||
|
if (column_to < 1)
|
||||||
|
column_to = valid_mask.framesize(2);
|
||||||
|
end
|
||||||
|
% nothing to do
|
||||||
|
if ((row_from == 1) && (column_from == 1) && ...
|
||||||
|
(row_to == valid_mask.framesize(1)) && (column_to == valid_mask.framesize(2)))
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
x_from = column_from;
|
||||||
|
y_from = row_from;
|
||||||
|
roi_size = [ row_to-row_from+1 column_to-column_from+1 ];
|
||||||
|
else
|
||||||
|
% nothing to do
|
||||||
|
if (valid_mask.framesize == roi_size)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
% determine the location of the ROI from its size via the known modi
|
||||||
|
x_from = 0;
|
||||||
|
y_from = 0;
|
||||||
|
% two modules
|
||||||
|
if (roi_size == [407 487])
|
||||||
|
x_from = 495;
|
||||||
|
y_from = 637;
|
||||||
|
end
|
||||||
|
if (roi_size == [831 1475])
|
||||||
|
x_from = 1;
|
||||||
|
y_from = 425;
|
||||||
|
end
|
||||||
|
if (roi_size == [831 981])
|
||||||
|
x_from = 495;
|
||||||
|
y_from = 425;
|
||||||
|
end
|
||||||
|
if ((x_from == 0) || (y_from == 0))
|
||||||
|
error('can not handle the ROI size (%d,%d)',roi_size(1),roi_size(2));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% create the full valid pixel mask
|
||||||
|
vpm = zeros(valid_mask.framesize);
|
||||||
|
vpm(valid_mask.indices) = 1;
|
||||||
|
% cut out the region of interest
|
||||||
|
vpm = vpm(y_from:(y_from+roi_size(1)-1), ...
|
||||||
|
x_from:(x_from+roi_size(2)-1));
|
||||||
|
|
||||||
|
% return the indices of valid pixels within this ROI
|
||||||
|
valid_mask.indices = find(vpm == 1);
|
||||||
|
valid_mask.framesize = size(vpm);
|
||||||
@@ -0,0 +1,456 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: prep_integ_masks.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.9 $ $Date: 2016/01/21 14:51:57 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% prepare masks for the radial integration of SAXS patterns
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read
|
||||||
|
% - pilatus_valid_pixel_roi
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% September 4th 2009:
|
||||||
|
% correct in help text one of the RadiusFrom to RadiusTo
|
||||||
|
%
|
||||||
|
% May 9th 2008: 1st documented version
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ integ_masks ] = prep_integ_masks(filename, center_xy, varargin)
|
||||||
|
import beamline.pilatus_valid_pixel_roi
|
||||||
|
import io.image_read
|
||||||
|
import plotting.display_valid_mask
|
||||||
|
import utils.pixel_to_q
|
||||||
|
|
||||||
|
% set number of radii
|
||||||
|
no_of_radii = 0;
|
||||||
|
% number of angular segments per radius
|
||||||
|
no_of_segments = 1;
|
||||||
|
% pixel size in mm
|
||||||
|
pixel_size_mm = [];%.172;
|
||||||
|
% detector distance in mm
|
||||||
|
det_dist_mm = [];%2000;
|
||||||
|
calculate_q=0; %only calculate q if exact detector distance is given
|
||||||
|
% wavelength (unit inconsequential, will be reflected in q)
|
||||||
|
lambda = [];%1;
|
||||||
|
% output directory for the masks
|
||||||
|
out_dir = '~/Data10/analysis/data/';
|
||||||
|
filename_valid_mask = [ out_dir 'pilatus_valid_mask.mat' ];
|
||||||
|
filename_integ_masks = [ out_dir 'pilatus_integration_masks.mat' ];
|
||||||
|
% output figure number
|
||||||
|
fig_no = 240;
|
||||||
|
% save integration masks
|
||||||
|
save_data = 1;
|
||||||
|
% display valid pixel mask
|
||||||
|
display_valid_mask_flag = 1;
|
||||||
|
% detector number
|
||||||
|
det_no= 1;
|
||||||
|
% angular range to be excluded to cut out the beam stop
|
||||||
|
bs_angle_from = 0;
|
||||||
|
bs_angle_to = 0;
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 2)
|
||||||
|
fprintf('\nUsage:\n');
|
||||||
|
fprintf('[integ_masks]=%s( filename, center_xy [[,<name>,<value>]...]);\n',mfilename);
|
||||||
|
fprintf('Prepare the masks for an efficient radial integration.\n');
|
||||||
|
fprintf('The optional angular range in degree can be used to cut out a beam stop.\n');
|
||||||
|
fprintf('Angle 0 is horizontally to the left, positive in counterclockwise direction.\n');
|
||||||
|
fprintf('The specified data file is loaded and some of the integration masks are plotted into that frame.\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
|
||||||
|
fprintf('''NormalXY'',[x y] pixel coordinates, from where the detector normal points\n');
|
||||||
|
fprintf(' toward the sample. Default is equal to center_xy\n');
|
||||||
|
fprintf('''PixelSize_mm'',<double> pixel size in mm, default is %.3f\n',pixel_size_mm);
|
||||||
|
fprintf('''DetDist_mm'',<double> detector distance in mm, default is %.1f\n',det_dist_mm);
|
||||||
|
fprintf('''Wavelength'',<double> wavelength. The units chosen here will determine the units of q\n');
|
||||||
|
fprintf(' The defaults is %.1f\n',lambda);
|
||||||
|
fprintf('''NoOfRadii'',<integer> radial integration start radius, default is %d\n',no_of_radii);
|
||||||
|
fprintf(' or ,<vector>, defining the limits of radius bins\n');
|
||||||
|
fprintf('''NoOfSegments'',<integer> Number of angular segments. If an integer, this number of equally wide azimuthal\n')
|
||||||
|
fprintf(' bins over 360 degrees are created. default is %d\n',no_of_segments);
|
||||||
|
fprintf(' or ,<vector>, defining the limits of angular bins\n');
|
||||||
|
fprintf('''SaveData'',<0-no,1-yes> save the integration masks, default is %d\n',save_data);
|
||||||
|
fprintf('''FilenameValidMask'',<path and filename> Matlab file with the valid pixel indices ind_valid,\n');
|
||||||
|
fprintf(' default is %s\n',filename_valid_mask);
|
||||||
|
fprintf('''FilenameIntegMasks'',<path and filename> output file name for the structure integ_masks,\n');
|
||||||
|
fprintf(' default is %s\n',filename_integ_masks);
|
||||||
|
fprintf('''FigNo'',<integer> number of the figure in which the result is displayed\n');
|
||||||
|
fprintf('''DetNo'',<integer> number of detector 1 for SAXS and 2 for WAXS\n');
|
||||||
|
fprintf(' Default is 1 (SAXS)\n');
|
||||||
|
fprintf('''BeamstopAngleFrom'',<float> exclude an angular region from the integration, default for the start value is %d\n',...
|
||||||
|
bs_angle_from);
|
||||||
|
fprintf('''BeamstopAngleTo'',<float> exclude an angular region from the integration, default for the end value is %d\n',...
|
||||||
|
bs_angle_to);
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The file name should be the name of a single file without wildcards\n');
|
||||||
|
fprintf('that is displayed as an example.\n');
|
||||||
|
fprintf('The image file has no other function beyond being displayed as example.\n');
|
||||||
|
fprintf('Example:\n');
|
||||||
|
fprintf('[integ_masks]=%s(''~/Data10/pilatus/image.cbf'',[512 512]);\n',...
|
||||||
|
mfilename);
|
||||||
|
|
||||||
|
error('At least the filename and the beam center have to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of center coordinates
|
||||||
|
if (length(center_xy) ~= 2)
|
||||||
|
error('The beam center needs to be specified as a two component vector [cen_x cen_y].\n');
|
||||||
|
end
|
||||||
|
center_x = center_xy(1);
|
||||||
|
center_y = center_xy(2);
|
||||||
|
norm_x = center_x;
|
||||||
|
norm_y = center_y;
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 3)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 2 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 0)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'NormalXY'
|
||||||
|
if (numel(value)==2)
|
||||||
|
norm_x = value(1);
|
||||||
|
norm_y = value(2);
|
||||||
|
end
|
||||||
|
case 'PixelSize_mm'
|
||||||
|
pixel_size_mm = value;
|
||||||
|
case 'DetDist_mm'
|
||||||
|
det_dist_mm = value;
|
||||||
|
calculate_q=1;
|
||||||
|
case 'Wavelength_nm'
|
||||||
|
lambda = value;
|
||||||
|
case 'Wavelength'
|
||||||
|
lambda = value/10;
|
||||||
|
case 'NoOfRadii'
|
||||||
|
no_of_radii = value;
|
||||||
|
case 'NoOfSegments'
|
||||||
|
no_of_segments = value;
|
||||||
|
case 'FilenameValidMask'
|
||||||
|
filename_valid_mask = value;
|
||||||
|
case 'FilenameIntegMasks'
|
||||||
|
filename_integ_masks = value;
|
||||||
|
case 'SaveData'
|
||||||
|
save_data = value;
|
||||||
|
case 'DisplayValidMask'
|
||||||
|
display_valid_mask_flag = value;
|
||||||
|
case 'FigNo'
|
||||||
|
fig_no = value;
|
||||||
|
case 'DetNo'
|
||||||
|
det_no = value;
|
||||||
|
case 'BeamstopAngleFrom'
|
||||||
|
bs_angle_from = value;
|
||||||
|
case 'BeamstopAngleTo'
|
||||||
|
bs_angle_to = value;
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% MGS - The fact that the detector number is dictating whether to have a
|
||||||
|
% radius variable or q is not ideal. Additional arguments should be given
|
||||||
|
% for this such as calculate_q or save_radius_var.
|
||||||
|
% initialize return arguments
|
||||||
|
if (det_no == 1)||(det_no == 3)
|
||||||
|
calculate_radius = true;
|
||||||
|
elseif (det_no == 2)
|
||||||
|
calculate_radius = false;
|
||||||
|
else
|
||||||
|
error('Only det_no 1, 2, and 3 are recognized')
|
||||||
|
end
|
||||||
|
if ( calculate_radius ) && (calculate_q)
|
||||||
|
integ_masks = struct('radius',[], 'indices',[], 'norm_sum', [],'q',[]);
|
||||||
|
elseif (calculate_radius) && (calculate_q == 0)
|
||||||
|
integ_masks = struct('radius',[], 'indices',[], 'norm_sum', []);
|
||||||
|
elseif (~calculate_radius)
|
||||||
|
integ_masks = struct('indices',[], 'norm_sum', [],'q',[]);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% check radius
|
||||||
|
%if (exist('r_from','var'))
|
||||||
|
if (size(no_of_radii)>1)
|
||||||
|
if (no_of_radii(1) < 1)
|
||||||
|
%if (r_from < 1)
|
||||||
|
error('The minimum radius is 1, %d is invalid.',r_from);
|
||||||
|
end
|
||||||
|
%end
|
||||||
|
%if (exist('r_from','var') && exist('r_to','var'))
|
||||||
|
if (no_of_radii(end) < no_of_radii(1))
|
||||||
|
%if ((r_to ~= 0) && (r_to < r_from))
|
||||||
|
error('The maximum radius must be greater than the minimum one, %d is invalid.\n',no_of_radii(end));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of angular segments
|
||||||
|
if (no_of_segments < 1)
|
||||||
|
error('The number of angular segments must be at least 1');
|
||||||
|
end
|
||||||
|
if (numel(no_of_segments)>1)
|
||||||
|
angular_segments = no_of_segments;
|
||||||
|
no_of_segments = numel(no_of_segments)-1;
|
||||||
|
else
|
||||||
|
angular_segments = 360/no_of_segments * (0:no_of_segments);
|
||||||
|
end
|
||||||
|
angular_segments = mod(angular_segments, 360);
|
||||||
|
|
||||||
|
% check beamstop region
|
||||||
|
if ((bs_angle_from < 0.0) || (bs_angle_to > 360.0))
|
||||||
|
error('The angular range for the beam stop region is 0 to 360 degree.');
|
||||||
|
end
|
||||||
|
if (bs_angle_to < bs_angle_from)
|
||||||
|
error('The maximum beam stop angle must be less than or equal to the minimum one.\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
% load the indices of valid pixels
|
||||||
|
fprintf('loading the valid pixel mask %s\n',filename_valid_mask);
|
||||||
|
load(filename_valid_mask);
|
||||||
|
dim_x = valid_mask.framesize(2);
|
||||||
|
dim_y = valid_mask.framesize(1);
|
||||||
|
|
||||||
|
|
||||||
|
if (~isempty(filename))
|
||||||
|
% load test frame
|
||||||
|
frame = image_read(filename,vararg);
|
||||||
|
% select the first frame for display
|
||||||
|
frame.data = frame.data(:,:,1);
|
||||||
|
% in case of less than full detector readout cut out the right part of
|
||||||
|
% the valid pixel mask
|
||||||
|
valid_mask = pilatus_valid_pixel_roi(valid_mask,'RoiSize',size(frame.data));
|
||||||
|
dim_x = size(frame.data,2);
|
||||||
|
dim_y = size(frame.data,1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% plot valid pixel mask
|
||||||
|
if (display_valid_mask_flag)
|
||||||
|
figure(fig_no);
|
||||||
|
vpm = zeros(dim_y,dim_x);
|
||||||
|
vpm(valid_mask.indices) = 1;
|
||||||
|
imagesc(vpm);
|
||||||
|
axis xy;
|
||||||
|
axis equal;
|
||||||
|
axis tight;
|
||||||
|
title('valid pixels');
|
||||||
|
set(gcf,'Name','valid pixels');
|
||||||
|
drawnow;
|
||||||
|
end
|
||||||
|
|
||||||
|
if calculate_radius
|
||||||
|
%if (exist('r_to','var'))
|
||||||
|
% choose maximum radius, if specified via r_to=0
|
||||||
|
if (no_of_radii < 1)
|
||||||
|
no_of_radii = max( [ sqrt(center_x^2+center_y^2) ...
|
||||||
|
sqrt((dim_x-center_x)^2+center_y^2) ...
|
||||||
|
sqrt(center_x^2+(dim_y-center_y)^2) ...
|
||||||
|
sqrt((dim_x-center_x)^2+(dim_y-center_y)^2) ] );
|
||||||
|
end
|
||||||
|
if size(no_of_radii)==1
|
||||||
|
no_of_radii=1:1:no_of_radii;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fprintf('preparing the integration masks ...\n');
|
||||||
|
|
||||||
|
% create an array of the (x,y) coordinates relative to the beam center and
|
||||||
|
% convert it to polar coordinates
|
||||||
|
%
|
||||||
|
if calculate_radius % For SAXS detector - MGS, should be fixed, why is it neded different calculation for different detectors?
|
||||||
|
% angular range to be excluded to cut out the beam stop
|
||||||
|
|
||||||
|
[ x, y ] = meshgrid( (1:dim_x)-center_x, (1:dim_y)-center_y );
|
||||||
|
[ theta, rho ] = cart2pol( x, y );
|
||||||
|
% convert angular range from -pi/pi to 0/360
|
||||||
|
theta = (theta/pi +1) * 180.0;
|
||||||
|
|
||||||
|
% prepare circular masks of the integer width r_step (in pixel)
|
||||||
|
integ_masks.radius = no_of_radii;
|
||||||
|
r_step=no_of_radii(2)-no_of_radii(1);
|
||||||
|
if calculate_q
|
||||||
|
integ_masks.q = pixel_to_q(no_of_radii,pixel_size_mm,det_dist_mm, 12.39852/lambda);
|
||||||
|
end
|
||||||
|
no_of_radii = length(integ_masks.radius);
|
||||||
|
integ_masks.indices = cell( no_of_radii, no_of_segments );
|
||||||
|
integ_masks.norm_sum = zeros( no_of_radii, no_of_segments );
|
||||||
|
seg_inds = cell(no_of_segments,1);
|
||||||
|
for ind_seg = 1:no_of_segments
|
||||||
|
seg_from = angular_segments(ind_seg);
|
||||||
|
seg_to = angular_segments(ind_seg+1);
|
||||||
|
if (seg_from >= seg_to)
|
||||||
|
ind_curr = find( ((theta > seg_from) | (theta <= seg_to) ) & ...
|
||||||
|
((theta <= bs_angle_from) | (theta >= bs_angle_to)) );
|
||||||
|
else
|
||||||
|
ind_curr = find( ((theta > seg_from) & (theta <= seg_to) ) & ...
|
||||||
|
((theta <= bs_angle_from) | (theta >= bs_angle_to)) );
|
||||||
|
end
|
||||||
|
% only take valid pixels into account
|
||||||
|
ind_curr = intersect(ind_curr, valid_mask.indices);
|
||||||
|
seg_inds{ind_seg} = ind_curr;
|
||||||
|
end
|
||||||
|
|
||||||
|
for ind_r=1:no_of_radii
|
||||||
|
if (rem(ind_r,100) == 0)
|
||||||
|
fprintf('%4d / %d',ind_r,no_of_radii);
|
||||||
|
if (ind_r <= no_of_radii-100)
|
||||||
|
fprintf(', ');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
r_inds = find( (rho >= integ_masks.radius(ind_r)) & ...
|
||||||
|
(rho < integ_masks.radius(ind_r)+r_step) );
|
||||||
|
for ind_seg = 1:no_of_segments
|
||||||
|
integ_masks.indices{ind_r, ind_seg} = intersect( r_inds, seg_inds{ind_seg} );
|
||||||
|
% calculate the normalization value (sum of the pixels within the mask)
|
||||||
|
integ_masks.norm_sum(ind_r, ind_seg) = ...
|
||||||
|
length( integ_masks.indices{ind_r, ind_seg} );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
fprintf('\n');
|
||||||
|
|
||||||
|
else
|
||||||
|
[ x, y ] = meshgrid( (1:dim_x)-norm_x, (1:dim_y)-norm_y );
|
||||||
|
if (norm_x == center_x && norm_y == center_y)
|
||||||
|
[ theta, rho ] = cart2pol( x, y );
|
||||||
|
q = 4*pi/lambda*sin(atan2(rho,det_dist_mm/pixel_size_mm)/2);
|
||||||
|
% convert angular range from -pi/pi to 0/360
|
||||||
|
theta = theta/pi*180.0;
|
||||||
|
else
|
||||||
|
if (norm_x ~= center_x)
|
||||||
|
angle = atan((norm_x - center_x) / (det_dist_mm/pixel_size_mm));
|
||||||
|
z = -x*sin(angle) + det_dist_mm/pixel_size_mm*cos(angle);
|
||||||
|
x = x*cos(angle) + det_dist_mm/pixel_size_mm*sin(angle);
|
||||||
|
else
|
||||||
|
fprintf('not implemented yet!!!\n');
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
q = 4*pi/lambda*sin(atan2(sqrt(x.^2 + y.^2),z)/2);
|
||||||
|
theta = atan2(y,x)/pi*180;
|
||||||
|
end
|
||||||
|
t_1d = reshape(theta(valid_mask.indices),1,[]);
|
||||||
|
q_1d = reshape(q(valid_mask.indices),1,[]);
|
||||||
|
|
||||||
|
t_ed = linspace( -180, 180,1e0+1);
|
||||||
|
integ_masks.theta = t_ed(1:end-1);
|
||||||
|
integ_masks.theta_end = t_ed(end);
|
||||||
|
q_ed = linspace(min(q_1d),max(q_1d),1e3+1);
|
||||||
|
integ_masks.q = q_ed(1:end-1);
|
||||||
|
integ_masks.q_end = q_ed(end);
|
||||||
|
|
||||||
|
[~,t_bin] = histc(t_1d,t_ed);
|
||||||
|
[~,q_bin] = histc(q_1d,q_ed);
|
||||||
|
|
||||||
|
integ_masks.indices = cell(numel(q_ed)-1,numel(t_ed)-1);
|
||||||
|
integ_masks.norm_sum = zeros(size(integ_masks.indices));
|
||||||
|
for q_i=1:numel(q_ed)-1
|
||||||
|
for t_i=1:numel(t_ed)-1
|
||||||
|
integ_masks.indices{q_i,t_i} = ...
|
||||||
|
valid_mask.indices(and(q_bin==q_i,t_bin==t_i));
|
||||||
|
integ_masks.norm_sum(q_i,t_i) = numel(integ_masks.indices{q_i,t_i});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% save integration masks
|
||||||
|
if (save_data)
|
||||||
|
fprintf('Saving center_xy, no_of_segments, integ_masks to %s\n',...
|
||||||
|
filename_integ_masks);
|
||||||
|
if angular_segments(end) == 0
|
||||||
|
angular_segments(end) = 360;
|
||||||
|
end
|
||||||
|
phi_det = (angular_segments(2:end) + angular_segments(1:end-1))/2; %% Center of the angular sector in degrees
|
||||||
|
save(filename_integ_masks,'center_xy','no_of_segments','integ_masks','angular_segments','phi_det');
|
||||||
|
end
|
||||||
|
|
||||||
|
% display some integration circles
|
||||||
|
if (~isempty(filename))
|
||||||
|
figure(fig_no+1);
|
||||||
|
hold off;
|
||||||
|
clf;
|
||||||
|
frame_plot = double(frame.data);
|
||||||
|
frame_plot( frame_plot < 1 ) = 1;
|
||||||
|
|
||||||
|
plot_step = round(length(integ_masks.indices)/50);
|
||||||
|
if (plot_step < 2)
|
||||||
|
plot_step = 2;
|
||||||
|
end
|
||||||
|
for (ind_r = 1:plot_step:size(integ_masks.indices,1))
|
||||||
|
for (ind_seg = 1:2:no_of_segments)
|
||||||
|
frame_plot(integ_masks.indices{ind_r,ind_seg}) = 10^(6*ind_seg/no_of_segments);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
imagesc(log10(frame_plot));
|
||||||
|
axis xy;
|
||||||
|
axis equal;
|
||||||
|
axis tight;
|
||||||
|
colorbar;
|
||||||
|
title([ 'integration segment test plot for ' strrep(filename,'_','\_') ]);
|
||||||
|
set(gcf,'Name','integration masks');
|
||||||
|
end
|
||||||
@@ -0,0 +1,345 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: prep_valid_mask.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.8 $ $Date: 2016/01/21 15:07:41 $
|
||||||
|
% $Author: guizar_m $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% prepare a list of the linear indices for the valid pixels
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% May 15th 2010, Oliver Bunk:
|
||||||
|
% add command line argument for ThresholdMedian
|
||||||
|
%
|
||||||
|
% September 4th 2009, Oliver Bunk:
|
||||||
|
% use find_files rather than dir to find the files
|
||||||
|
%
|
||||||
|
% May 9th 2008, Oliver Bunk: 1st documented version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
function [valid_mask] = prep_valid_mask(data_dir, varargin)
|
||||||
|
import io.image_read
|
||||||
|
import plotting.display_valid_mask
|
||||||
|
import utils.find_files
|
||||||
|
|
||||||
|
% initialize return arguments
|
||||||
|
valid_mask = struct('indices',[], 'framesize',[]);
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
% use all cbf files
|
||||||
|
filename_mask = '*.cbf';
|
||||||
|
% filename for loading and saving the valid pixel mask
|
||||||
|
filename_valid_mask = '~/Data10/analysis/data/pilatus_valid_mask.mat';
|
||||||
|
% below this threshold intensity a pixel is considered to be dark
|
||||||
|
threshold_dark = 1;
|
||||||
|
% above this threshold intensity a pixel is considered to be hot
|
||||||
|
threshold_hot = 20;
|
||||||
|
% this value times the square root of the intensity is used as hot pixel
|
||||||
|
% threshold
|
||||||
|
threshold_median = 5.0;
|
||||||
|
% replace the existing mask
|
||||||
|
extend = 'no';
|
||||||
|
% save the mask
|
||||||
|
save_data = 1;
|
||||||
|
% display result in this figure
|
||||||
|
fig_no = 200;
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
fprintf('\nUsage:\n');
|
||||||
|
fprintf('[valid_mask]=%s(data_dir [[,<name>,<value>]...]);\n',mfilename);
|
||||||
|
fprintf('Prepare a list of the linear indices for the valid pixels.\n');
|
||||||
|
fprintf('To get reliable data a series of at least 10 frames should be analyzed.\n');
|
||||||
|
fprintf('The direct beam region will be regarded as invalid since it is out of the\n');
|
||||||
|
fprintf('range for valid pixels. To ''repair'' this one should take a second series of\n');
|
||||||
|
fprintf('exposures at a different detector position and call this macro with the ''Extend'',''or''\n');
|
||||||
|
fprintf('option.\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''FilenameMask'',<file specifier> specify the files to be used from the data directory, empty string for all, default is ''%s''\n',...
|
||||||
|
filename_mask);
|
||||||
|
fprintf('''ThresholdDark'',<float> pixels permanently below this value are considered to be dark, default is %d\n',...
|
||||||
|
threshold_dark);
|
||||||
|
fprintf('''ThresholdHot'',<float> pixels at least once above this value are considered to be hot, default is %d\n',...
|
||||||
|
threshold_hot);
|
||||||
|
fprintf('''ThresholdMedian'',<float> pixels of intensity I above the constant ThresholdHot and above\n');
|
||||||
|
fprintf(' ThresholdMedian times (I+sqrt(I)) are considered to be hot, 0 to deactivate this additional threshold,\n');
|
||||||
|
fprintf(' default is %.1f\n',...
|
||||||
|
threshold_median);
|
||||||
|
fprintf('''SaveData'',<0-no,1-yes> save the valid pixel mask, default is %d\n',save_data);
|
||||||
|
fprintf('''FilenameValidMask'',<path and filename> Matlab file with the valid pixel indices,\n');
|
||||||
|
fprintf(' default is %s\n',filename_valid_mask);
|
||||||
|
fprintf('''Extend'',<''and'', ''or'' or ''no''> update an existing mask using the specified conjunction, default is %s\n',...
|
||||||
|
extend);
|
||||||
|
fprintf('''FigNo'',<integer> number of the figure in which the result is displayed, default is %d\n',...
|
||||||
|
fig_no);
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('Examples:\n');
|
||||||
|
fprintf('[valid_mask]=%s(''~/Data10/pilatus/air_scattering/'');\n',...
|
||||||
|
mfilename);
|
||||||
|
fprintf('[valid_mask]=%s(''~/Data10/pilatus/air_scattering_det_pos_2/'',''Extend'',''or'');\n',...
|
||||||
|
mfilename);
|
||||||
|
|
||||||
|
error('At least the data directory has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = no_of_in_arg -1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments:
|
||||||
|
% initialize the list of unhandled parameters
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'ThresholdDark'
|
||||||
|
threshold_dark = value;
|
||||||
|
case 'ThresholdHot'
|
||||||
|
threshold_hot = value;
|
||||||
|
case 'ThresholdMedian'
|
||||||
|
threshold_median = value;
|
||||||
|
case 'FilenameMask'
|
||||||
|
filename_mask = value;
|
||||||
|
case 'FilenameValidMask'
|
||||||
|
filename_valid_mask = value;
|
||||||
|
case 'SaveData'
|
||||||
|
save_data = value;
|
||||||
|
case 'FigNo'
|
||||||
|
fig_no = value;
|
||||||
|
case 'Extend'
|
||||||
|
extend = value;
|
||||||
|
otherwise
|
||||||
|
vararg_remain{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg_remain{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vararg_remain{end+1} = 'UnhandledParError';
|
||||||
|
vararg_remain{end+1} = 0;
|
||||||
|
|
||||||
|
% check extend parameter
|
||||||
|
if ((~strcmp(extend,'no')) && ...
|
||||||
|
(~strcmp(extend,'and')) && (~strcmp(extend,'or')))
|
||||||
|
error('extend must be ''and'', ''or'' or ''no''\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
% set some default values for the plot window
|
||||||
|
set(0, 'DefaultAxesfontsize', 12);
|
||||||
|
set(0, 'DefaultAxeslinewidth', 1, 'DefaultAxesfontsize', 12);
|
||||||
|
set(0, 'DefaultLinelinewidth', 1);
|
||||||
|
|
||||||
|
% get all matching filenames
|
||||||
|
if (data_dir(end) ~= '/')
|
||||||
|
data_dir(end+1) = '/';
|
||||||
|
end
|
||||||
|
[data_dir,fnames,vararg_remain] = ...
|
||||||
|
find_files( [ data_dir filename_mask ], vararg_remain );
|
||||||
|
|
||||||
|
if (length(fnames) < 1)
|
||||||
|
error('No matching files found for %s%s.\n',data_dir,filename_mask);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (~strcmp(extend,'no'))
|
||||||
|
if exist(filename_valid_mask,'file')
|
||||||
|
fprintf('loading the existing valid mask %s\n', ...
|
||||||
|
filename_valid_mask);
|
||||||
|
load(filename_valid_mask);
|
||||||
|
ind_existing_valid = valid_mask.indices;
|
||||||
|
else
|
||||||
|
fprintf('no prior valid mask %s found\n', ...
|
||||||
|
filename_valid_mask);
|
||||||
|
ind_existing_valid = '';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% process the frames
|
||||||
|
ind_hot = [];
|
||||||
|
ind_dark = [];
|
||||||
|
fprintf('data directory is %s\n',data_dir);
|
||||||
|
for (f_ind=1:length(fnames))
|
||||||
|
fprintf('%3d/%3d: reading %s%s\n',f_ind,length(fnames),...
|
||||||
|
data_dir,fnames(f_ind).name);
|
||||||
|
[frame] = image_read([data_dir fnames(f_ind).name ],vararg_remain);
|
||||||
|
frame.data = double(frame.data);
|
||||||
|
for (frame_ind = 1:size(frame.data,3))
|
||||||
|
% median filtered data for comparison
|
||||||
|
if (threshold_median ~= 0)
|
||||||
|
data_med = frame.data(:,:,frame_ind);
|
||||||
|
|
||||||
|
% add pixels at the module boundary to ease median filtering
|
||||||
|
ind = find(data_med == 0);
|
||||||
|
data_med_shift = circshift(data_med,[2 2]);
|
||||||
|
data_med(ind) = data_med_shift(ind);
|
||||||
|
|
||||||
|
ind = find(data_med == 0);
|
||||||
|
data_med_shift = circshift(data_med,[-2 -2]);
|
||||||
|
data_med(ind) = data_med_shift(ind);
|
||||||
|
|
||||||
|
ind = find(data_med == 0);
|
||||||
|
data_med_shift = circshift(data_med,[-2 2]);
|
||||||
|
data_med(ind) = data_med_shift(ind);
|
||||||
|
|
||||||
|
ind = find(data_med == 0);
|
||||||
|
data_med_shift = circshift(data_med,[2 -2]);
|
||||||
|
data_med(ind) = data_med_shift(ind);
|
||||||
|
|
||||||
|
% median filter the data
|
||||||
|
data_med = medfilt2(data_med,[5 5]);
|
||||||
|
|
||||||
|
% the square root of the intensity estimates the standard deviation
|
||||||
|
data_med_sqrt = data_med.^0.5;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (f_ind == 1)
|
||||||
|
framesize1 = size(frame.data,1);
|
||||||
|
framesize2 = size(frame.data,2);
|
||||||
|
framesize = framesize1 * framesize2;
|
||||||
|
end
|
||||||
|
|
||||||
|
% check that the file have identical dimensions
|
||||||
|
if ((framesize1 ~= size(frame.data,1)) || ...
|
||||||
|
(framesize2 ~= size(frame.data,2)))
|
||||||
|
error('The previous file(s) had %d x %d pixels, this frame has %d x %d pixels',...
|
||||||
|
framesize1,framesize2,size(frame.data,1),size(frame.data,2));
|
||||||
|
end
|
||||||
|
|
||||||
|
% pixels are considered to be dark if the intensity is below the
|
||||||
|
% constant threshold
|
||||||
|
ind = find(frame.data(:,:,frame_ind) < threshold_dark);
|
||||||
|
fprintf('%6d dark pixels below %10.3e counts, ', ...
|
||||||
|
length(ind),threshold_dark);
|
||||||
|
if (f_ind == 1)
|
||||||
|
ind_dark = ind;
|
||||||
|
else
|
||||||
|
% dark pixels must be dark in all frames
|
||||||
|
ind_dark = intersect(ind_dark,ind);
|
||||||
|
end
|
||||||
|
|
||||||
|
% hot pixels are hot if they are above the threshold
|
||||||
|
ind = find(frame.data(:,:,frame_ind) > threshold_hot);
|
||||||
|
% and, if active, above the intensity plus a threshold times the square
|
||||||
|
% root of the intensity as an estimation of the countin statistics
|
||||||
|
% error
|
||||||
|
if (threshold_median ~= 0.0)
|
||||||
|
ind = intersect(ind,find((frame.data(:,:,frame_ind) > data_med+threshold_median*data_med_sqrt)));
|
||||||
|
fprintf('%4d hot pixels above %d and %.1f * sqrt(intensity) counts\n', ...
|
||||||
|
length(ind),threshold_hot,threshold_median);
|
||||||
|
else
|
||||||
|
fprintf('%4d hot pixels above %d counts\n', ...
|
||||||
|
length(ind),threshold_hot);
|
||||||
|
end
|
||||||
|
% for hot pixels it is enough to be above the threshold in one frame
|
||||||
|
ind_hot = union(ind_hot,ind);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% calculate the complementary masks of the valid pixels
|
||||||
|
valid_mask.indices = setdiff(1:framesize,union(ind_dark,ind_hot));
|
||||||
|
|
||||||
|
fprintf('In total %d dark and %d hot pixels found.\n',...
|
||||||
|
length(ind_dark),length(ind_hot));
|
||||||
|
fprintf('%d valid pixels remain.\n',length(valid_mask.indices));
|
||||||
|
|
||||||
|
if (~strcmp(extend,'no'))
|
||||||
|
fprintf('Extending the existing valid pixel mask of %d pixels\n',...
|
||||||
|
length(ind_existing_valid));
|
||||||
|
if (strcmp(extend,'and'))
|
||||||
|
fprintf('using the and conjugation\n');
|
||||||
|
valid_mask.indices = ...
|
||||||
|
intersect(valid_mask.indices,ind_existing_valid);
|
||||||
|
else
|
||||||
|
fprintf('using the or conjugation\n');
|
||||||
|
if ~isempty(ind_existing_valid)
|
||||||
|
valid_mask.indices = ...
|
||||||
|
union(valid_mask.indices,ind_existing_valid);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
fprintf('The combined mask has %d valid pixels.\n',...
|
||||||
|
length(valid_mask.indices));
|
||||||
|
end
|
||||||
|
|
||||||
|
% store the frame size in the return data
|
||||||
|
valid_mask.framesize = [framesize1 framesize2];
|
||||||
|
|
||||||
|
if (save_data)
|
||||||
|
% create a backup of the mask
|
||||||
|
if (exist(filename_valid_mask,'file'))
|
||||||
|
filename_mask_backup = [ filename_valid_mask '.bak' ];
|
||||||
|
fprintf('Copying the current mask %s to %s\n',filename_valid_mask,...
|
||||||
|
filename_mask_backup);
|
||||||
|
copyfile(filename_valid_mask,filename_mask_backup);
|
||||||
|
end
|
||||||
|
|
||||||
|
% save the masks
|
||||||
|
fprintf('Saving valid_mask to %s\n',filename_valid_mask);
|
||||||
|
save(filename_valid_mask,'valid_mask');
|
||||||
|
end
|
||||||
|
|
||||||
|
% plot new valid pixel mask
|
||||||
|
if (fig_no > 0)
|
||||||
|
display_valid_mask('FilenameValidMask',filename_valid_mask,...
|
||||||
|
'NoHelp',1,'FigNo',fig_no);
|
||||||
|
end
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,179 @@
|
|||||||
|
// RADIAL_INTEG_MEX perform radial integration for a 2D frame
|
||||||
|
//
|
||||||
|
// ** ind_r_max int32
|
||||||
|
// ** no_of_segments int32
|
||||||
|
// ** norm_sum double
|
||||||
|
// ** indices cell
|
||||||
|
// ** frame_data 2D or 3D array, double
|
||||||
|
//
|
||||||
|
// return:
|
||||||
|
// ++ frame_I 2D or 3D array, double
|
||||||
|
// ++ frame_std 2D or 3D array, double
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// [frame_I(:,:,ind_frame), frame_std(:,:,ind_frame)] = radial_integ_mex(int32(ind_r_max),int32(no_of_segments), integ_masks.norm_sum, integ_masks.indices, frame_data);
|
||||||
|
//
|
||||||
|
// compile with:
|
||||||
|
// mex 'CFLAGS="\$CFLAGS -O3 -std=c++17 -fopenmp"' LDFLAGS="\$LDFLAGS -fopenmp" radial_integ_mex.cpp
|
||||||
|
//
|
||||||
|
// MATLAB code:
|
||||||
|
// for (ind_r = 1:ind_r_max)
|
||||||
|
// for (ind_seg = 1:no_of_segments)
|
||||||
|
// if (integ_masks.norm_sum(ind_r,ind_seg) > 0)
|
||||||
|
// frame_I_one_frame(ind_r,ind_seg) = ...
|
||||||
|
// mean(frame_data(integ_masks.indices{ind_r,ind_seg}));
|
||||||
|
// frame_std_one_frame(ind_r,ind_seg) = ...
|
||||||
|
// std(frame_data(integ_masks.indices{ind_r,ind_seg}));
|
||||||
|
// else
|
||||||
|
// % mark unknown intensities
|
||||||
|
// frame_I_one_frame(ind_r,ind_seg) = -1;
|
||||||
|
// frame_std_one_frame(ind_r,ind_seg) = -1;
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
|
||||||
|
// *-----------------------------------------------------------------------*
|
||||||
|
// | |
|
||||||
|
// | Except where otherwise noted, this work is licensed under a |
|
||||||
|
// | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
// | International (CC BY-NC-SA 4.0) license. |
|
||||||
|
// | |
|
||||||
|
// | Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
// | |
|
||||||
|
// | Author: CXS group, PSI |
|
||||||
|
// *-----------------------------------------------------------------------*
|
||||||
|
// You may use this code with the following provisions:
|
||||||
|
//
|
||||||
|
// If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
// computing language this notice should be included in the redistribution.
|
||||||
|
//
|
||||||
|
// If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
// publication or if it is fully or partially rewritten for another
|
||||||
|
// computing language the authors and institution should be acknowledged
|
||||||
|
// in written form in the publication: “Data processing was carried out
|
||||||
|
// using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
// Paul Scherrer Institut, Switzerland.”
|
||||||
|
// Variations on the latter text can be incorporated upon discussion with
|
||||||
|
// the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
// for the published work.
|
||||||
|
//
|
||||||
|
// A publication that focuses on describing features, or parameters, that
|
||||||
|
// are already existing in the code should be first discussed with the
|
||||||
|
// authors.
|
||||||
|
//
|
||||||
|
// This code and subroutines are part of a continuous development, they
|
||||||
|
// are provided “as they are” without guarantees or liability on part
|
||||||
|
// of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
// proper use and the correctness of the results.
|
||||||
|
|
||||||
|
#include "mex.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <math.h>
|
||||||
|
#include <omp.h>
|
||||||
|
|
||||||
|
void mexFunction( int nlhs, mxArray *plhs[],
|
||||||
|
int nrhs, const mxArray *prhs[])
|
||||||
|
{
|
||||||
|
double *norm_sum;
|
||||||
|
double *frame_data;
|
||||||
|
uint ind_r_max, no_of_segments;
|
||||||
|
const mwSize *pDims;
|
||||||
|
int nDimNum;
|
||||||
|
int maxSlice;
|
||||||
|
|
||||||
|
/* check for proper number of arguments */
|
||||||
|
if(nrhs!=5) {
|
||||||
|
mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","Five inputs required.");
|
||||||
|
}
|
||||||
|
if(nlhs!=2) {
|
||||||
|
mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","Two output containers are required.");
|
||||||
|
}
|
||||||
|
/* make sure the first two input arguments are of type int */
|
||||||
|
if( !mxIsClass(prhs[0], "int32")) {
|
||||||
|
mexErrMsgIdAndTxt("cxsSoftware:radialIntegMex:notInteger","r_max must be of type integer.");
|
||||||
|
}
|
||||||
|
if( !mxIsClass(prhs[1], "int32")) {
|
||||||
|
mexErrMsgIdAndTxt("cxsSoftware:radialIntegMex:notInteger","no_of_segments must be of type integer.");
|
||||||
|
}
|
||||||
|
if( !mxIsClass(prhs[2], "double")) {
|
||||||
|
mexErrMsgIdAndTxt("cxsSoftware:radialIntegMex:notInteger","norm_sum must be of type double.");
|
||||||
|
}
|
||||||
|
if( !mxIsCell(prhs[3])) {
|
||||||
|
mexErrMsgIdAndTxt("cxsSoftware:radialIntegMex:notInteger","indices must be of type cell.");
|
||||||
|
}
|
||||||
|
if( !mxIsClass(prhs[4], "double")) {
|
||||||
|
mexErrMsgIdAndTxt("cxsSoftware:radialIntegMex:notInteger","frame_data must be of type double.");
|
||||||
|
}
|
||||||
|
ind_r_max = mxGetScalar(prhs[0]);
|
||||||
|
no_of_segments = mxGetScalar(prhs[1]);
|
||||||
|
norm_sum = mxGetPr(prhs[2]);
|
||||||
|
|
||||||
|
frame_data = mxGetPr(prhs[4]);
|
||||||
|
|
||||||
|
nDimNum = mxGetNumberOfDimensions(prhs[4]);
|
||||||
|
pDims = mxGetDimensions(prhs[4]);
|
||||||
|
|
||||||
|
if (nDimNum==2){
|
||||||
|
plhs[0] = mxCreateNumericMatrix((mwSize)ind_r_max, (mwSize)no_of_segments, mxDOUBLE_CLASS, mxREAL);
|
||||||
|
plhs[1] = mxCreateNumericMatrix((mwSize)ind_r_max, (mwSize)no_of_segments, mxDOUBLE_CLASS, mxREAL);
|
||||||
|
maxSlice = 1;
|
||||||
|
} else if (nDimNum==3) {
|
||||||
|
maxSlice = pDims[2];
|
||||||
|
mwSize dims[3] = {(mwSize)ind_r_max,(mwSize)no_of_segments,(mwSize)maxSlice};
|
||||||
|
plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
|
||||||
|
plhs[1] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
|
||||||
|
} else {
|
||||||
|
mexErrMsgIdAndTxt("cxsSoftware:radialIntegMex:dimsError","frame_data must be 2D or 3D.");
|
||||||
|
}
|
||||||
|
|
||||||
|
double* outputMatrixMean = (double *)mxGetData(plhs[0]);
|
||||||
|
double* outputMatrixStdDev = (double *)mxGetData(plhs[1]);
|
||||||
|
|
||||||
|
#pragma omp parallel for collapse(2)
|
||||||
|
for (uint slID=0; slID < maxSlice; slID++){
|
||||||
|
for (uint ind_r=0; ind_r<ind_r_max; ind_r++){
|
||||||
|
for (uint ind_seg=0; ind_seg<no_of_segments; ind_seg++){
|
||||||
|
double tmpMean = 0;
|
||||||
|
double tmpStdDev = 0;
|
||||||
|
|
||||||
|
if (norm_sum[ind_r+ind_seg*ind_r_max] > 0){
|
||||||
|
mxArray *subarray = mxGetCell(prhs[3], ind_r+ind_seg*ind_r_max);
|
||||||
|
double *indicesSub = mxGetPr(subarray);
|
||||||
|
uint dim = mxGetNumberOfElements(subarray);
|
||||||
|
|
||||||
|
|
||||||
|
for (uint ii=0; ii<dim; ii++){
|
||||||
|
tmpMean += frame_data[(int)indicesSub[ii]-1 + slID*pDims[0]*pDims[1]];
|
||||||
|
}
|
||||||
|
if (tmpMean>0){
|
||||||
|
tmpMean /= dim;
|
||||||
|
}
|
||||||
|
for (uint ii=0; ii<dim; ii++){
|
||||||
|
tmpStdDev += std::pow(std::abs(frame_data[(int)indicesSub[ii]-1 + slID*pDims[0]*pDims[1]]-tmpMean),2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmpMean>0 && dim>1){
|
||||||
|
tmpStdDev = sqrt(tmpStdDev/(dim-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
tmpMean = -1;
|
||||||
|
tmpStdDev = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputMatrixMean[ind_r+ind_seg*ind_r_max+slID*(ind_r_max)*(no_of_segments)] = tmpMean;
|
||||||
|
outputMatrixStdDev[ind_r+ind_seg*ind_r_max+slID*(ind_r_max)*(no_of_segments)] = tmpStdDev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,710 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: radial_integ.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.12 $ $Date: 2016/01/21 15:11:50 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% radial integration of 2D data read from file(s)
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
% The integration masks need to be prepared first using prep_integ_masks.m
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% February 18 2015:
|
||||||
|
% updated to use new function names of parallel toolbox in Matlab 2014b
|
||||||
|
%
|
||||||
|
% July 22nd 2010:
|
||||||
|
% add simple parallel processing using parfor
|
||||||
|
%
|
||||||
|
% April 28th 2010:
|
||||||
|
% use default_parameter_value
|
||||||
|
%
|
||||||
|
% June 5th 2008: 1st documented version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ I,vararg_remain ] = radial_integ(filename_masks,varargin)
|
||||||
|
import beamline.prep_integ_masks
|
||||||
|
import io.image_read
|
||||||
|
import plotting.plot_radial_integ
|
||||||
|
import utils.default_parameter_value
|
||||||
|
import utils.find_files
|
||||||
|
import utils.abspath
|
||||||
|
|
||||||
|
% initialize return arguments
|
||||||
|
I = struct('I_all',[], 'I_std',[],'filenames_all',[],'q',[],'radius',[]);
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
outdir_data = default_parameter_value(mfilename,'OutdirData');
|
||||||
|
filename_integ_masks = default_parameter_value(mfilename,'FilenameIntegMasks');
|
||||||
|
r_max_forced = default_parameter_value(mfilename,'rMaxForced');
|
||||||
|
fig_no = default_parameter_value(mfilename,'FigNo');
|
||||||
|
save_combined_I = default_parameter_value(mfilename,'SaveCombinedI');
|
||||||
|
recursive = default_parameter_value(mfilename,'Recursive');
|
||||||
|
use_find = default_parameter_value(mfilename,'UseFind');
|
||||||
|
unhandled_par_error = default_parameter_value(mfilename,'UnhandledParError');
|
||||||
|
parallel_tasks_max = 1; %default_parameter_value(mfilename,'ParTasksMax');
|
||||||
|
save_format = '-v6';
|
||||||
|
use_mex = true;
|
||||||
|
c_reader = true;
|
||||||
|
useStack = true;
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
fprintf('\nUsage:\n');
|
||||||
|
fprintf('%s(filename_mask, [[,<name>,<value>] ...]);\n',mfilename);
|
||||||
|
fprintf('filename_mask can be something like ''*.cbf'' or ''image.cbf'' or\n');
|
||||||
|
fprintf('a cell array of filenames or filename masks like {''dir1/*.cbf'',''dir2/*.cbf''}.\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''OutdirData'',<directory> save the integrated intensities to files in this directory, '''' for no saving, default is %s\n',outdir_data);
|
||||||
|
fprintf('''FilenameIntegMasks'',<filename> Matlab file containing the integration masks, default is ''%s''\n',filename_integ_masks);
|
||||||
|
fprintf('''rMaxForced'',<radius in pixel> stop integration at this maximum r even if the integration masks reach further, default is 0 - do not stop\n');
|
||||||
|
fprintf('''FigNo'',<figure number> number of the figure for an online plot of the intensities in case parallel processing is not used, 0 for no plot, default is %d\n',fig_no);
|
||||||
|
fprintf('''SaveFormat'',<format string> default is %s\n',save_format);
|
||||||
|
fprintf('''SaveCombinedI'',<0-no, 1-yes> save intensities from all specified files found in one directory in a single file, default is yes\n');
|
||||||
|
fprintf('''Recursive'',<0-no, 1-yes> recursively integrate files in all matching sub-directories, default is yes\n');
|
||||||
|
fprintf('''ParTasksMax'',<integer> specify the maximum number of CPU cores to use, 1 to deactivate the use of parallel computing, default is %d\n',parallel_tasks_max);
|
||||||
|
fprintf('''UseFind'',<0-no, 1-yes> use Linux/Unix command find to interprete the filename mask, default is yes\n');
|
||||||
|
fprintf('''UseMex'', <0-no, 1-yes> use radial_integ_mex; usually faster than MATLAB, default is yes\n');
|
||||||
|
fprintf('''CReader'', <0-no, 1-yes> use the fast measurement reader; usually faster than image_read, default is yes\n');
|
||||||
|
fprintf('''UseStack'', <0-no, 1-yes> load all detector frames into memory before calling the radial_integ functions; default is yes\n');
|
||||||
|
fprintf('''UnhandledParError'',<0-no,1-yes> exit in case not all named parameters are used/known, default is %d\n',unhandled_par_error);
|
||||||
|
fprintf('Examples:\n');
|
||||||
|
fprintf('%s(''~/Data10/pilatus/mydatadir/*.cbf'',''OutdirData'',''~/Data10/analysis/radial_integ/'');\n',mfilename);
|
||||||
|
fprintf('Additional <name>,<value> pairs recognized by image_read can be specified.\n');
|
||||||
|
error('At least the filename mask has to be specified as input argument.');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'OutdirData'
|
||||||
|
outdir_data = value;
|
||||||
|
case 'SaveFormat'
|
||||||
|
save_format = value;
|
||||||
|
case 'FilenameIntegMasks'
|
||||||
|
filename_integ_masks = value;
|
||||||
|
case 'rMaxForced'
|
||||||
|
r_max_forced = value;
|
||||||
|
case 'FigNo'
|
||||||
|
fig_no = value;
|
||||||
|
case 'SaveCombinedI'
|
||||||
|
save_combined_I = value;
|
||||||
|
case 'Recursive'
|
||||||
|
recursive = value;
|
||||||
|
case 'UseFind'
|
||||||
|
use_find = value;
|
||||||
|
case 'UnhandledParError'
|
||||||
|
unhandled_par_error = value;
|
||||||
|
case 'ParTasksMax'
|
||||||
|
parallel_tasks_max = value;
|
||||||
|
case 'UseMex'
|
||||||
|
use_mex = value;
|
||||||
|
case 'CReader'
|
||||||
|
c_reader = value;
|
||||||
|
case 'UseStack'
|
||||||
|
useStack = value;
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% initialize the list of unhandled parameters
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
|
||||||
|
% do not exit in image_par in case of unhandled parameters
|
||||||
|
if (~unhandled_par_error)
|
||||||
|
vararg{end+1} = 'UnhandledParError';
|
||||||
|
vararg{end+1} = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (~isempty(outdir_data))
|
||||||
|
% add slash to output directory
|
||||||
|
if (outdir_data(end) ~= '/')
|
||||||
|
outdir_data = [ outdir_data '/' ];
|
||||||
|
end
|
||||||
|
|
||||||
|
% create output directory
|
||||||
|
[mkdir_stat,mkdir_message] = mkdir(outdir_data);
|
||||||
|
if (~mkdir_stat)
|
||||||
|
error('invalid directory %s: %s',outdir_data,mkdir_message);
|
||||||
|
end
|
||||||
|
if ((mkdir_stat) && (isempty(mkdir_message)))
|
||||||
|
fprintf('The output directory %s has been created.\n',outdir_data);
|
||||||
|
else
|
||||||
|
fprintf('The output directory is %s.\n',outdir_data);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fprintf('data are not saved\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
% load integration masks from this file
|
||||||
|
% this loads:
|
||||||
|
% center_xy, no_of_segments, integ_masks
|
||||||
|
fprintf('loading integration masks from %s\n',filename_integ_masks);
|
||||||
|
load(filename_integ_masks);
|
||||||
|
if ((~exist('center_xy','var')) && (exist('center_x','var')))
|
||||||
|
center_xy(1) = center_x;
|
||||||
|
center_xy(2) = center_y;
|
||||||
|
if (~exist('integ_masks','var'))
|
||||||
|
integ_masks.radius = r;
|
||||||
|
integ_masks.indices = masks_r;
|
||||||
|
integ_masks.norm_sum = mask_r_sum;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
fprintf('center at (x, y) = (%.1f, %.1f)\n',center_xy(1),center_xy(2));
|
||||||
|
|
||||||
|
% limit radial range
|
||||||
|
if (r_max_forced > 0)
|
||||||
|
ind = find( integ_masks.radius < r_max_forced );
|
||||||
|
if (length(ind) < 1)
|
||||||
|
fprintf('No radii below rMaxForced = %d found\n',r_max_forced);
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
integ_masks.radius = integ_masks.radius(1:ind(end));
|
||||||
|
integ_masks.norm_sum = integ_masks.norm_sum(1:ind(end), :);
|
||||||
|
end
|
||||||
|
if isfield(integ_masks,'radius')
|
||||||
|
fprintf('radii from %d to %d\n',...
|
||||||
|
integ_masks.radius(1),integ_masks.radius(end));
|
||||||
|
else
|
||||||
|
fprintf('radii from %d to %d\n',...
|
||||||
|
integ_masks.q(1),integ_masks.q(end));
|
||||||
|
end
|
||||||
|
% ease handling by ensuring that filename_masks is a cell array
|
||||||
|
if (~iscell(filename_masks))
|
||||||
|
filename_masks = { filename_masks };
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% initialize parallel processing if this is enabled and not yet done
|
||||||
|
if (parallel_tasks_max > 1)
|
||||||
|
%matlabpool_size = matlabpool('size');
|
||||||
|
%if (matlabpool_size < 1)
|
||||||
|
if isempty(gcp('nocreate')) %MGS2015 If there is no current pool
|
||||||
|
% create a scheduler object using the default configuration, which is a
|
||||||
|
% local scheduler if nothing else has been installed
|
||||||
|
% scheduler = findResource('scheduler','type', defaultParallelConfig);
|
||||||
|
scheduler = parcluster; %MGS2015
|
||||||
|
|
||||||
|
% adapt maximum number of tasks/workers, if necessary
|
||||||
|
%cluster_size = get(scheduler,'ClusterSize');
|
||||||
|
cluster_size = scheduler.NumWorkers; %MGS2015
|
||||||
|
if (parallel_tasks_max > cluster_size)
|
||||||
|
fprintf('Adapting the maximum number of tasks from %d to %d.\n',...
|
||||||
|
parallel_tasks_max, cluster_size);
|
||||||
|
parallel_tasks_max = cluster_size;
|
||||||
|
end
|
||||||
|
|
||||||
|
% open a Matlab pool for simple parallel processing
|
||||||
|
if (parallel_tasks_max > 1)
|
||||||
|
%matlabpool('open',parallel_tasks_max);%MGS2015
|
||||||
|
pool = parpool(parallel_tasks_max);
|
||||||
|
fprintf('Using parallel processing with %d tasks.\n', ...
|
||||||
|
parallel_tasks_max);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
pool = gcp;%MGS2015
|
||||||
|
if ( pool.NumWorkers < parallel_tasks_max )
|
||||||
|
fprintf('%s: usage of up to %d CPUs in parallel has been specified but an already open matlabpool with %d workers has been found and will be used instead\n', ...
|
||||||
|
mfilename, parallel_tasks_max, pool.NumWorkers);
|
||||||
|
parallel_tasks_max = pool.NumWorkers;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pool.IdleTimeout = Inf;
|
||||||
|
|
||||||
|
if ((parallel_tasks_max > 1) && (fig_no > 0))
|
||||||
|
fprintf('%s: Online plotting is disabled since parallel processing is enabled.\n', ...
|
||||||
|
mfilename);
|
||||||
|
end
|
||||||
|
|
||||||
|
% loop over all filename masks
|
||||||
|
ind_mask_max = length(filename_masks);
|
||||||
|
|
||||||
|
% Initialize variables for saving
|
||||||
|
no_of_segments = size(integ_masks.indices,2);
|
||||||
|
if isfield(integ_masks,'radius')
|
||||||
|
radius = integ_masks.radius;
|
||||||
|
ind_r_max = length(radius);
|
||||||
|
else
|
||||||
|
radius = [];
|
||||||
|
q = integ_masks.q;
|
||||||
|
ind_r_max = length(q);
|
||||||
|
end
|
||||||
|
if isfield(integ_masks,'q')
|
||||||
|
q = integ_masks.q;
|
||||||
|
else
|
||||||
|
q = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
for (ind_mask = 1:ind_mask_max) %#ok<*NO4LP>
|
||||||
|
filename_mask = filename_masks{ind_mask};
|
||||||
|
fprintf('%s:\n',filename_mask);
|
||||||
|
[data_dir,fnames] = find_files( filename_mask, 'UseFind',use_find );
|
||||||
|
|
||||||
|
if (length(fnames) < 1)
|
||||||
|
fprintf('No matching files found for %s.\n',filename_mask);
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
% collect recursively all matching file names
|
||||||
|
[ filenames_all ] = ...
|
||||||
|
collect_radial_integ_filenames(data_dir, fnames, ...
|
||||||
|
recursive, ...
|
||||||
|
vararg);
|
||||||
|
|
||||||
|
% prepare for integration of the so far identified files
|
||||||
|
file_ind_max = length(filenames_all);
|
||||||
|
for file_ind=1:file_ind_max
|
||||||
|
filenames_all{file_ind}=abspath(filenames_all{file_ind});
|
||||||
|
end
|
||||||
|
|
||||||
|
% get the number of frames per file by loading the first file (not very
|
||||||
|
% elegant)
|
||||||
|
[frame] = image_read(filenames_all{1}, vararg);
|
||||||
|
no_of_frames = size(frame.data,3);
|
||||||
|
I_all = zeros(ind_r_max, no_of_segments, no_of_frames, file_ind_max);
|
||||||
|
I_std = zeros(ind_r_max, no_of_segments, no_of_frames, file_ind_max);
|
||||||
|
|
||||||
|
if (parallel_tasks_max > 1)
|
||||||
|
% integration using parallel processing
|
||||||
|
parfor (file_ind = 1:file_ind_max)
|
||||||
|
|
||||||
|
% read the raw data frame and integrate it
|
||||||
|
[frame_I, frame_std] = ...
|
||||||
|
perform_radial_integ_parallel(file_ind, file_ind_max, ...
|
||||||
|
filenames_all{file_ind}, ...
|
||||||
|
integ_masks, ind_r_max, no_of_segments, ...
|
||||||
|
vararg);
|
||||||
|
|
||||||
|
% no_of_frames = size(frame_I,3);
|
||||||
|
% if (no_of_frames ~= size(I_all,3))
|
||||||
|
% error('number of frames per file changes from %d to %d',size(I_all,3),no_of_frames);
|
||||||
|
% end
|
||||||
|
|
||||||
|
I_all(:,:,:,file_ind) = frame_I;
|
||||||
|
I_std(:,:,:,file_ind) = frame_std;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% read the raw data
|
||||||
|
if c_reader
|
||||||
|
try
|
||||||
|
[~, ~, ext] = fileparts(filenames_all{1});
|
||||||
|
arg.data_path = filenames_all';
|
||||||
|
arg.nthreads = min(round(feature('numcores')*0.8),14);
|
||||||
|
arg.precision = 'single';
|
||||||
|
arg.extension = ext(2:end);
|
||||||
|
if strcmpi(ext(1:end), 'h5') && ~isempty(find(strcmp(varargin, 'H5Location')))
|
||||||
|
arg.data_location = varargin{find(strcmp(varargin, 'H5Location'))+1};
|
||||||
|
end
|
||||||
|
frameStorage.data = io.read_measurement(arg);
|
||||||
|
frameStorage.data = permute(frameStorage.data,[2 1 3]);
|
||||||
|
frameStorage.data = flip(flip(frameStorage.data,1),2);
|
||||||
|
catch ME
|
||||||
|
fprintf('Failed to load data. If the problem persists, set c_reader=false.\n');
|
||||||
|
rethrow(ME);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
[frameStorage] = image_read(filename_masks, vararg);
|
||||||
|
end
|
||||||
|
if ~useStack
|
||||||
|
for (file_ind = 1:file_ind_max)
|
||||||
|
|
||||||
|
% read the raw data frame and integrate it
|
||||||
|
[frame_I, frame_std] = ...
|
||||||
|
perform_radial_integ(file_ind, file_ind_max, ...
|
||||||
|
frameStorage.data(:,:,file_ind), ...
|
||||||
|
integ_masks, ind_r_max, no_of_segments, use_mex, ...
|
||||||
|
vararg);
|
||||||
|
|
||||||
|
I_all(:,:,:,file_ind) = frame_I;
|
||||||
|
I_std(:,:,:,file_ind) = frame_std;
|
||||||
|
|
||||||
|
% plot integrated intensities as feedback
|
||||||
|
if (fig_no > 0)
|
||||||
|
if isfield(integ_masks,'radius')
|
||||||
|
d.radius = radius;
|
||||||
|
else
|
||||||
|
d.radius= q;
|
||||||
|
end
|
||||||
|
d.I_all = frame_I;
|
||||||
|
d.I_std = frame_std;
|
||||||
|
plot_radial_integ(d,'FigNo',fig_no);
|
||||||
|
drawnow;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% integrate it
|
||||||
|
try
|
||||||
|
[frame_I, frame_std] = radial_integ_mex(int32(ind_r_max),int32(no_of_segments), integ_masks.norm_sum, integ_masks.indices, double(frameStorage.data));
|
||||||
|
catch
|
||||||
|
tmpPath = fileparts(mfilename('fullpath'));
|
||||||
|
fprintf('Recompiling mex function...\n');
|
||||||
|
|
||||||
|
% Fall back to single thread if the OpenMP fail.
|
||||||
|
|
||||||
|
eval(['mex ' fullfile(tmpPath, 'private', 'radial_integ_mex.cpp') ' -outdir ' fullfile(tmpPath, 'private')]);
|
||||||
|
try
|
||||||
|
[frame_I, frame_std] = radial_integ_mex(int32(ind_r_max),int32(no_of_segments), integ_masks.norm_sum, integ_masks.indices, double(frameStorage.data));
|
||||||
|
catch ME
|
||||||
|
fprintf('radial_integ_mex failed. If the problem persists, consider setting use_mex=false.\n');
|
||||||
|
rethrow(ME);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
I_all(:,:,1,:) = frame_I;
|
||||||
|
I_std(:,:,1,:) = frame_std;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% reshuffle the data to get rid off the frame-within-file dimension,
|
||||||
|
% dimension 3.
|
||||||
|
% This would be easier with linear indexing in case the frame and file
|
||||||
|
% dimensions would be 1 and 2.
|
||||||
|
I_all_org = I_all;
|
||||||
|
I_std_org = I_std;
|
||||||
|
I_all = zeros(size(I_all_org,1), size(I_all_org,2), size(I_all_org,3) * size(I_all_org,4));
|
||||||
|
I_std = zeros(size(I_all));
|
||||||
|
for (ind_frame = 1:size(I_all_org,3))
|
||||||
|
for (ind_file = 1:size(I_all_org,4))
|
||||||
|
I_all(:,:,(ind_file-1)*size(I_all_org,3)+ind_frame) = I_all_org(:,:,ind_frame,ind_file);
|
||||||
|
I_std(:,:,(ind_file-1)*size(I_std_org,3)+ind_frame) = I_std_org(:,:,ind_frame,ind_file);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% save data, if this option is enabled
|
||||||
|
if (~isempty(outdir_data))
|
||||||
|
if (save_combined_I)
|
||||||
|
% save all integrated frames as single Matlab file
|
||||||
|
|
||||||
|
if (exist('I_all','var'))
|
||||||
|
% use first file as file-name base
|
||||||
|
[~, name] = fileparts(filenames_all{1});
|
||||||
|
% name = name(1:end-12);
|
||||||
|
fname_out = fullfile(outdir_data, [ name '_integ.mat' ]);
|
||||||
|
fprintf('saving %s\n',fname_out);
|
||||||
|
% remove directory information before storing the filenames
|
||||||
|
for (file_ind = 1:file_ind_max)
|
||||||
|
[~, name, extension] = fileparts(filenames_all{file_ind});
|
||||||
|
filenames_all{file_ind} = [ name extension ];
|
||||||
|
end
|
||||||
|
norm_sum = integ_masks.norm_sum;
|
||||||
|
save(fname_out,'I_all','I_std', 'norm_sum', 'filenames_all','radius','q','angular_segments','phi_det', save_format);
|
||||||
|
else
|
||||||
|
fprintf('No data to save for directory %s\n',data_dir);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
|
||||||
|
% save the integrated data for each frame as separate ASCII
|
||||||
|
% file
|
||||||
|
savedat = zeros(ind_r_max, no_of_segments +1);
|
||||||
|
if isfield(integ_masks,'radius')
|
||||||
|
savedat(:,1) = radius;
|
||||||
|
else
|
||||||
|
savedat(:,1)= q;
|
||||||
|
end
|
||||||
|
for (file_ind = 1:file_ind_max)
|
||||||
|
% save integrated data for this image in the output arrays
|
||||||
|
savedat(:,2:end) = I_all(:,:,file_ind);
|
||||||
|
|
||||||
|
[pathstr, name] = fileparts(filenames_all{file_ind});
|
||||||
|
fname_out = fullfile(pathstr, [ name '_integ.txt' ]);
|
||||||
|
fprintf('saving %s\n',fname_out);
|
||||||
|
save([outdir_data fname_out],'savedat','-ascii');
|
||||||
|
end
|
||||||
|
|
||||||
|
fprintf('\nOutput data format:\n');
|
||||||
|
fprintf('- first column with radius of circle in pixel\n');
|
||||||
|
fprintf('- further columns with average intensity in circle segment\n');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% compile return value
|
||||||
|
I(ind_mask).I_all = I_all;
|
||||||
|
I(ind_mask).I_std = I_std;
|
||||||
|
if isfield(integ_masks,'radius')
|
||||||
|
I(ind_mask).radius = integ_masks.radius;
|
||||||
|
end
|
||||||
|
I(ind_mask).norm_sum = integ_masks.norm_sum;
|
||||||
|
I(ind_mask).filenames_all = filenames_all;
|
||||||
|
if isfield(integ_masks,'q')
|
||||||
|
I(ind_mask).q = integ_masks.q;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [ filenames_all ] = ...
|
||||||
|
collect_radial_integ_filenames(data_dir, fnames, ...
|
||||||
|
recursive, ...
|
||||||
|
vararg)
|
||||||
|
import beamline.prep_integ_masks
|
||||||
|
import io.image_read
|
||||||
|
import plotting.plot_radial_integ
|
||||||
|
import utils.default_parameter_value
|
||||||
|
import utils.find_files
|
||||||
|
% add slashes to directories
|
||||||
|
if ((~isempty(data_dir)) && (data_dir(end) ~= '/'))
|
||||||
|
data_dir = [ data_dir '/' ];
|
||||||
|
end
|
||||||
|
|
||||||
|
% define some variables which depend on the input arguments
|
||||||
|
file_ind_max = length(fnames);
|
||||||
|
|
||||||
|
% initialize variables used in the loop
|
||||||
|
filenames_all_max = 0;
|
||||||
|
filenames_all = cell(file_ind_max,1);
|
||||||
|
|
||||||
|
% loop over all matching files
|
||||||
|
for (file_ind=1:file_ind_max)
|
||||||
|
% % skip single frames created using the spec macro ct
|
||||||
|
% if (length(fnames(file_ind).name) > 7)
|
||||||
|
% fprintf('');
|
||||||
|
% if (strcmp(fnames(file_ind).name((end-6):(end-3)),'_ct.'))
|
||||||
|
% fprintf('skipping %s\n',fnames(file_ind).name);
|
||||||
|
% continue
|
||||||
|
% end
|
||||||
|
% end
|
||||||
|
% directory: recursion
|
||||||
|
if ((fnames(file_ind).isdir) && (recursive))
|
||||||
|
% ignore . and .. directories
|
||||||
|
if ((strcmp(fnames(file_ind).name,'.')) || ...
|
||||||
|
(strcmp(fnames(file_ind).name,'..')))
|
||||||
|
fprintf('skipping %s\n',fnames(file_ind).name);
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
data_dir_sub = [ data_dir fnames(file_ind).name '/' ];
|
||||||
|
fnames_sub = dir( data_dir_sub );
|
||||||
|
fprintf('recursion for %s\n',fnames(file_ind).name);
|
||||||
|
[ filenames_all_rec,vararg_remain ] = ...
|
||||||
|
collect_radial_integ_filenames(data_dir_sub, ...
|
||||||
|
fnames_sub, ...
|
||||||
|
integ_masks, ...
|
||||||
|
fig_no, save_combined_I, recursive, ...
|
||||||
|
vararg);
|
||||||
|
% store result of this recursion
|
||||||
|
if (~isempty(filenames_all_rec))
|
||||||
|
filenames_all_ind = (filenames_all_max+1):(filenames_all_max+length(filenames_all_rec));
|
||||||
|
filenames_all(filenames_all_ind) = filenames_all_rec;
|
||||||
|
filenames_all_max = filenames_all_ind(end);
|
||||||
|
end
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
if ((length(fnames(file_ind).name) <= 4) || ...
|
||||||
|
(strcmp(fnames(file_ind).name(end-3:end),'.tmp')) || ...
|
||||||
|
(strcmp(fnames(file_ind).name(end-3:end),'.log')))
|
||||||
|
fprintf('skipping %s\n',fnames(file_ind).name);
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% store matching filenames in one array
|
||||||
|
filenames_all_max = filenames_all_max +1;
|
||||||
|
filenames_all{filenames_all_max} = [ data_dir fnames(file_ind).name ];
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (~exist('filenames_all','var'))
|
||||||
|
filenames_all = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (length(filenames_all) > filenames_all_max)
|
||||||
|
filenames_all = filenames_all{1:filenames_all_max};
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [frame_I,frame_std] = ...
|
||||||
|
perform_radial_integ(file_ind, file_ind_max, ...
|
||||||
|
frame, ...
|
||||||
|
integ_masks, ind_r_max, no_of_segments, use_mex, ...
|
||||||
|
vararg)
|
||||||
|
import beamline.prep_integ_masks
|
||||||
|
import io.image_read
|
||||||
|
import plotting.plot_radial_integ
|
||||||
|
import utils.default_parameter_value
|
||||||
|
import utils.find_files
|
||||||
|
% read the raw data frame
|
||||||
|
% fprintf('%6d /%6d: ',file_ind,file_ind_max);
|
||||||
|
% [frame] = image_read(filename, vararg);
|
||||||
|
if (isempty(frame))
|
||||||
|
error('could not load frame %u',file_ind);
|
||||||
|
end
|
||||||
|
|
||||||
|
% get the number of frames in case of multi-frame data files like HDF5
|
||||||
|
no_of_frames = size(frame,3);
|
||||||
|
|
||||||
|
% initialize result variables
|
||||||
|
frame_I = zeros(ind_r_max,no_of_segments,no_of_frames);
|
||||||
|
frame_std = zeros(ind_r_max,no_of_segments,no_of_frames);
|
||||||
|
|
||||||
|
if use_mex
|
||||||
|
for (ind_frame = 1:no_of_frames)
|
||||||
|
% get the current frame
|
||||||
|
frame_data = double(frame(:,:,ind_frame));
|
||||||
|
try
|
||||||
|
[frame_I(:,:,ind_frame), frame_std(:,:,ind_frame)] = radial_integ_mex(int32(ind_r_max),int32(no_of_segments), integ_masks.norm_sum, integ_masks.indices, frame_data);
|
||||||
|
catch
|
||||||
|
tmpPath = fileparts(mfilename('fullpath'));
|
||||||
|
fprintf('Recompiling mex function...\n');
|
||||||
|
|
||||||
|
% Fall back to single thread if the OpenMP fail.
|
||||||
|
|
||||||
|
eval(['mex ' fullfile(tmpPath, 'private', 'radial_integ_mex.cpp') ' -outdir ' fullfile(tmpPath, 'private')]);
|
||||||
|
try
|
||||||
|
[frame_I(:,:,ind_frame), frame_std(:,:,ind_frame)] = radial_integ_mex(int32(ind_r_max),int32(no_of_segments), integ_masks.norm_sum, integ_masks.indices, frame_data);
|
||||||
|
catch ME
|
||||||
|
fprintf('radial_integ_mex failed. If the problem persists, consider setting use_mex=false.\n');
|
||||||
|
rethrow(ME);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for (ind_frame = 1:no_of_frames)
|
||||||
|
|
||||||
|
% get the current frame
|
||||||
|
frame_data = double(frame(:,:,ind_frame));
|
||||||
|
% initialize output variables for current data
|
||||||
|
frame_I_one_frame = zeros(ind_r_max,no_of_segments);
|
||||||
|
frame_std_one_frame = zeros(ind_r_max,no_of_segments);
|
||||||
|
for (ind_r = 1:ind_r_max)
|
||||||
|
for (ind_seg = 1:no_of_segments)
|
||||||
|
if (integ_masks.norm_sum(ind_r,ind_seg) > 0)
|
||||||
|
frame_I_one_frame(ind_r,ind_seg) = ...
|
||||||
|
mean(frame_data(integ_masks.indices{ind_r,ind_seg}));
|
||||||
|
frame_std_one_frame(ind_r,ind_seg) = ...
|
||||||
|
std(frame_data(integ_masks.indices{ind_r,ind_seg}));
|
||||||
|
else
|
||||||
|
% mark unknown intensities
|
||||||
|
frame_I_one_frame(ind_r,ind_seg) = -1;
|
||||||
|
frame_std_one_frame(ind_r,ind_seg) = -1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
frame_I(:,:,ind_frame) = frame_I_one_frame;
|
||||||
|
frame_std(:,:,ind_frame) = frame_std_one_frame;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%
|
||||||
|
function [frame_I,frame_std] = ...
|
||||||
|
perform_radial_integ_parallel(file_ind, file_ind_max, ...
|
||||||
|
filename, ...
|
||||||
|
integ_masks, ind_r_max, no_of_segments, ...
|
||||||
|
vararg)
|
||||||
|
import beamline.prep_integ_masks
|
||||||
|
import io.image_read
|
||||||
|
import plotting.plot_radial_integ
|
||||||
|
import utils.default_parameter_value
|
||||||
|
import utils.find_files
|
||||||
|
% read the raw data frame
|
||||||
|
fprintf('%6d /%6d: ',file_ind,file_ind_max);
|
||||||
|
[frame] = image_read(filename, vararg);
|
||||||
|
if (isempty(frame.data))
|
||||||
|
error('could not load %s',filename);
|
||||||
|
end
|
||||||
|
|
||||||
|
% get the number of frames in case of multi-frame data files like HDF5
|
||||||
|
no_of_frames = size(frame.data,3);
|
||||||
|
|
||||||
|
% initialize result variables
|
||||||
|
frame_I = zeros(ind_r_max,no_of_segments,no_of_frames);
|
||||||
|
frame_std = zeros(ind_r_max,no_of_segments,no_of_frames);
|
||||||
|
|
||||||
|
|
||||||
|
parfor (ind_frame = 1:no_of_frames)
|
||||||
|
% get the current frame
|
||||||
|
frame_data = double(frame.data(:,:,ind_frame));
|
||||||
|
% initialize output variables for current data
|
||||||
|
frame_I_one_frame = zeros(ind_r_max,no_of_segments);
|
||||||
|
frame_std_one_frame = zeros(ind_r_max,no_of_segments);
|
||||||
|
|
||||||
|
for (ind_r = 1:ind_r_max)
|
||||||
|
for (ind_seg = 1:no_of_segments)
|
||||||
|
if (integ_masks.norm_sum(ind_r,ind_seg) > 0)
|
||||||
|
frame_I_one_frame(ind_r,ind_seg) = ...
|
||||||
|
mean(frame_data(integ_masks.indices{ind_r,ind_seg}));
|
||||||
|
frame_std_one_frame(ind_r,ind_seg) = ...
|
||||||
|
std(frame_data(integ_masks.indices{ind_r,ind_seg}));
|
||||||
|
else
|
||||||
|
% mark unknown intensities
|
||||||
|
frame_I_one_frame(ind_r,ind_seg) = -1;
|
||||||
|
frame_std_one_frame(ind_r,ind_seg) = -1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
frame_I(:,:,ind_frame) = frame_I_one_frame;
|
||||||
|
frame_std(:,:,ind_frame) = frame_std_one_frame;
|
||||||
|
end
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
% (beamline.)radial_integ_wrapper()
|
||||||
|
% Reads the radial integration filequeue when the filequeue is enabled
|
||||||
|
% by _filequeue_on in SPEC, and calls the radial integration script with
|
||||||
|
% parameters generated by radial_integration_SAXS_and_WAXS from scan of
|
||||||
|
% standards.
|
||||||
|
% This function is called without arguments to run on multiple nodes in
|
||||||
|
% parallel.
|
||||||
|
% Make sure your current matlab directory is Data10/matlab/.
|
||||||
|
% To change default settings modify the starting lines in function body.
|
||||||
|
%
|
||||||
|
% see also: beamline.radial_integ
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function radial_integ_wrapper()
|
||||||
|
|
||||||
|
import utils.verbose
|
||||||
|
|
||||||
|
p=struct();
|
||||||
|
p.queue_path = utils.abspath('../specES1/radial_integ_queue');
|
||||||
|
p.det_todo = [1 2];
|
||||||
|
p.recon_latest_first = 0; % =0 from first; =1 from last; =2 random.
|
||||||
|
|
||||||
|
|
||||||
|
% ----- Modify until here -----
|
||||||
|
|
||||||
|
finishup = utils.onCleanup(@(x) radial_integ_exit(x), p);
|
||||||
|
for i=1:numel(p.det_todo)
|
||||||
|
mat_todo=[utils.abspath('../analysis/radial_integration_todo') sprintf('/vargin_det%d.mat',p.det_todo(i))];
|
||||||
|
try
|
||||||
|
m=load(mat_todo);
|
||||||
|
catch err
|
||||||
|
error(sprintf('Did not find vargin file for detector %d, check current folder is in matlab/, and the radial integration standards are finished.\n',p.det_todo(i)));
|
||||||
|
end
|
||||||
|
args_todo{i}=m.args;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
while 1==1
|
||||||
|
|
||||||
|
finishup.update(p);
|
||||||
|
|
||||||
|
if ~exist(fullfile(p.queue_path,'in_progress'),'dir')
|
||||||
|
mkdir(fullfile(p.queue_path,'in_progress'));
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~exist(fullfile(p.queue_path,'failed'),'dir')
|
||||||
|
mkdir(fullfile(p.queue_path,'failed'));
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~exist(fullfile(p.queue_path,'done'),'dir')
|
||||||
|
mkdir(fullfile(p.queue_path,'done'));
|
||||||
|
end
|
||||||
|
|
||||||
|
fext = 'dat';
|
||||||
|
|
||||||
|
status_ok = true;
|
||||||
|
verbose(1,['Touching folder and looking for files in the queue in ' p.queue_path]);
|
||||||
|
system(sprintf('touch %s',p.queue_path));
|
||||||
|
files_recons = dir(fullfile(p.queue_path,'scan*.dat'));
|
||||||
|
|
||||||
|
% Found one file to reconstruct
|
||||||
|
if ~isempty(files_recons)
|
||||||
|
if p.recon_latest_first==0
|
||||||
|
p.file_this_recons = files_recons(1).name;
|
||||||
|
elseif p.recon_latest_first==1
|
||||||
|
p.file_this_recons = files_recons(end).name;
|
||||||
|
else
|
||||||
|
p.file_this_recons = files_recons(randi([1 numel(files_recons)])).name;
|
||||||
|
end
|
||||||
|
finishup.update(p);
|
||||||
|
verbose(1,['Found file in queue ' fullfile(p.queue_path,p.file_this_recons)]);
|
||||||
|
% now move it quickly before someone else will take it
|
||||||
|
try
|
||||||
|
io.movefile_fast(fullfile(p.queue_path,p.file_this_recons),fullfile(p.queue_path,'in_progress'))
|
||||||
|
verbose(1,['Moving file to ' fullfile(p.queue_path,'in_progress')]);
|
||||||
|
catch
|
||||||
|
verbose(1,['Failed moving file to ' fullfile(p.queue_path,'in_progress')]);
|
||||||
|
pause(1);
|
||||||
|
status_ok = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
if status_ok
|
||||||
|
% parse the file
|
||||||
|
|
||||||
|
fid = fopen(fullfile(p.queue_path,'in_progress',p.file_this_recons),'r');
|
||||||
|
|
||||||
|
tline = fgetl(fid);
|
||||||
|
while ischar(tline)
|
||||||
|
str_parts = strsplit(tline, ' ');
|
||||||
|
if numel(str_parts)>1
|
||||||
|
fname = strtrim(str_parts{1});
|
||||||
|
if strcmpi(fname(1:2), 'p.')
|
||||||
|
% found p entry
|
||||||
|
val = [];
|
||||||
|
for ii=2:numel(str_parts)
|
||||||
|
if ~isempty(strtrim(str_parts{ii}))
|
||||||
|
if ~isnan(str2double(str_parts{ii}))
|
||||||
|
% found number
|
||||||
|
val = [val, str2double(str_parts{ii})];
|
||||||
|
else
|
||||||
|
% found char
|
||||||
|
val = [val, strtrim(str_parts{ii})];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
p.(fname(3:end)) = val;
|
||||||
|
|
||||||
|
|
||||||
|
elseif strcmpi(str_parts{1}, 'samplename')
|
||||||
|
p.samplename = strjoin(strtrim(str_parts(2:end)), '_');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
tline = fgetl(fid);
|
||||||
|
end
|
||||||
|
|
||||||
|
fclose(fid);
|
||||||
|
finishup.update(p);
|
||||||
|
try
|
||||||
|
for i=1:numel(p.det_todo)
|
||||||
|
beamline.integrate_range(p.scan_number,p.scan_number,1,args_todo{i});
|
||||||
|
end
|
||||||
|
verbose(1,['Radial integration of scan ' num2str(p.scan_number) ' finished, moving queue file to ' fullfile(p.queue_path,'done')]);
|
||||||
|
file_move_from = fullfile(p.queue_path,'in_progress',p.file_this_recons);
|
||||||
|
file_move_to = fullfile(p.queue_path,'done',p.file_this_recons);
|
||||||
|
io.movefile_fast(file_move_from,file_move_to);
|
||||||
|
catch err
|
||||||
|
try
|
||||||
|
verbose(1,['Error encountered at scan ' num2str(p.scan_number) ', moving queue file to ' fullfile(p.queue_path,'failed')]);
|
||||||
|
file_move_from = fullfile(p.queue_path,'in_progress',p.file_this_recons);
|
||||||
|
file_move_to = fullfile(p.queue_path,'failed',p.file_this_recons);
|
||||||
|
io.movefile_fast(file_move_from,file_move_to);
|
||||||
|
disp(err);
|
||||||
|
catch err
|
||||||
|
verbose(1,['Error with file system delays, skipping.']);
|
||||||
|
disp(err);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
verbose(1,'Did not find enough files in queue, pausing 10 seconds.');
|
||||||
|
pause(10);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function radial_integ_exit(p)
|
||||||
|
import utils.verbose;
|
||||||
|
verbose(1,'Radial integration interrupted');
|
||||||
|
if isfile(fullfile(p.queue_path,'in_progress',p.file_this_recons))
|
||||||
|
try
|
||||||
|
verbose(1,['Moving current queue file back to ' p.queue_path]);
|
||||||
|
file_move_from = fullfile(p.queue_path,'in_progress',p.file_this_recons);
|
||||||
|
file_move_to = fullfile(p.queue_path,p.file_this_recons);
|
||||||
|
io.movefile_fast(file_move_from,file_move_to);
|
||||||
|
catch
|
||||||
|
disp(err);
|
||||||
|
verbose(1,'File system error, aborting.');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,548 @@
|
|||||||
|
% radial_integration_SAXS_and_WAXS.m
|
||||||
|
% Template for radial integration made around 2015
|
||||||
|
% Changes:
|
||||||
|
% 2016-08-22: define mask files at the beginning, allowing for a flag in case it needs to be repeated
|
||||||
|
% add the save fast and v6
|
||||||
|
|
||||||
|
% License at the end of script
|
||||||
|
|
||||||
|
clear all
|
||||||
|
close all
|
||||||
|
|
||||||
|
%% step 0: add the path for the matlab-scripts (fill in userID,detno and specdatfile)
|
||||||
|
addpath ..
|
||||||
|
%e-account followed by underline
|
||||||
|
userID = [beamline.identify_eaccount '_'];
|
||||||
|
% detector number: 1 for SAXS Pilatus 2M, 2 for WAXS Pilatus 300k, 3 for
|
||||||
|
% SAXS Eiger 500 k
|
||||||
|
detno = 1;
|
||||||
|
% which data format to save? '-v6' is the standard.
|
||||||
|
save_format = '-v6';
|
||||||
|
% flag for filenames for valid pixel mask, beamstop mask coordinates and integration mask.
|
||||||
|
% Example: '_2M_at_two_meters'
|
||||||
|
% Leave empty '' for default folder and filenames.
|
||||||
|
file_flag='';
|
||||||
|
|
||||||
|
% change here for offline analysis
|
||||||
|
homedir = sprintf('~/Data10/');
|
||||||
|
%homedir = '/mnt/das-gpfs/work/p16268/';
|
||||||
|
|
||||||
|
%CHANGE: spec dat file
|
||||||
|
SpecDatFile = '~/Data10';
|
||||||
|
|
||||||
|
if (detno == 1 )||(detno == 2)
|
||||||
|
datadir = fullfile(sprintf('%s',homedir),sprintf('pilatus_%d/',detno));
|
||||||
|
elseif detno == 3
|
||||||
|
datadir = fullfile(sprintf('%s',homedir),sprintf('eiger'));
|
||||||
|
end
|
||||||
|
if detno == 2
|
||||||
|
integdir = sprintf('%sanalysis/radial_integration_waxs%s/',homedir,file_flag);
|
||||||
|
elseif detno == 1
|
||||||
|
integdir = sprintf('%sanalysis/radial_integration%s/',homedir,file_flag);
|
||||||
|
elseif detno == 3
|
||||||
|
integdir = sprintf('%sanalysis/radial_integration_eiger%s/',homedir,file_flag);
|
||||||
|
end
|
||||||
|
if detno == 2
|
||||||
|
outdir = sprintf('%sanalysis/data_waxs%s/',homedir,file_flag);
|
||||||
|
elseif detno == 1
|
||||||
|
outdir = sprintf('%sanalysis/data/%s',homedir,file_flag);
|
||||||
|
elseif detno == 3
|
||||||
|
outdir = sprintf('%sanalysis/data_eiger%s/',homedir,file_flag);
|
||||||
|
end
|
||||||
|
addpath(sprintf('%smatlab/',homedir));
|
||||||
|
if (detno == 1 )||(detno == 2)
|
||||||
|
maskfilename = sprintf('%spilatus_%d_valid_mask%s.mat', outdir,detno,file_flag);
|
||||||
|
integmaskfilename=sprintf('%spilatus_%d_integration_masks%s.mat',outdir,detno,file_flag);
|
||||||
|
elseif detno == 3
|
||||||
|
maskfilename = sprintf('%seiger_%d_valid_mask%s.mat', outdir,detno,file_flag);
|
||||||
|
integmaskfilename=sprintf('%seiger_%d_integration_masks%s.mat',outdir,detno,file_flag);
|
||||||
|
end
|
||||||
|
maskcoordfilename=sprintf('%smask_coordinates_%d%s.mat',outdir,detno, file_flag);
|
||||||
|
|
||||||
|
dirs = whos('-regexp','.*dir$');
|
||||||
|
for ii=1:numel(dirs)
|
||||||
|
dir_to_do = eval(dirs(ii).name);
|
||||||
|
if ~exist(dir_to_do,'dir')
|
||||||
|
fprintf('creating directory %s\n', dir_to_do);
|
||||||
|
system(sprintf('mkdir -p %s',dir_to_do));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
%% enter scan numbers of standards
|
||||||
|
%glassy carbon, glassy carbon moved detector to side, air scattering, first
|
||||||
|
%one is glassy carbon used to remove beamstop later
|
||||||
|
scannr = [14 15 14];
|
||||||
|
%AgBE (for SAXS and WAXS), LaB6 (for WAXS), Si (for WAXS)
|
||||||
|
todo = [12 13 14];
|
||||||
|
legendstr = {'AgBE';'LaB6';'Si'};
|
||||||
|
|
||||||
|
%% step 1: prepare the valid pixel mask
|
||||||
|
redo = 1;
|
||||||
|
|
||||||
|
if (redo)
|
||||||
|
fprintf('preparing the valid pixel mask\n');
|
||||||
|
|
||||||
|
% calculating the union of several valid pixel masks
|
||||||
|
% starting with a rather dark file to discriminate hot pixels
|
||||||
|
system(sprintf('rm -f %s', maskfilename));
|
||||||
|
|
||||||
|
if (detno == 1 )||(detno == 2)
|
||||||
|
prepvalidmask_args = {};
|
||||||
|
compilex12sa_args = {'DetectorNumber',detno,'FileExtension','cbf'};
|
||||||
|
integrate_range_args = {'PilatusDetNo',detno,'FileExtension','cbf'};
|
||||||
|
elseif detno == 3
|
||||||
|
prepvalidmask_args = {'H5Location','/eh5/images/','FilenameMask','*'};
|
||||||
|
compilex12sa_args = {'FileExtension','h5'};
|
||||||
|
end
|
||||||
|
|
||||||
|
for ii=scannr
|
||||||
|
beamline.prep_valid_mask(utils.compile_x12sa_filename(ii,-1, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID,compilex12sa_args{:}), ...
|
||||||
|
'ThresholdDark',1, ...
|
||||||
|
'ThresholdHot',20, ...
|
||||||
|
'Extend','or', ...
|
||||||
|
'FilenameValidMask',maskfilename,prepvalidmask_args{:});
|
||||||
|
% 'FigNo',ii==scannr(end));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
%% step 2: cut out beam stop and shadows manually (for WAXS only necessary if there is a shadow)
|
||||||
|
|
||||||
|
redo = 1;
|
||||||
|
if (redo)
|
||||||
|
scannr = scannr(1);
|
||||||
|
if (detno == 1)||(detno == 2)
|
||||||
|
compilex12sa_args = {'DetectorNumber',detno,'FileExtension','cbf'};
|
||||||
|
imageshow_args = {};
|
||||||
|
elseif (detno == 3)
|
||||||
|
compilex12sa_args = {'FileExtension','h5'};
|
||||||
|
imageshow_args = {'H5Location','/eh5/images/'};
|
||||||
|
end
|
||||||
|
% include the beamstop in the valid pixel mask - follow instructions in
|
||||||
|
% popup box
|
||||||
|
beamline.choose_beamstop_mask(utils.compile_x12sa_filename(scannr(1),0, 'BasePath',datadir,'BaseName',userID, compilex12sa_args{:}),...
|
||||||
|
'ReadCoord',0,'SaveCoord',1, 'SaveData',1,'FilenameValidMask',maskfilename,'FilenameCoord',maskcoordfilename, 'ImageShowArgs', imageshow_args)
|
||||||
|
|
||||||
|
end
|
||||||
|
%% show silver behenate scattering to find the radius of the first ring (only SAXS)
|
||||||
|
if (detno==1)
|
||||||
|
plotting.image_show(utils.compile_x12sa_filename(todo(1),0, ...
|
||||||
|
'PointWildcard', 1, ...
|
||||||
|
'SubExpWildcard', 1, ...
|
||||||
|
'DetectorNumber',detno, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID), ...
|
||||||
|
'IsFmask', true);
|
||||||
|
elseif (detno == 3)
|
||||||
|
filepath = utils.compile_x12sa_dirname(todo(1));
|
||||||
|
D = dir(fullfile(datadir,filepath,'*.h5'));
|
||||||
|
plotting.image_show(fullfile(D(1).folder,D(1).name), ...
|
||||||
|
'H5Location','/eh5/images/');
|
||||||
|
end
|
||||||
|
%% here you have to give some manual inputs to run step 3
|
||||||
|
% for SAXS you have to put y pixel value of the the silver behenate ring above the beamstop, and the order of the peak that you chose
|
||||||
|
if (detno==1)||(detno == 3)
|
||||||
|
order_AgBE = 1;
|
||||||
|
y_from = 509;
|
||||||
|
y_to = 514;
|
||||||
|
cen_guess = []; %[y,x] ; leave empty, i.e. cen_guess=[], for automatic guess;
|
||||||
|
%and choose how many sectors you want to do the integration (16 for
|
||||||
|
%anisotropic scattering, 1 for isotropic scattering
|
||||||
|
num_segments=16;
|
||||||
|
elseif (detno==2)
|
||||||
|
%for WAXS you can run with the default values to start with and adjust in
|
||||||
|
%case an error appears or the fit (shown in figure 4) is bad
|
||||||
|
|
||||||
|
open('+beamline/WAXS_standards.fig');
|
||||||
|
%give the order of the first silver behenate ring appearing
|
||||||
|
%(compare with WAXS_standards.fig)
|
||||||
|
order_AgBe=7;
|
||||||
|
|
||||||
|
%parameter used in finding the x-position, default 5, if in figure 20 the
|
||||||
|
%blue curve is all zeros, lower this value (necessary for low intensity of
|
||||||
|
%silver behenate measurement
|
||||||
|
d = 5;
|
||||||
|
|
||||||
|
%threshold to find WAXS peak of standards, default is 50, might be lowered
|
||||||
|
%for lower intensities
|
||||||
|
threshold=[2 50 100];
|
||||||
|
%if wrong peaks are found tune finding the right peaks with the window
|
||||||
|
%where peaks are being searched here, default is min=0 and max=1500,
|
||||||
|
%(see WAXS_standards.fig)
|
||||||
|
min_AgBE=0;
|
||||||
|
max_AgBE=1500;
|
||||||
|
min_Si=0;
|
||||||
|
max_Si=1500;
|
||||||
|
min_LaB6=0;
|
||||||
|
max_LaB6=1500;
|
||||||
|
|
||||||
|
end
|
||||||
|
% step 3: prepare integration mask
|
||||||
|
% For the WAXS mask this is still a bit clunky. You can adjust above the
|
||||||
|
% min and max values where it will look for a peak and the threshold. Also
|
||||||
|
% in the fit for the horizonal position make sure there is both red and
|
||||||
|
% blue peaks for the fitting, if not you can adjust the d parameter above.
|
||||||
|
% Decreasing it helps when the silver behenate scattering is low.
|
||||||
|
|
||||||
|
if (detno==1)
|
||||||
|
scannr = todo(1);
|
||||||
|
else
|
||||||
|
%here enter the scannumbers of the standards
|
||||||
|
% todo = [211,208,212];
|
||||||
|
% legendstr = {'AgBE';'LaB6';'Si'};
|
||||||
|
scannr = todo(1);
|
||||||
|
S = io.spec_read(SpecDatFile,'ScanNr',todo(1));
|
||||||
|
end
|
||||||
|
|
||||||
|
if (detno==1)||(detno==2)
|
||||||
|
I = plotting.image_show(utils.compile_x12sa_filename(scannr,0, ...
|
||||||
|
'PointWildcard', 1, ...
|
||||||
|
'SubExpWildcard', 1, ...
|
||||||
|
'DetectorNumber',detno, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID), ...
|
||||||
|
'IsFmask', true);
|
||||||
|
elseif (detno == 3)
|
||||||
|
filepath = utils.compile_x12sa_dirname(scannr);
|
||||||
|
D = dir(fullfile(datadir,filepath,'*.h5'));
|
||||||
|
I = plotting.image_show(fullfile(D(1).folder,D(1).name), ...
|
||||||
|
'H5Location','/eh5/images/');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mask = getfield(load(maskfilename),'valid_mask');
|
||||||
|
mask.frame = zeros(mask.framesize);
|
||||||
|
mask.frame(mask.indices) = 1;
|
||||||
|
|
||||||
|
I = mean(I.data,3).*mask.frame;
|
||||||
|
if (detno==1)||(detno == 3)
|
||||||
|
J = ifftn(fftn(I,size(I)*2-[1 1]).^2);
|
||||||
|
if isempty(cen_guess)
|
||||||
|
cen_guess = math.peakfit2d(J)/2; %[y,x]
|
||||||
|
end
|
||||||
|
|
||||||
|
if (detno == 1)
|
||||||
|
filename_center = utils.compile_x12sa_filename(scannr(1),0, 'BasePath',datadir,'BaseName',userID);
|
||||||
|
imageshow_args = {};
|
||||||
|
elseif (detno == 3)
|
||||||
|
filename_center = fullfile(D(1).folder,D(1).name);
|
||||||
|
imageshow_args = {'H5Location','/eh5/images/'};
|
||||||
|
end
|
||||||
|
|
||||||
|
[cen]=utils.get_beam_center(filename_center,'GuessX',cen_guess(2),'GuessY',cen_guess(1), ...
|
||||||
|
'RadiusFrom',y_from-cen_guess(1),'RadiusTo',y_to-cen_guess(1), ...
|
||||||
|
'TestX',4,'TestY',4,'FilenameValidMask',maskfilename, imageshow_args{:});
|
||||||
|
|
||||||
|
else
|
||||||
|
% this isn't nice yet
|
||||||
|
% i) it depends on the chosen orientation on how to read
|
||||||
|
% detector-2 images
|
||||||
|
% ii) it merely finds maximum values instead of fitting, possibly
|
||||||
|
% with sub-pixel precision
|
||||||
|
% iii) as a consequence, figuring out which values are trustworthy
|
||||||
|
% is done rather crudly
|
||||||
|
%d = 3; %5 seams not to work if intensity of silver behenate is too low??
|
||||||
|
if (detno == 2)
|
||||||
|
imageshow_args = {};
|
||||||
|
end
|
||||||
|
dx = 30;
|
||||||
|
[s1,s2] = size(I);
|
||||||
|
|
||||||
|
J = ifft(fft(I,s1*2-1,1).^2,[],1);
|
||||||
|
[~,n] = max(J);
|
||||||
|
w = std(I,1,1)./sqrt(mean(I,1));
|
||||||
|
o = 1:numel(n);
|
||||||
|
|
||||||
|
o = o(w>d);
|
||||||
|
n = n(w>d)/2;
|
||||||
|
|
||||||
|
o = o(abs(n-s1/2)<dx);
|
||||||
|
n = n(abs(n-s1/2)<dx);
|
||||||
|
|
||||||
|
x = s1/2+linspace(-dx,dx,4*dx+1);
|
||||||
|
|
||||||
|
figure(20)
|
||||||
|
m = histc(n,x);
|
||||||
|
[~,n0] = max(m);
|
||||||
|
plot(x,m)
|
||||||
|
hold on
|
||||||
|
|
||||||
|
s = fitoptions('Method','NonlinearLeastSquares',...
|
||||||
|
'Lower',[ 0,s1/2-dx, 0, 0, 0],...
|
||||||
|
'Upper',[Inf,s1/2+dx,Inf,Inf,Inf],...
|
||||||
|
'Startpoint',[10,x(n0),1,10,1]);
|
||||||
|
f = fittype('a*exp(-((x-b)/c)^2)+d*exp(-((x-n)/e)^2)', ...
|
||||||
|
'problem','n','options',s);
|
||||||
|
[c,~] = fit(x',m',f,'problem',s1/2);
|
||||||
|
figure(50)
|
||||||
|
plot(c,'r');
|
||||||
|
hold off
|
||||||
|
|
||||||
|
figure(10)
|
||||||
|
cen1 = c.b;
|
||||||
|
o = o(abs(n-cen1)<=1);
|
||||||
|
n = n(abs(n-cen1)<=1);
|
||||||
|
hold on
|
||||||
|
plot(o,n,'w.')
|
||||||
|
plot([1 s2],[1 1]*round(cen1),'w')
|
||||||
|
x = 1:s2;
|
||||||
|
plot(x(mask.frame(round(cen1),:)>0), ...
|
||||||
|
log(I(round(cen1),mask.frame(round(cen1),:)>0))/ ...
|
||||||
|
max(log(I(round(cen1),mask.frame(round(cen1),:)>0)))*s1, ...
|
||||||
|
'k')
|
||||||
|
hold off
|
||||||
|
|
||||||
|
figure(30)
|
||||||
|
WAXS = zeros(s2,numel(todo));
|
||||||
|
WAXS(:,1) = I(round(cen1),:);
|
||||||
|
for ii=2:numel(todo)
|
||||||
|
I = io.image_read(utils.compile_x12sa_filename(todo(ii),0, ...
|
||||||
|
'PointWildcard', 1, ...
|
||||||
|
'SubExpWildcard', 1, ...
|
||||||
|
'DetectorNumber',detno, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID), ...
|
||||||
|
'IsFmask', 1);
|
||||||
|
WAXS(:,ii) = mean(I.data(round(cen1),:,:),3);
|
||||||
|
end
|
||||||
|
|
||||||
|
h = semilogy(WAXS);
|
||||||
|
legend(legendstr)
|
||||||
|
|
||||||
|
% finding peaks "automatically"
|
||||||
|
x_coord = [];
|
||||||
|
q_coord = [];
|
||||||
|
hold on
|
||||||
|
peaks = cell(1,size(WAXS,2));
|
||||||
|
for ii=1:size(WAXS,2)
|
||||||
|
%the treshhold value, default set to 50, might be adjusted
|
||||||
|
peaks{ii} = utils.peakfinder((WAXS(:,ii)),threshold(ii));
|
||||||
|
%peaks{ii} = peakfinder((WAXS(:,ii)),50);
|
||||||
|
if strcmp(legendstr{ii},'AgBE')
|
||||||
|
tmp = peaks{ii};
|
||||||
|
tmp = tmp(tmp>=min_AgBE);
|
||||||
|
peaks{ii} = tmp(tmp<=max_AgBE);
|
||||||
|
|
||||||
|
end
|
||||||
|
if strcmp(legendstr{ii},'Si')
|
||||||
|
tmp = peaks{ii};
|
||||||
|
tmp = tmp(tmp>=min_Si);
|
||||||
|
peaks{ii} = tmp(tmp<=max_Si);
|
||||||
|
end
|
||||||
|
if strcmp(legendstr{ii},'LaB6')
|
||||||
|
tmp = peaks{ii};
|
||||||
|
tmp = tmp(tmp<=max_LaB6);
|
||||||
|
peaks{ii} = tmp(tmp>=min_LaB6);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
x_coord = vertcat(x_coord,peaks{ii});
|
||||||
|
if strcmp(legendstr{ii},'AgBE')
|
||||||
|
q0 = 2*pi/58.38;
|
||||||
|
q_coord = horzcat(q_coord,q0*(order_AgBe+(0:numel(peaks{ii})-1)));
|
||||||
|
elseif strcmp(legendstr{ii},'LaB6')
|
||||||
|
q0 = 2*pi/4.1549;
|
||||||
|
q_coord = horzcat(q_coord,q0*sqrt((1:numel(peaks{ii}))));
|
||||||
|
elseif strcmp(legendstr{ii},'Si')
|
||||||
|
q0 = 2*pi/5.4308;
|
||||||
|
q_coord = horzcat(q_coord,q0*sqrt(3));
|
||||||
|
end
|
||||||
|
semilogy(peaks{ii},WAXS(peaks{ii},ii),'.', ...
|
||||||
|
'Color',get(h(ii),'Color'), ...
|
||||||
|
'MarkerSize',24)
|
||||||
|
end
|
||||||
|
hold off
|
||||||
|
|
||||||
|
figure(40); clf
|
||||||
|
if (numel(x_coord)>3)
|
||||||
|
% fprintf('%f\t%f\n',[x_coord';q_coord])
|
||||||
|
% % a
|
||||||
|
% % b
|
||||||
|
% % c
|
||||||
|
s = fitoptions('Method','NonlinearLeastSquares',...
|
||||||
|
'Lower' ,[-Inf,-Inf, 0],...
|
||||||
|
'Upper' ,[ Inf, 0,1e3],...
|
||||||
|
'Startpoint',[s2/2, 200,550]);
|
||||||
|
f = fittype('4*pi/l*sin((atan((a-b)*p/c)+atan((x-a)*p/c))/2)', ...
|
||||||
|
'problem',{'p','l'},'options',s);
|
||||||
|
[c,~] = fit(x_coord,q_coord',f,'problem',{.172,12.398/S.mokev});
|
||||||
|
subplot(2,1,1)
|
||||||
|
plot(x_coord,q_coord,'x');
|
||||||
|
hold on
|
||||||
|
drawnow;
|
||||||
|
tmp = axis;
|
||||||
|
x = linspace(c.b,tmp(2));
|
||||||
|
plot(x,feval(c,x),'r');
|
||||||
|
subplot(2,1,2)
|
||||||
|
bar(x_coord,feval(c,x_coord)-q_coord');
|
||||||
|
xlim(tmp(1:2));
|
||||||
|
dc = confint(c);
|
||||||
|
dc = (dc(2,:)-dc(1,:))/2;
|
||||||
|
fprintf(['detector distance:\t%.1fmm, \t%.1fmm\n', ...
|
||||||
|
'center of rings: \t%.1fpixels,\t%.1fpixels\n', ...
|
||||||
|
'angle of detector:\t%.1fdeg, \t%.1fdeg.\n'], ...
|
||||||
|
c.c,dc(3), ...
|
||||||
|
c.b,dc(2), ...
|
||||||
|
atan((c.a-c.b)*c.p/c.c)/pi*180, ...
|
||||||
|
180/pi*c.p/c.c*sqrt(dc(1)^2+dc(2)^2 + ((c.a-c.b)/c.c*dc(3))^2));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
tic
|
||||||
|
if (detno==1)||(detno==3)
|
||||||
|
S = io.spec_read(SpecDatFile,'ScanNr',todo(1));
|
||||||
|
fprintf('preparing the integration mask(s)\n');
|
||||||
|
beamline.prep_integ_masks(utils.compile_x12sa_filename(todo(1),0, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID, compilex12sa_args{:}), ...
|
||||||
|
cen, ...
|
||||||
|
'DetNo',detno, ...
|
||||||
|
'NoOfSegments',num_segments, ...
|
||||||
|
'FilenameValidMask',maskfilename, ...
|
||||||
|
'FilenameIntegMasks',integmaskfilename, imageshow_args{:});
|
||||||
|
|
||||||
|
beamline.integrate_range(todo(1),todo(1),1, ... % change for not re-running on already integrated files
|
||||||
|
'OutdirData',integdir, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID, ...
|
||||||
|
'FilenameIntegMasks',integmaskfilename, ...
|
||||||
|
compilex12sa_args{:},imageshow_args{:});
|
||||||
|
|
||||||
|
elseif (detno==2)
|
||||||
|
S = io.spec_read(SpecDatFile,'ScanNr',todo(1));
|
||||||
|
fprintf('preparing the integration mask(s)\n');
|
||||||
|
beamline.prep_integ_masks(utils.compile_x12sa_filename(todo(1),0, ...
|
||||||
|
'DetectorNumber',detno, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID), ...
|
||||||
|
[c.b cen1], ...
|
||||||
|
'DetNo',detno, ...
|
||||||
|
'Wavelength_nm', 12.398/S.mokev, ...
|
||||||
|
'NormalXY', [c.a cen1], ...
|
||||||
|
'DetDist_mm', c.c, ...
|
||||||
|
'PixelSize_mm', .172, ...
|
||||||
|
'NoOfSegments',1, ...
|
||||||
|
'FilenameValidMask',maskfilename, ...
|
||||||
|
'FilenameIntegMasks',integmaskfilename, ...
|
||||||
|
'DisplayValidMask',0);
|
||||||
|
end
|
||||||
|
toc
|
||||||
|
|
||||||
|
|
||||||
|
%% calculate detector distance (SAXS only) check in Figure 100 if the peak_agbe really is the 1st order AgBE
|
||||||
|
if (detno==1)||(detno==3)
|
||||||
|
[x,y] = plotting.plot_radial_integ(sprintf('%s%s%d_%05d_00000_00000_integ.mat',integdir,userID,1,todo(1)));
|
||||||
|
%%the 1st order silver behenate is at ... pixels
|
||||||
|
%peakfinder(log(y(10:end)),1);
|
||||||
|
peaks2 = utils.peakfinder(log(y(10:end)),1);
|
||||||
|
peak_agbe = x(peaks2(order_AgBE+1))+9 %normally the 1st order AgBE, check!
|
||||||
|
wavelength = 12.398/S.mokev;
|
||||||
|
detector_distance = peak_agbe*.172/tan(2*asin(wavelength*order_AgBE/(2*58.38)))
|
||||||
|
end
|
||||||
|
%% redo SAXS integration mask now it will take the detector distance into account and also save the q-value
|
||||||
|
if (detno==1)||(detno==3)
|
||||||
|
if (detno == 1)
|
||||||
|
detector_pixelsize = 0.172;
|
||||||
|
elseif (detno == 3)
|
||||||
|
detector_pixelsize = 0.075;
|
||||||
|
end
|
||||||
|
S = io.spec_read(SpecDatFile,'ScanNr',todo(1));
|
||||||
|
fprintf('preparing the integration mask(s)\n');
|
||||||
|
beamline.prep_integ_masks(utils.compile_x12sa_filename(todo(1),0, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID,compilex12sa_args{:}), ...
|
||||||
|
cen, ...
|
||||||
|
'DetNo',detno, ...
|
||||||
|
'NoOfSegments',num_segments, ...
|
||||||
|
'Wavelength_nm', 12.398/S.mokev, ...
|
||||||
|
'DetDist_mm', detector_distance, ...
|
||||||
|
'PixelSize_mm', detector_pixelsize, ...
|
||||||
|
'FilenameValidMask',maskfilename, ...
|
||||||
|
'FilenameIntegMasks',integmaskfilename, imageshow_args{:});
|
||||||
|
end
|
||||||
|
%% step 5: radial integration & averaging of files --
|
||||||
|
%start here again if you merely want to integreat
|
||||||
|
%for fast measurements (i.e. scanning SAXS) start on several cn parallel
|
||||||
|
%adjust therefor integrate_range(scan_no_from,scan_no_to,scan_no_step)
|
||||||
|
%and rund only step 0 and step 5
|
||||||
|
save_format = '-v6';
|
||||||
|
|
||||||
|
close all
|
||||||
|
% beamline.integrate_range(107,1e8,3, ... % change for not re-running on already integrated files
|
||||||
|
% 'PilatusDetNo',detno, ...
|
||||||
|
% 'OutdirData',integdir, ...
|
||||||
|
% 'BasePath',datadir,'BaseName',userID, ...
|
||||||
|
% 'FilenameIntegMasks',integmaskfilename, 'SaveFormat', save_format);
|
||||||
|
|
||||||
|
beamline.integrate_range(136,137,1, ... % change for not re-running on already integrated files
|
||||||
|
'OutdirData',integdir, ...
|
||||||
|
'BasePath',datadir,'BaseName',userID, ...
|
||||||
|
'FilenameIntegMasks',integmaskfilename, 'SaveFormat', save_format, ...
|
||||||
|
integrate_range_args{:},imageshow_args{:});
|
||||||
|
|
||||||
|
|
||||||
|
%% or alternatively when computers node are ready and matlab is open
|
||||||
|
save_format = '-v6';
|
||||||
|
fprintf('beamline.integrate_range(107,1e8,4,''OutdirData'',''%s'',''BasePath'',''%s'',''BaseName'',''%s'',''FilenameIntegMasks'',''%s'',''SaveFormat'', ''%s''',integdir,datadir,userID,integmaskfilename,save_format)
|
||||||
|
args={'OutdirData', integdir,'BasePath',datadir ,'BaseName',userID ,'FilenameIntegMasks',integmaskfilename ,'SaveFormat',save_format };
|
||||||
|
|
||||||
|
for ii = 1:2:numel(integrate_range_args)
|
||||||
|
if ischar(integrate_range_args{ii+1})
|
||||||
|
straux = '''%s''';
|
||||||
|
elseif isnumeric(integrate_range_args{ii+1})
|
||||||
|
straux = '%d';
|
||||||
|
end
|
||||||
|
fprintf( [',''%s'',' straux ' '] ,integrate_range_args{ii},integrate_range_args{ii+1});
|
||||||
|
args=[args,integrate_range_args{ii},integrate_range_args{ii+1}];
|
||||||
|
end
|
||||||
|
for ii = 1:2:numel(imageshow_args)
|
||||||
|
if ischar(imageshow_args{ii+1})
|
||||||
|
straux = '''%s''';
|
||||||
|
elseif isnumeric(imageshow_args{ii+1})
|
||||||
|
straux = '%d';
|
||||||
|
end
|
||||||
|
fprintf([',''%s'',' straux ' '],imageshow_args{ii},imageshow_args{ii+1});
|
||||||
|
args=[args,imageshow_args{ii},imageshow_args{ii+1}];
|
||||||
|
end
|
||||||
|
|
||||||
|
% if detno==2 % Disable CReader for WAXS detector since currently it's not supported.
|
||||||
|
% fprintf([',''CReader'',0 ']);
|
||||||
|
% args=[args,'CReader',0];
|
||||||
|
% end
|
||||||
|
|
||||||
|
fprintf(');\n')
|
||||||
|
|
||||||
|
folder_todo=utils.abspath('~/Data10/analysis/radial_integration_todo/');
|
||||||
|
if ~exist(folder_todo)
|
||||||
|
mkdir(folder_todo);
|
||||||
|
end
|
||||||
|
|
||||||
|
save(sprintf([folder_todo 'vargin_det%d.mat'],detno),'args');
|
||||||
|
fprintf(['Parameters saved to' folder_todo 'vargin_det%d.mat\n'],detno);
|
||||||
|
%%
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
% read_omny_angles( OMNY_angles_file, scannums, tomo_id )
|
||||||
|
% OMNY_angles_file - File with Scan number, angle target, angle readout
|
||||||
|
% scannums - Array of scan numbers
|
||||||
|
% tomo_id - integer or list of integers, only if the scannums is empty
|
||||||
|
%
|
||||||
|
% out - Contains fields with scan, target_angle, readout_angle
|
||||||
|
% errorflag - = 1 if at least one scan was not found
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ out errorflag ] = read_omny_angles( OMNY_angles_file, scannums, tomo_id )
|
||||||
|
|
||||||
|
if ~exist(OMNY_angles_file, 'file')
|
||||||
|
error('Missing OMNY file: %s', OMNY_angles_file)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~exist('tomo_id')
|
||||||
|
tomo_id = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
if (~isempty(scannums))&&(~isempty(tomo_id))
|
||||||
|
error('You have provided both scannums and tomo_id, please provide just either scannums OR tomo_id. One of them should be empty ( =[] ).')
|
||||||
|
end
|
||||||
|
if (isempty(scannums))&&(isempty(tomo_id))
|
||||||
|
error('You have not provided scannums or tomo_id, please provide either scannums OR tomo_id. One of them should be empty ( =[] ).')
|
||||||
|
end
|
||||||
|
fid = fopen(OMNY_angles_file);
|
||||||
|
|
||||||
|
% check omny file type
|
||||||
|
ln = fgetl(fid);
|
||||||
|
switch numel(strsplit(ln, ' '))
|
||||||
|
case {3,6}
|
||||||
|
outmat = textscan(fid,'%f %f %f %f %f %s');
|
||||||
|
fclose(fid);
|
||||||
|
out = [];
|
||||||
|
errorflag = 0;
|
||||||
|
counter = 1;
|
||||||
|
|
||||||
|
for ii = 1:numel(scannums)
|
||||||
|
ind = find(outmat{1}==scannums(ii),1,'last');
|
||||||
|
if isempty(ind)
|
||||||
|
fprintf('Did not find Scan %d in %s\n',scannums(ii),OMNY_angles_file);
|
||||||
|
errorflag = 1;
|
||||||
|
else
|
||||||
|
out.scan(counter) = outmat{1}(ind);
|
||||||
|
out.target_angle(counter) = outmat{2}(ind);
|
||||||
|
out.readout_angle(counter) = outmat{3}(ind);
|
||||||
|
out.subtomo_num(counter) = outmat{4}(ind);
|
||||||
|
out.detpos_num(counter) = outmat{5}(ind);
|
||||||
|
out.sample_name(counter) = outmat{6}(ind);
|
||||||
|
counter = counter+1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
case 7
|
||||||
|
outmat = textscan(fid,'%f %f %f %f %f %f %s');
|
||||||
|
fclose(fid);
|
||||||
|
out = [];
|
||||||
|
errorflag = 0;
|
||||||
|
counter = 1;
|
||||||
|
if ~isempty(scannums)
|
||||||
|
for ii = 1:numel(scannums)
|
||||||
|
ind = find(outmat{1}==scannums(ii),1,'last');
|
||||||
|
if isempty(ind)
|
||||||
|
fprintf('Did not find Scan %d in %s\n',scannums(ii),OMNY_angles_file);
|
||||||
|
errorflag = 1;
|
||||||
|
else
|
||||||
|
out.scan(counter) = outmat{1}(ind);
|
||||||
|
out.target_angle(counter) = outmat{2}(ind);
|
||||||
|
out.readout_angle(counter) = outmat{3}(ind);
|
||||||
|
out.tomo_id(counter) = outmat{4}(ind);
|
||||||
|
out.subtomo_num(counter) = outmat{5}(ind);
|
||||||
|
out.detpos_num(counter) = outmat{6}(ind);
|
||||||
|
out.sample_name(counter) = outmat{7}(ind);
|
||||||
|
counter = counter+1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif ~isempty(tomo_id)
|
||||||
|
ind = find(ismember(outmat{4},tomo_id));
|
||||||
|
if isempty(ind)
|
||||||
|
fprintf(['Did not find tomo_id ',repmat('%i ',1,length(tomo_id)),' in %s\n'],tomo_id,OMNY_angles_file);
|
||||||
|
errorflag = 1;
|
||||||
|
end
|
||||||
|
out.scan = outmat{1}(ind);
|
||||||
|
out.target_angle = outmat{2}(ind);
|
||||||
|
out.readout_angle = outmat{3}(ind);
|
||||||
|
out.tomo_id = outmat{4}(ind);
|
||||||
|
out.subtomo_num = outmat{5}(ind);
|
||||||
|
out.detpos_num = outmat{6}(ind);
|
||||||
|
out.sample_name = outmat{7}(ind);
|
||||||
|
end
|
||||||
|
otherwise
|
||||||
|
error('Unknown OMNY file format.')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
% Read interferometer positions written by Orchestra
|
||||||
|
% Input is the filename with path
|
||||||
|
% Output is a structure containing fields:
|
||||||
|
% The two values of the one line header originally 'Scan' and 'Samroy'
|
||||||
|
% Values for each point of 10 expected columns of numbers
|
||||||
|
% 12 June 2013
|
||||||
|
% June6 2015 - Changed in order to accept an arbitrary number
|
||||||
|
% of values in order to be compatible with 10 columns for flOMNI and 19 for
|
||||||
|
% OMNY
|
||||||
|
% This function should be replaced by beamline.read_position_file in the
|
||||||
|
% ptycho codes and deprecated.
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function struct_out = read_omny_pos( omnyposfile )
|
||||||
|
%disp(omnyposfile)
|
||||||
|
struct_out = beamline.read_position_file( omnyposfile );
|
||||||
|
%disp(size(struct_out.TotalPoints))
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
% READ_POSITION_FILE Read positions from a file, the format and header are
|
||||||
|
% compatible with multiple interferometer positions and standard deviations
|
||||||
|
% as written by Orchestra and the sgalil spec macro.
|
||||||
|
%
|
||||||
|
% struct_out = read_position_file( posfile )
|
||||||
|
% Inputs:
|
||||||
|
% **posfile filename with path
|
||||||
|
% *returns*
|
||||||
|
% ++struct_out is a structure containing fields including the values
|
||||||
|
% for header and for each scanning point
|
||||||
|
|
||||||
|
% 12 June 2013
|
||||||
|
% June6 2015 - Changed in order to accept an arbitrary number
|
||||||
|
% of values in order to be compatible with 10 columns for flOMNI and 19 for
|
||||||
|
% OMNY
|
||||||
|
% 15 Apr 2019 - Changed name and generalized description beyond OMNY and
|
||||||
|
% Orchestra
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function struct_out = read_position_file( posfile )
|
||||||
|
|
||||||
|
assert(exist(posfile, 'file')>0, ['Position file ', posfile, ' not found'])
|
||||||
|
|
||||||
|
f = fopen(posfile,'r');
|
||||||
|
header = textscan(f,'%s %d, %s %f',1);
|
||||||
|
struct_out.(header{1}{1}) = header{2};
|
||||||
|
struct_out.(header{3}{1}) = header{4};
|
||||||
|
names = textscan(f,'%s',1,'Delimiter','\r');
|
||||||
|
names = strsplit(char(names{1}));
|
||||||
|
reading_string = ['%f', repmat(' %f',1,numel(names)-1)];
|
||||||
|
values = textscan(f,reading_string);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
for ii = 1:numel(names)
|
||||||
|
struct_out.(char(names(ii))) = values{ii};
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,803 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: stxm_online.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.16 $ $Date: 2011/04/04 17:03:48 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% plot a STXM scan
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% April 4th 2011:
|
||||||
|
% do not normalize the dark field since this is problematic for SAXS with a
|
||||||
|
% beam stop
|
||||||
|
%
|
||||||
|
% September 29th 2010:
|
||||||
|
% include changes by Martin Dierolf and Joan Vila in the standard version
|
||||||
|
% of stxm_online
|
||||||
|
%
|
||||||
|
% December 10th 2008:
|
||||||
|
% add bug-fixes and suggestions from Martin Dierolf:
|
||||||
|
% DirPerLine parameter could not be set via the command line,
|
||||||
|
% BurstMode flag was always active, is now coupled to dir_per_line,
|
||||||
|
% new Parameter ZeroOrderR
|
||||||
|
%
|
||||||
|
% September 5th 2008:
|
||||||
|
% use compile_x12sa_filename,
|
||||||
|
% plot as 2x2 sub figures
|
||||||
|
%
|
||||||
|
% June 14th 2008: 1st documented version based on work
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [varargout] = stxm_online(first_scan_number, Ny, varargin)
|
||||||
|
import beamline.pilatus_valid_pixel_roi
|
||||||
|
import io.image_read
|
||||||
|
import plotting.image_show
|
||||||
|
import utils.compile_x12sa_filename
|
||||||
|
import utils.find_files
|
||||||
|
|
||||||
|
% set default values
|
||||||
|
% Pilatus 2M
|
||||||
|
detector_number = 1;
|
||||||
|
% single directory or directory per line format
|
||||||
|
dir_per_line = 1;
|
||||||
|
% figure number for display
|
||||||
|
fig_no = 2;
|
||||||
|
% number of points along a scan line, 0 for automatic determination from
|
||||||
|
% the first line
|
||||||
|
Nx = 0;
|
||||||
|
% size of the regio of interest
|
||||||
|
roi_dim = 128;
|
||||||
|
% automatic determination of the center position
|
||||||
|
cen_x = 0;
|
||||||
|
cen_y = 0;
|
||||||
|
% dark field integration starting radius
|
||||||
|
dark_field_r = 20;
|
||||||
|
% radius of excluded area around center
|
||||||
|
zero_order_r = 0;
|
||||||
|
% calculate the first moment rather than a Fourier transform to get the
|
||||||
|
% differential phase contrast
|
||||||
|
first_moment = 1;
|
||||||
|
% use additionally differentiation of the integrated phase
|
||||||
|
integrated_phase = 1;
|
||||||
|
% do not update the plot every line to save some time
|
||||||
|
update_interval = 3;
|
||||||
|
% save resulting figure
|
||||||
|
figure_dir = '~/Data10/analysis/online/stxm/figures/';
|
||||||
|
% save the resulting data
|
||||||
|
data_dir = '~/Data10/analysis/online/stxm/data/';
|
||||||
|
% valid pixel mask
|
||||||
|
filename_valid_mask = '~/Data10/analysis/data/pilatus_valid_mask.mat';
|
||||||
|
|
||||||
|
phase = [];
|
||||||
|
gx = [];
|
||||||
|
gy = [];
|
||||||
|
|
||||||
|
full_screen_position_integrated_phase = [ 5 525 1201 420];
|
||||||
|
print_a4_position_integrated_phase = [ 5 525 743 420 ];
|
||||||
|
full_screen_position_standard = [ 5 109 1201 836];
|
||||||
|
print_a4_position_standard = [ 5 109 743 836 ];
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 2)
|
||||||
|
fprintf('Usage:\n')
|
||||||
|
fprintf('[trans,dpcx,dpcy,df]=%s(<(first) scan number>, <no. of scan lines> [[,<name>,<value>] ...]);\n',...
|
||||||
|
mfilename);
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''DetectorNumber'',<1-Pilatus 2M, 2-Pilatus 300k, 3-Pilatus 100k>\n');
|
||||||
|
fprintf('''Nx'',<no. of points per line> default is %d (0 means automatic determination from first scan line)\n',Nx);
|
||||||
|
fprintf('''ROIdim'',<no. of points> region of interest used for data analysis, default is %d\n',roi_dim);
|
||||||
|
fprintf('''CenX'',<point> 0 means automatic determination, default is %d\n',cen_x);
|
||||||
|
fprintf('''CenY'',<point> 0 means automatic determination, default is %d\n',cen_y);
|
||||||
|
fprintf('''DarkFieldR'',<min. radius> dark field integration starts at this radius, default is %.0f\n',dark_field_r);
|
||||||
|
fprintf('''FigNo'',<integer value> figure number for data display, default is %d\n',fig_no);
|
||||||
|
fprintf('''DirPerLine'',<0-no,1-yes> separate directory for each scan line, default is %d\n',dir_per_line);
|
||||||
|
fprintf('''ZeroOrderR'', <min. radius> pixel values inside this radius are set to zero, default is %d\n', zero_order_r);
|
||||||
|
fprintf('''FirstMoment'',<0-no,1-yes> calculate the first moment rather than a Fourier transform to get the differential phase contrast, default is %d\n',first_moment);
|
||||||
|
fprintf('''IntegratedPhase'',<0-no,1-yes> differentiate additionally the sum signal and re-differentiate it, default is %d\n',integrated_phase);
|
||||||
|
fprintf('''UpdateInterval'',<integer N> update the plot each Nth line, default is %d\n',update_interval);
|
||||||
|
fprintf('''FigureDir'',''directory'' save the resulting plot in eps, jpeg and Matlab fig format, '''' for no saving, default is %s\n',figure_dir);
|
||||||
|
fprintf('''DataDir'',''directory'' save the resulting data as Matlab file, '''' for no saving, default is %s\n',data_dir);
|
||||||
|
fprintf('''FilenameValidMask'',<path and filename> Matlab file with the valid pixel indices ind_valid, [] for no valid pixel mask,\n');
|
||||||
|
fprintf(' default is %s\n',filename_valid_mask);
|
||||||
|
fprintf('Additional <name>,<value> pairs recognized by compile_x12sa_filename and by image_read can be specified. Please call them for an overview\n');
|
||||||
|
fprintf('\n');
|
||||||
|
error('At least the (first) scan number and the number of scan lines have to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 3)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 2 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 0)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'DetectorNumber'
|
||||||
|
detector_number = value;
|
||||||
|
case 'Nx'
|
||||||
|
Nx = value;
|
||||||
|
case 'ROIdim'
|
||||||
|
roi_dim = value;
|
||||||
|
case 'CenX'
|
||||||
|
cen_x = value;
|
||||||
|
case 'CenY'
|
||||||
|
cen_y = value;
|
||||||
|
case 'DarkFieldR'
|
||||||
|
dark_field_r = value;
|
||||||
|
case 'FigNo'
|
||||||
|
fig_no = value;
|
||||||
|
case 'DirPerLine'
|
||||||
|
dir_per_line = value;
|
||||||
|
case 'ZeroOrderR'
|
||||||
|
zero_order_r = value;
|
||||||
|
case 'FirstMoment'
|
||||||
|
first_moment = value;
|
||||||
|
case 'IntegratedPhase'
|
||||||
|
integrated_phase = value;
|
||||||
|
case 'UpdateInterval'
|
||||||
|
update_interval = value;
|
||||||
|
case 'FilenameValidMask'
|
||||||
|
filename_valid_mask = value;
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% pass some parameters to image_show
|
||||||
|
vararg(11:(end+10)) = vararg;
|
||||||
|
vararg{ 1} = 'RetryReadSleep';
|
||||||
|
vararg{ 2} = 5.0;
|
||||||
|
vararg{ 3} = 'RetryReadMax';
|
||||||
|
vararg{ 4} = 5;
|
||||||
|
vararg{ 5} = 'ErrorIfNotFound';
|
||||||
|
vararg{ 6} = 0;
|
||||||
|
% vararg{ 7} = 'BurstMode';
|
||||||
|
% if (dir_per_line)
|
||||||
|
% vararg{ 8} = 1;
|
||||||
|
% else
|
||||||
|
% vararg{ 8} = 0;
|
||||||
|
% end
|
||||||
|
vararg{7} = 'UnhandledParError';
|
||||||
|
vararg{8} = 0;
|
||||||
|
vararg{9} = 'DetectorNumber';
|
||||||
|
vararg{10} = detector_number;
|
||||||
|
|
||||||
|
% region of interest index in each dimension
|
||||||
|
roi_rel_ind = -round(0.5*roi_dim):(round(0.5*roi_dim)-1);
|
||||||
|
|
||||||
|
% load the indices of valid pixels
|
||||||
|
if ((~isempty(filename_valid_mask)) && (exist(filename_valid_mask,'file')))
|
||||||
|
fprintf('loading the valid pixel mask %s\n',filename_valid_mask);
|
||||||
|
load(filename_valid_mask);
|
||||||
|
end
|
||||||
|
|
||||||
|
% wait for the data to be available
|
||||||
|
scan_no_check = first_scan_number;
|
||||||
|
if ((dir_per_line) && (Ny > 1))
|
||||||
|
scan_no_check = scan_no_check +1;
|
||||||
|
end
|
||||||
|
filename_mask = compile_x12sa_filename(scan_no_check,0,'DetectorNumber',detector_number);
|
||||||
|
[~, fnames] = find_files(filename_mask);
|
||||||
|
data_available = (~isempty(fnames));
|
||||||
|
if (~data_available)
|
||||||
|
fprintf('Waiting for %s to become available.\n',filename_mask);
|
||||||
|
while (~data_available);
|
||||||
|
pause(1);
|
||||||
|
[~, fnames] = find_files(filename_mask);
|
||||||
|
data_available = (~isempty(fnames));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check that number of points per line determination will be possible
|
||||||
|
|
||||||
|
% determine number of points per line
|
||||||
|
if (Nx <= 0)
|
||||||
|
if (~dir_per_line)
|
||||||
|
error('The number of points per line can only automatically be determined if separate scan directories are used for each line.');
|
||||||
|
end
|
||||||
|
vararg_remain = vararg;
|
||||||
|
vararg_remain(3:(end+2)) = vararg_remain;
|
||||||
|
vararg_remain{1} = 'SubExpWildcard';
|
||||||
|
vararg_remain{2} = 1;
|
||||||
|
[fmask,vararg_remain] = ...
|
||||||
|
compile_x12sa_filename(first_scan_number,0,vararg_remain); %#ok<NASGU>
|
||||||
|
Nx = length(dir(fmask));
|
||||||
|
if (Nx < 1)
|
||||||
|
error('No matching files found for %s',fmask);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
fprintf('%d lines with %d points per line in\n',Ny,Nx);
|
||||||
|
|
||||||
|
|
||||||
|
if (integrated_phase)
|
||||||
|
figure(fig_no +1);
|
||||||
|
hold off;
|
||||||
|
clf;
|
||||||
|
% print as layed out on the screen, i.e., preserve aspect ratio
|
||||||
|
set(gcf,'PaperPositionMode','auto');
|
||||||
|
% paper size
|
||||||
|
set(gcf,'PaperType','A4');
|
||||||
|
% background color
|
||||||
|
set(gcf,'Color','white');
|
||||||
|
% resize and position
|
||||||
|
set(gcf,'Position',full_screen_position_integrated_phase);
|
||||||
|
|
||||||
|
colormap(bone(256));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
figure(fig_no);
|
||||||
|
hold off;
|
||||||
|
clf;
|
||||||
|
% print as layed out on the screen, i.e., preserve aspect ratio
|
||||||
|
set(gcf,'PaperPositionMode','auto');
|
||||||
|
% paper size
|
||||||
|
set(gcf,'PaperType','A4');
|
||||||
|
% background color
|
||||||
|
set(gcf,'Color','white');
|
||||||
|
% resize and position
|
||||||
|
set(gcf,'Position',full_screen_position_standard);
|
||||||
|
|
||||||
|
colormap(bone(256));
|
||||||
|
|
||||||
|
|
||||||
|
% STXM display loop
|
||||||
|
point_no = 0;
|
||||||
|
scan_number = first_scan_number;
|
||||||
|
|
||||||
|
frame = [];
|
||||||
|
for ii=Ny:-1:1
|
||||||
|
sub_exp_no = 0;
|
||||||
|
for jj=Nx:-1:1
|
||||||
|
if (dir_per_line)
|
||||||
|
vararg_remain = vararg;
|
||||||
|
vararg_remain(3:(end+2)) = vararg_remain;
|
||||||
|
vararg_remain{1} = 'SubExpNo';
|
||||||
|
vararg_remain{2} = sub_exp_no;
|
||||||
|
[filename,vararg_remain] = ...
|
||||||
|
compile_x12sa_filename(scan_number,0,vararg_remain);
|
||||||
|
else
|
||||||
|
[filename,vararg_remain] = ...
|
||||||
|
compile_x12sa_filename(scan_number,point_no,vararg);
|
||||||
|
end
|
||||||
|
last_frame = frame;
|
||||||
|
[frame,vararg_remain] = image_read(filename,vararg_remain);
|
||||||
|
if (isempty(frame.data))
|
||||||
|
fprintf('%s not found, repeating the previous frame\n',filename);
|
||||||
|
frame = last_frame;
|
||||||
|
end
|
||||||
|
if (~isempty(vararg_remain))
|
||||||
|
vararg_remain
|
||||||
|
error('There are unhandled parameters.');
|
||||||
|
end
|
||||||
|
|
||||||
|
if (point_no == 0)
|
||||||
|
trans = zeros(Ny,Nx);
|
||||||
|
dpcx = trans;
|
||||||
|
dpcy = trans;
|
||||||
|
df = trans;
|
||||||
|
|
||||||
|
if ((cen_x <= 0) || (cen_y <= 0))
|
||||||
|
[cx, cy] = find_center(frame.data);
|
||||||
|
fprintf('Beam cemter guess (x,y) = (%d,%d)\n',cx,cy);
|
||||||
|
if (cen_x <= 0)
|
||||||
|
cen_x = cx;
|
||||||
|
end
|
||||||
|
if (cen_y <= 0)
|
||||||
|
cen_y = cy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
roi_x_ind = cen_x + roi_rel_ind;
|
||||||
|
if ((roi_x_ind(1) < 1) || (roi_x_ind(end) > size(frame.data,2)))
|
||||||
|
error('Region of interest out of range in x\n');
|
||||||
|
end
|
||||||
|
roi_y_ind = cen_y + roi_rel_ind;
|
||||||
|
if ((roi_y_ind(1) < 1) || (roi_y_ind(end) > size(frame.data,1)))
|
||||||
|
error('Region of interest out of range in y\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
[yy,xx] = meshgrid(roi_rel_ind,roi_rel_ind);
|
||||||
|
[~, rho] = cart2pol(xx,yy);
|
||||||
|
|
||||||
|
ind_df = find((rho > dark_field_r) & (rho < roi_rel_ind(end)));
|
||||||
|
|
||||||
|
if (~isempty(filename_valid_mask))
|
||||||
|
% in case of less than full detector readout cut out the right part of
|
||||||
|
% the valid pixel mask
|
||||||
|
valid_mask = pilatus_valid_pixel_roi(valid_mask,'RoiSize',size(frame.data));
|
||||||
|
else
|
||||||
|
% if the valid pixel mask is not used specify all pixels to
|
||||||
|
% be valid
|
||||||
|
valid_mask.indices = 1:(size(frame.data,1)*size(frame.data,2));
|
||||||
|
end
|
||||||
|
|
||||||
|
% calculate the indices of the valid and invalid pixels within
|
||||||
|
% the region of interest
|
||||||
|
frame_valid = zeros(size(frame.data));
|
||||||
|
frame_valid(valid_mask.indices) = 1;
|
||||||
|
frame_valid = frame_valid(roi_y_ind,roi_x_ind);
|
||||||
|
ind_invalid = find(frame_valid == 0);
|
||||||
|
% ind_valid = find(frame_valid ~= 0);
|
||||||
|
ind_df = setdiff(ind_df,ind_invalid);
|
||||||
|
end
|
||||||
|
|
||||||
|
% cut out the region of interest
|
||||||
|
frame_roi = frame.data(roi_y_ind,roi_x_ind);
|
||||||
|
frame_roi(ind_invalid) = 0;
|
||||||
|
|
||||||
|
% set central part of detector frame to zero, if specified
|
||||||
|
if (zero_order_r> 0)
|
||||||
|
frame_roi(rho<zero_order_r) = 0; %min(frame_roi(:));
|
||||||
|
end
|
||||||
|
|
||||||
|
% data analysis for the current point
|
||||||
|
if (first_moment)
|
||||||
|
[tr,px,py] = stxm_pt2(frame_roi);
|
||||||
|
else
|
||||||
|
[tr,px,py] = stxm_pt(frame_roi);
|
||||||
|
end
|
||||||
|
trans(ii,jj) = tr;
|
||||||
|
dpcx(ii,jj) = px;
|
||||||
|
dpcy(ii,jj) = py;
|
||||||
|
|
||||||
|
% df(ii,jj) = sum(frame_roi(ind_df)) / sum(sum(frame_roi(ind_valid)));
|
||||||
|
df(ii,jj) = sum(frame_roi(ind_df));
|
||||||
|
|
||||||
|
point_no = point_no +1;
|
||||||
|
sub_exp_no = sub_exp_no +1;
|
||||||
|
end
|
||||||
|
|
||||||
|
% plot linewise each update_interval-th line
|
||||||
|
if (Nx > 1) && (Ny > 1)
|
||||||
|
if ((ii == Ny) || (rem(ii,update_interval) == 1) || (ii == 1))
|
||||||
|
if(gcf ~= fig_no)
|
||||||
|
figure(fig_no);
|
||||||
|
end
|
||||||
|
iv = 2;
|
||||||
|
ih = 2;
|
||||||
|
colormap(bone(256));
|
||||||
|
|
||||||
|
subplot(iv,ih,1);
|
||||||
|
imagesc(trans);
|
||||||
|
axis xy; axis equal; axis tight;
|
||||||
|
colorbar;
|
||||||
|
axis_min = min(min(trans(trans ~= 0)));
|
||||||
|
if (isnan(axis_min))
|
||||||
|
axis_min = 0;
|
||||||
|
end
|
||||||
|
axis_max = max(max(trans(trans ~= 0)));
|
||||||
|
if (isnan(axis_max))
|
||||||
|
axis_max = 0;
|
||||||
|
end
|
||||||
|
caxis([(axis_min-.0001) (axis_max+.0001)]);
|
||||||
|
title_str = [ 'transmission #' num2str(first_scan_number,'%d') ];
|
||||||
|
if (dir_per_line)
|
||||||
|
title_str = [ title_str '-' num2str(first_scan_number+Ny-1,'%d') ]; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
title_str = sprintf('%s (detector %d)',title_str,detector_number);
|
||||||
|
title(title_str);
|
||||||
|
|
||||||
|
subplot(iv,ih,2);
|
||||||
|
imagesc(df);
|
||||||
|
axis xy; axis equal; axis tight;
|
||||||
|
colorbar;
|
||||||
|
axis_min = min(min(df(df ~= 0)));
|
||||||
|
if (isnan(axis_min))
|
||||||
|
axis_min = 0;
|
||||||
|
end
|
||||||
|
axis_max = max(max(df(df~=0)));
|
||||||
|
if (isnan(axis_max))
|
||||||
|
axis_max = 0;
|
||||||
|
end
|
||||||
|
caxis([(axis_min-.0001) (axis_max+.0001)]);
|
||||||
|
title('dark field');
|
||||||
|
|
||||||
|
subplot(iv,ih,3);
|
||||||
|
imagesc(dpcx);
|
||||||
|
axis xy; axis equal; axis tight;
|
||||||
|
colorbar;
|
||||||
|
axis_min = min(min(dpcx(dpcx ~= 0)));
|
||||||
|
if (isnan(axis_min))
|
||||||
|
axis_min = 0;
|
||||||
|
end
|
||||||
|
axis_max = max(max(dpcx(dpcx~=0)));
|
||||||
|
if (isnan(axis_max))
|
||||||
|
axis_max = 0;
|
||||||
|
end
|
||||||
|
caxis([(axis_min-.0001) (axis_max+.0001)]);
|
||||||
|
title('DPC x');
|
||||||
|
|
||||||
|
subplot(iv,ih,4);
|
||||||
|
imagesc(dpcy);
|
||||||
|
axis xy; axis equal; axis tight;
|
||||||
|
colorbar;
|
||||||
|
axis_min = min(min(dpcy(dpcy ~= 0)));
|
||||||
|
if (isnan(axis_min))
|
||||||
|
axis_min = 0;
|
||||||
|
end
|
||||||
|
axis_max = max(max(dpcy(dpcy~=0)));
|
||||||
|
if (isnan(axis_max))
|
||||||
|
axis_max = 0;
|
||||||
|
end
|
||||||
|
caxis([(axis_min-.0001) (axis_max+.0001)]);
|
||||||
|
title('DPC y');
|
||||||
|
|
||||||
|
drawnow;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (dir_per_line)
|
||||||
|
scan_number = scan_number +1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% store return arguments
|
||||||
|
if nargout > 0
|
||||||
|
varargout{1} = trans;
|
||||||
|
end
|
||||||
|
if nargout > 1
|
||||||
|
varargout{2} = dpcx;
|
||||||
|
end
|
||||||
|
if nargout > 2
|
||||||
|
varargout{3} = dpcy;
|
||||||
|
end
|
||||||
|
if nargout > 3
|
||||||
|
varargout{4} = df;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargout > 4
|
||||||
|
varargout{5} = phase;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargout > 5
|
||||||
|
varargout{6} = gx;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargout > 6
|
||||||
|
varargout{7} = gy;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (integrated_phase)
|
||||||
|
% calculate the integrated phase from the differential phase contrast
|
||||||
|
% in horizontal and vertical direction
|
||||||
|
phase = phase_from_dpc(dpcx,dpcy, 'fourier');
|
||||||
|
|
||||||
|
% calculate the 1D differential phase contrast from the integrated
|
||||||
|
% phase
|
||||||
|
[gx, gy] = gradient(phase);
|
||||||
|
|
||||||
|
figure(fig_no +1);
|
||||||
|
iv = 1;
|
||||||
|
ih = 3;
|
||||||
|
colormap(bone(256));
|
||||||
|
|
||||||
|
subplot(iv,ih,1);
|
||||||
|
imagesc(phase);
|
||||||
|
axis xy; axis equal; axis tight;
|
||||||
|
colorbar;
|
||||||
|
axis_min = min(phase(phase ~= 0));
|
||||||
|
if (isnan(axis_min))
|
||||||
|
axis_min = 0;
|
||||||
|
end
|
||||||
|
axis_max = max(phase(phase~=0));
|
||||||
|
if (isnan(axis_max))
|
||||||
|
axis_max = 0;
|
||||||
|
end
|
||||||
|
caxis([(axis_min-.0001) (axis_max+.0001)]);
|
||||||
|
title_str = [ 'integrated phase #' num2str(first_scan_number,'%d') ];
|
||||||
|
if (dir_per_line)
|
||||||
|
title_str = [ title_str '-' num2str(first_scan_number+Ny-1,'%d') ];
|
||||||
|
end
|
||||||
|
title_str = sprintf('%s (detector %d)',title_str,detector_number);
|
||||||
|
title(title_str);
|
||||||
|
|
||||||
|
subplot(iv,ih,2);
|
||||||
|
imagesc(gx);
|
||||||
|
axis xy; axis equal; axis tight;
|
||||||
|
colorbar;
|
||||||
|
axis_min = min(gx(gx ~= 0));
|
||||||
|
if (isnan(axis_min))
|
||||||
|
axis_min = 0;
|
||||||
|
end
|
||||||
|
axis_max = max(gx(gx ~= 0));
|
||||||
|
if (isnan(axis_max))
|
||||||
|
axis_max = 0;
|
||||||
|
end
|
||||||
|
caxis([(axis_min-.0001) (axis_max+.0001)]);
|
||||||
|
title('DPC x from integrated phase');
|
||||||
|
|
||||||
|
subplot(iv,ih,3);
|
||||||
|
imagesc(gy);
|
||||||
|
axis xy; axis equal; axis tight;
|
||||||
|
colorbar;
|
||||||
|
axis_min = min(gy(gy ~= 0));
|
||||||
|
if (isnan(axis_min))
|
||||||
|
axis_min = 0;
|
||||||
|
end
|
||||||
|
axis_max = max(gy(gy ~= 0));
|
||||||
|
if (isnan(axis_max))
|
||||||
|
axis_max = 0;
|
||||||
|
end
|
||||||
|
caxis([(axis_min-.0001) (axis_max+.0001)]);
|
||||||
|
title('DPC y from integrated phase');
|
||||||
|
|
||||||
|
drawnow;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% file name for saving
|
||||||
|
filename = sprintf('stxm_scans_%d_%05d-%05d',detector_number,...
|
||||||
|
first_scan_number,first_scan_number+Ny-1);
|
||||||
|
|
||||||
|
|
||||||
|
% save figures
|
||||||
|
if (~isempty(figure_dir))
|
||||||
|
figure(fig_no);
|
||||||
|
|
||||||
|
% create output directories and write the plot in different formats
|
||||||
|
if (~exist(figure_dir,'dir'))
|
||||||
|
mkdir(figure_dir)
|
||||||
|
end
|
||||||
|
if ((figure_dir(end) ~= '/') && (figure_dir(end) ~= '\'))
|
||||||
|
figure_dir = [ figure_dir '/' ];
|
||||||
|
end
|
||||||
|
fprintf('output directory for figures is %s\n',figure_dir);
|
||||||
|
|
||||||
|
% resize to a smaller width as print layout
|
||||||
|
set(gcf,'Position',print_a4_position_standard);
|
||||||
|
|
||||||
|
subdir = [ figure_dir 'jpg/' ];
|
||||||
|
if (~exist(subdir,'dir'))
|
||||||
|
mkdir(subdir);
|
||||||
|
end
|
||||||
|
fprintf('saving %s.jpg\n',filename);
|
||||||
|
print('-djpeg','-r300',[subdir filename '.jpg'] );
|
||||||
|
|
||||||
|
subdir = [ figure_dir 'eps/' ];
|
||||||
|
if (~exist(subdir,'dir'))
|
||||||
|
mkdir(subdir);
|
||||||
|
end
|
||||||
|
fprintf('saving %s.eps\n',filename);
|
||||||
|
print('-depsc','-r1200',[subdir filename '.eps'] );
|
||||||
|
|
||||||
|
% resize to full screen
|
||||||
|
set(gcf,'Position',full_screen_position_standard);
|
||||||
|
|
||||||
|
subdir = [ figure_dir 'fig/' ];
|
||||||
|
if (~exist(subdir,'dir'))
|
||||||
|
mkdir(subdir);
|
||||||
|
end
|
||||||
|
fprintf('saving %s.fig\n',filename);
|
||||||
|
hgsave([subdir filename '.fig']);
|
||||||
|
|
||||||
|
if (integrated_phase)
|
||||||
|
figure(fig_no +1);
|
||||||
|
|
||||||
|
subdir = [ figure_dir 'jpg/' ];
|
||||||
|
if (~exist(subdir,'dir'))
|
||||||
|
mkdir(subdir);
|
||||||
|
end
|
||||||
|
|
||||||
|
% resize to a smaller width as print layout
|
||||||
|
set(gcf,'Position',print_a4_position_integrated_phase);
|
||||||
|
|
||||||
|
fprintf('saving %s_integrated_phase.jpg\n',filename);
|
||||||
|
print('-djpeg','-r300',[subdir filename '_integrated_phase.jpg'] );
|
||||||
|
|
||||||
|
subdir = [ figure_dir 'eps/' ];
|
||||||
|
if (~exist(subdir,'dir'))
|
||||||
|
mkdir(subdir);
|
||||||
|
end
|
||||||
|
fprintf('saving %s_integrated_phase.eps\n',filename);
|
||||||
|
print('-depsc','-r1200',[subdir filename '_integrated_phase.eps'] );
|
||||||
|
|
||||||
|
% resize to a smaller width as print layout
|
||||||
|
set(gcf,'Position',full_screen_position_integrated_phase);
|
||||||
|
|
||||||
|
subdir = [ figure_dir 'fig/' ];
|
||||||
|
if (~exist(subdir,'dir'))
|
||||||
|
mkdir(subdir);
|
||||||
|
end
|
||||||
|
fprintf('saving %s_integrated_phase.fig\n',filename);
|
||||||
|
hgsave([subdir filename '_integrated_phase.fig']);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% save resulting data
|
||||||
|
if (~isempty(data_dir))
|
||||||
|
if ((data_dir(end) ~= '/') && (data_dir(end) ~= '\'))
|
||||||
|
data_dir = [ data_dir '/' ];
|
||||||
|
end
|
||||||
|
|
||||||
|
% create output directory
|
||||||
|
if (~exist(data_dir,'dir'))
|
||||||
|
mkdir(data_dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
% save data
|
||||||
|
fprintf('saving %s.mat\n',[data_dir filename]);
|
||||||
|
if (integrated_phase)
|
||||||
|
save([data_dir filename],'trans','dpcx','dpcy','df', 'phase', 'gx', 'gy');
|
||||||
|
else
|
||||||
|
save([data_dir filename],'trans','dpcx','dpcy','df');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [cx, cy] = find_center(f)
|
||||||
|
|
||||||
|
f = medfilt2(f,[5 5]);
|
||||||
|
|
||||||
|
[~, cx] = max(sum(f,1));
|
||||||
|
[~, cy] = max(sum(f,2));
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [tr, px, py] = stxm_pt(a)
|
||||||
|
|
||||||
|
persistent c1 c2 s1 s2 sz
|
||||||
|
|
||||||
|
if (isempty(sz)) || (any(sz ~= size(a)))
|
||||||
|
sz = size(a);
|
||||||
|
c1 = -cos(2*pi*(0:sz(1)-1)/sz(1));
|
||||||
|
s1 = sin(2*pi*(0:sz(1)-1)/sz(1));
|
||||||
|
c2 = -cos(2*pi*(0:sz(2)-1)/sz(2));
|
||||||
|
s2 = sin(2*pi*(0:sz(2)-1)/sz(2));
|
||||||
|
end
|
||||||
|
|
||||||
|
a1 = sum(a,1);
|
||||||
|
a2 = sum(a,2)';
|
||||||
|
|
||||||
|
tr = sum(a1);
|
||||||
|
px = atan2(sum(a1.*c1), sum(a1.*s1));
|
||||||
|
py = atan2(sum(a2.*c2), sum(a2.*s2));
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [tr, px, py ] = stxm_pt2(a)
|
||||||
|
|
||||||
|
persistent x y sz
|
||||||
|
|
||||||
|
if (isempty(sz)) || (any(sz ~= size(a)))
|
||||||
|
sz = size(a);
|
||||||
|
% masking out the invalid pixels is done by setting the
|
||||||
|
% corresponding intensities to zero before calling this function
|
||||||
|
[y,x] = ndgrid((0:sz(1)-1)-sz(1)/2, (0:sz(1)-1)-sz(1)/2);
|
||||||
|
% x2 = x.^2;
|
||||||
|
end
|
||||||
|
|
||||||
|
tr = sum(sum(a));
|
||||||
|
px = sum(sum(a.*x))/tr;
|
||||||
|
py = sum(sum(a.*y))/tr;
|
||||||
|
% p2 = (sum(a1.*x2)/tr + sum(a2.*x2)/tr - px^2 - py^2);
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function p = phase_from_dpc(dpcx,dpcy,varargin)
|
||||||
|
%
|
||||||
|
% Integrates the phase from a combination of x and y gradients.
|
||||||
|
% phase_from_dpc(dpcx,dpcy,'fourier') uses the Fourier method (default),
|
||||||
|
% phase_from_dpc(dpcx,dpcy,'finitdiff') uses a finite difference method.
|
||||||
|
|
||||||
|
if nargin > 2
|
||||||
|
method = varargin{1};
|
||||||
|
else
|
||||||
|
%method = 'fourier';
|
||||||
|
method = 'finitediff';
|
||||||
|
end
|
||||||
|
|
||||||
|
px = -dpcy;
|
||||||
|
py = -dpcx;
|
||||||
|
|
||||||
|
sz = size(px);
|
||||||
|
|
||||||
|
switch lower(method)
|
||||||
|
case 'fourier'
|
||||||
|
f = zeros(2*sz);
|
||||||
|
f(1:sz(1),1:sz(2)) = px + 1i*py;
|
||||||
|
f(1:sz(1),sz(2)+1:end) = fliplr(px + 1i*py);
|
||||||
|
f(sz(1)+1:end,1:sz(2)) = flipud(px + 1i*py);
|
||||||
|
f(sz(1)+1:end,sz(2)+1:end) = rot90(px + 1i*py,2);
|
||||||
|
[x1,x2] = ndgrid(-sz(1):(sz(1)-1),-sz(2):(sz(2)-1));
|
||||||
|
q1 = pi*fftshift(x1)/sz(1);
|
||||||
|
q2 = pi*fftshift(x2)/sz(2);
|
||||||
|
qc = q2 - 1i*q1;
|
||||||
|
inv_qc = 1./qc;
|
||||||
|
inv_qc(1,1) = 0;
|
||||||
|
nf = ifftn(fftn(f).*inv_qc);
|
||||||
|
p = real(nf(1:sz(1),1:sz(2)));
|
||||||
|
case 'finitediff'
|
||||||
|
ggx = pgradient(dpcx);
|
||||||
|
[~, ggy] = pgradient(dpcy);
|
||||||
|
f = .25*(ggx + ggy);
|
||||||
|
ta = zeros(sz);
|
||||||
|
for i = 1:10000
|
||||||
|
ta = ta + (pdel2(ta) - f);
|
||||||
|
|
||||||
|
% Zero boundary conditions
|
||||||
|
%ta(1,:) = 0;
|
||||||
|
%ta(:,1) = 0;
|
||||||
|
%ta(end,:) = 0;
|
||||||
|
%ta(:,end) = 0;
|
||||||
|
|
||||||
|
% Zero normal gradient boundary condition
|
||||||
|
ta(1,:) = ta(2,:);
|
||||||
|
ta(:,1) = ta(:,2);
|
||||||
|
ta(end,:) = ta(end-1,:);
|
||||||
|
ta(:,end) = ta(:,end-1);
|
||||||
|
|
||||||
|
if mod(i,1000)==0
|
||||||
|
figure(1); imagesc(real(ta)); colormap(bone(256)); colorbar; drawnow;
|
||||||
|
end
|
||||||
|
|
||||||
|
p = ta;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import beamline.stxm_online
|
||||||
|
|
||||||
|
first_scan_nr = 15;
|
||||||
|
nr_lines = 21;
|
||||||
|
centerx = 224;
|
||||||
|
centery = 98;
|
||||||
|
dark_field_radius = 20;
|
||||||
|
roi = 128;
|
||||||
|
|
||||||
|
[trans,dpcx,dpcy,df]=stxm_online(first_scan_nr, nr_lines , 'ROIdim',roi,'CenX', centerx, 'CenY', centery, 'DarkFieldR', dark_field_radius,'FilenameValidMask',[]);
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
first_scan_nr = 2175;
|
||||||
|
Nx=21;
|
||||||
|
nr_lines = 19;
|
||||||
|
centerx = 224;
|
||||||
|
centery = 98;
|
||||||
|
dark_field_radius = 20;
|
||||||
|
roi = 128;
|
||||||
|
|
||||||
|
[trans,dpcx,dpcy,df]=stxm_online(first_scan_nr, nr_lines , 'Nx',Nx,'ROIdim',roi,'CenX', centerx, 'CenY', centery, 'DarkFieldR', dark_field_radius,'FilenameValidMask',[],'DirPerLine',0);
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
@@ -0,0 +1,414 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: tune_valid_mask.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.5 $ $Date: 2012/09/02 15:13:40 $
|
||||||
|
% $Author: bunk $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% remove outlyers of intensity that deviates from the azimuthal integration
|
||||||
|
% from the valid pixel mask
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% May 21st 2010, Oliver Bunk:
|
||||||
|
% 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [valid_mask] = tune_valid_mask(data_dir, varargin)
|
||||||
|
import beamline.radial_integ
|
||||||
|
import io.image_read
|
||||||
|
import plotting.display_valid_mask
|
||||||
|
import utils.find_files
|
||||||
|
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
% directory with the integrated data files
|
||||||
|
indir_integ_data = '~/Data10/analysis/radial_integration/';
|
||||||
|
% filename of the integrated data, empty to determine it from the raw data
|
||||||
|
% file name
|
||||||
|
filename_integ_data = [];
|
||||||
|
% use all cbf files
|
||||||
|
filename_mask = '*.cbf';
|
||||||
|
% filename for loading and saving the valid pixel mask
|
||||||
|
filename_valid_mask = '~/Data10/analysis/data/pilatus_valid_mask.mat';
|
||||||
|
% integration masks
|
||||||
|
filename_integ_masks = '~/Data10/analysis/data/pilatus_integration_masks.mat';
|
||||||
|
|
||||||
|
% size of the median filter that is use to smooth the data for identifying
|
||||||
|
% outlyers
|
||||||
|
median_size = 11;
|
||||||
|
% first pixel to start at
|
||||||
|
radius_from = 20;
|
||||||
|
% last pixel to check
|
||||||
|
radius_to = 0;
|
||||||
|
% only intensities above this threshold are considered for being hot
|
||||||
|
threshold_hot = 5;
|
||||||
|
% this value times the standard deviation of the intensity is used as hot pixel
|
||||||
|
% threshold
|
||||||
|
threshold_median = 3.0;
|
||||||
|
% save the updated mask
|
||||||
|
save_data = 0;
|
||||||
|
% display result in this figure
|
||||||
|
fig_no = 201;
|
||||||
|
% matching files to use
|
||||||
|
point_range = [];
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
fprintf('\nUsage:\n');
|
||||||
|
fprintf('[valid_mask]=%s(data_dir [[,<name>,<value>]...]);\n',mfilename);
|
||||||
|
fprintf('Remove outlyers from the valid pixel mask by comparing azimuthally integrated data\n');
|
||||||
|
fprintf('against the same data median filtered and rejecting pixels with a deviation\n');
|
||||||
|
fprintf('in intensity specified in multiples of the standard deviation.\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
fprintf('''FilenameMask'',<file specifier> specify the files to be used from the data directory, empty string for all, default is ''%s''\n',...
|
||||||
|
filename_mask);
|
||||||
|
fprintf('''PointRange'',<vector or []> matching files to use, default is [] for all files\n');
|
||||||
|
fprintf('''IndirIntegData'',<filename.mat> directory with the azimuthally integrated data, default is %s\n',...
|
||||||
|
indir_integ_data);
|
||||||
|
fprintf('''FilenameIntegData'',<filename.mat> filename for the azimuthally integrated data, empty to determine the name\n');
|
||||||
|
fprintf(' from the first raw data file name, default is ''%s''\n',...
|
||||||
|
filename_integ_data);
|
||||||
|
fprintf('''FilenameIntegMasks'',<filename> Matlab file containing the integration masks, default is ''%s''\n',filename_integ_masks);
|
||||||
|
fprintf('''RadiusFrom'',<integer> no. of the pixel to start with, default is %.0f\n',radius_from);
|
||||||
|
fprintf('''RadiusTo'',<integer> no. of the last pixel to check, default is %.0f\n',radius_to);
|
||||||
|
fprintf('''MedianSize'',<integer> size of the median filter in pixels, default is %.0f\n',...
|
||||||
|
median_size);
|
||||||
|
fprintf('''ThresholdHot'',<float> pixels above this value are considered for being hot, default is %d\n',...
|
||||||
|
threshold_hot);
|
||||||
|
fprintf('''ThresholdMedian'',<float> pixels outside the range (I+/-threshold_median*sqrt(I))\n');
|
||||||
|
fprintf(' of the median filtered data are considered to be hot,\n');
|
||||||
|
fprintf(' default is %.1f\n',...
|
||||||
|
threshold_median);
|
||||||
|
fprintf('''SaveData'',<0-no,1-yes> save the valid pixel mask, default is %d\n',save_data);
|
||||||
|
fprintf('''FilenameValidMask'',<path and filename> Matlab file with the valid pixel indices,\n');
|
||||||
|
fprintf(' default is %s\n',filename_valid_mask);
|
||||||
|
fprintf('''FigNo'',<integer> number of the figure in which the result is displayed, default is %d\n',...
|
||||||
|
fig_no);
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('Examples:\n');
|
||||||
|
fprintf('[valid_mask]=%s(''~/Data10/pilatus/S05000-05999/S05715/e12612_1_05715_00000_00000.cbf'');\n',...
|
||||||
|
mfilename);
|
||||||
|
fprintf('[valid_mask]=%s(''~/Data10/pilatus/S05000-05999/S05715/*.cbf'');\n',...
|
||||||
|
mfilename);
|
||||||
|
|
||||||
|
error('At least the filename of the raw data has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = no_of_in_arg -1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments:
|
||||||
|
% initialize the list of unhandled parameters
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'FilenameIntegMasks'
|
||||||
|
filename_integ_masks = value;
|
||||||
|
case 'FilenameMask'
|
||||||
|
filename_mask = value;
|
||||||
|
case 'PointRange'
|
||||||
|
point_range = value;
|
||||||
|
case 'IndirIntegData'
|
||||||
|
indir_integ_data = value;
|
||||||
|
case 'FilenameIntegData'
|
||||||
|
filename_integ_data = value;
|
||||||
|
case 'RadiusFrom',
|
||||||
|
radius_from = round(value);
|
||||||
|
case 'RadiusTo',
|
||||||
|
radius_to = round(value);
|
||||||
|
case 'MedianSize'
|
||||||
|
median_size = round(value);
|
||||||
|
case 'ThresholdMedian'
|
||||||
|
threshold_median = value;
|
||||||
|
case 'ThresholdHot'
|
||||||
|
threshold_hot = value;
|
||||||
|
case 'FilenameValidMask'
|
||||||
|
filename_valid_mask = value;
|
||||||
|
case 'SaveData'
|
||||||
|
save_data = value;
|
||||||
|
case 'FigNo'
|
||||||
|
fig_no = value;
|
||||||
|
otherwise
|
||||||
|
vararg_remain{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg_remain{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vararg_remain{end+1} = 'UnhandledParError';
|
||||||
|
vararg_remain{end+1} = 0;
|
||||||
|
vararg_remain{end+1} = 'DisplayFilename';
|
||||||
|
vararg_remain{end+1} = 0;
|
||||||
|
|
||||||
|
% set some default values for the plot window
|
||||||
|
set(0, 'DefaultAxesfontsize', 12);
|
||||||
|
set(0, 'DefaultAxeslinewidth', 1, 'DefaultAxesfontsize', 12);
|
||||||
|
set(0, 'DefaultLinelinewidth', 1);
|
||||||
|
|
||||||
|
% get all matching filenames
|
||||||
|
if (data_dir(end) ~= '/')
|
||||||
|
data_dir(end+1) = '/';
|
||||||
|
end
|
||||||
|
[data_dir,fnames,vararg_remain] = ...
|
||||||
|
find_files( [ data_dir filename_mask ], vararg_remain );
|
||||||
|
|
||||||
|
if (length(fnames) < 1)
|
||||||
|
error('No matching files found for %s%s.\n',data_dir,filename_mask);
|
||||||
|
end
|
||||||
|
|
||||||
|
% load the current valid pixel mask in variable valid_mask
|
||||||
|
fprintf('loading the existing valid mask %s\n',filename_valid_mask);
|
||||||
|
load(filename_valid_mask);
|
||||||
|
framesize = valid_mask.framesize(1) * valid_mask.framesize(2);
|
||||||
|
|
||||||
|
% load the integration masks in variable integ_masks
|
||||||
|
fprintf('Loading the integration masks from %s\n',filename_integ_masks);
|
||||||
|
load(filename_integ_masks);
|
||||||
|
no_of_radii = length(integ_masks.radius);
|
||||||
|
|
||||||
|
if ((radius_to < radius_from) || (radius_to > no_of_radii))
|
||||||
|
radius_to = no_of_radii;
|
||||||
|
end
|
||||||
|
|
||||||
|
% process the frames
|
||||||
|
ind_hot = [];
|
||||||
|
ind_dark = [];
|
||||||
|
integ_data = [];
|
||||||
|
fprintf('data directory is %s\n',data_dir);
|
||||||
|
if (isempty(point_range))
|
||||||
|
point_range = 1:length(fnames);
|
||||||
|
else
|
||||||
|
ind = find(point_range <= length(fnames));
|
||||||
|
if (length(point_range) ~= length(ind))
|
||||||
|
fprintf('Warning, %d value(s) from the specified point range are out of the range [1,%.0f] and not used.\n',...
|
||||||
|
length(point_range)-length(ind),length(fnames));
|
||||||
|
point_range = point_range(ind);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for (point_ind=1:length(point_range))
|
||||||
|
f_ind = point_range(point_ind);
|
||||||
|
% read the raw data
|
||||||
|
fprintf('%3d/%3d: reading %s%s\n',f_ind,length(point_range),...
|
||||||
|
data_dir,fnames(f_ind).name);
|
||||||
|
filename_raw = [data_dir fnames(f_ind).name ];
|
||||||
|
[frame] = image_read(filename_raw,vararg_remain);
|
||||||
|
|
||||||
|
% check that the files have identical dimensions
|
||||||
|
if ((size(frame.data,1) ~= valid_mask.framesize(1)) || ...
|
||||||
|
(size(frame.data,2) ~= valid_mask.framesize(2)))
|
||||||
|
error('The valid pixel mask has %d x %d pixels, this frame has %d x %d pixels',...
|
||||||
|
valid_mask.framesize(1),valid_mask.framesize(2),...
|
||||||
|
size(frame.data,1),size(frame.data,2));
|
||||||
|
end
|
||||||
|
|
||||||
|
% read the radially integrated data
|
||||||
|
if (isempty(integ_data))
|
||||||
|
% determine filename for the integrated data from the first raw
|
||||||
|
% data filename
|
||||||
|
if (isempty(filename_integ_data))
|
||||||
|
[pathstr, filename_integ_data] = fileparts(fnames(f_ind).name);
|
||||||
|
filename_integ_data = [ filename_integ_data '_integ.mat' ]; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
filename_integ_data = fullfile(indir_integ_data,filename_integ_data);
|
||||||
|
fprintf('Loading the integrated intensities from %s\n',...
|
||||||
|
filename_integ_data);
|
||||||
|
integ_data = load(filename_integ_data);
|
||||||
|
|
||||||
|
% take the median of all segments with positive intensities, i.e.,
|
||||||
|
% skip negative intensities
|
||||||
|
I_all_prev = integ_data.I_all;
|
||||||
|
no_of_segments = size(I_all_prev,2);
|
||||||
|
no_of_points = size(I_all_prev,3);
|
||||||
|
I_all = zeros(no_of_radii,no_of_points);
|
||||||
|
I_std = zeros(no_of_radii,no_of_points);
|
||||||
|
if (no_of_segments > 1)
|
||||||
|
fprintf('Using the median of %d segments.\n',no_of_segments);
|
||||||
|
end
|
||||||
|
for (ind1=1:no_of_radii)
|
||||||
|
for (ind3=1:no_of_points)
|
||||||
|
no_of_el = 0;
|
||||||
|
I_use = zeros(1,no_of_segments);
|
||||||
|
ind_I_use = zeros(1,no_of_segments);
|
||||||
|
for (ind2=1:no_of_segments)
|
||||||
|
if (I_all_prev(ind1,ind2,ind3) >= 0)
|
||||||
|
no_of_el = no_of_el +1;
|
||||||
|
I_use(no_of_el) = I_all_prev(ind1,ind2,ind3);
|
||||||
|
ind_I_use(no_of_el) = ind2;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (no_of_el > 1)
|
||||||
|
[I_sorted,ind_sorted] = sort(I_use(1:no_of_el));
|
||||||
|
ind_median = round(0.5*no_of_el);
|
||||||
|
I_all(ind1,ind3) = I_sorted(ind_median);
|
||||||
|
% get the standard deviation of this intensity
|
||||||
|
I_std(ind1,ind3) = integ_data.I_std(ind1,ind_I_use(ind_sorted(ind_median)),ind3);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% print this information once rather than for each file
|
||||||
|
fprintf('Checking radii from %d to %d.\n',radius_from,radius_to);
|
||||||
|
end
|
||||||
|
|
||||||
|
% get the index to the integrated data
|
||||||
|
ind = 1;
|
||||||
|
ind_max = length(integ_data.filenames_all);
|
||||||
|
while ((ind <= ind_max) && ...
|
||||||
|
(isempty(strfind(integ_data.filenames_all{ind},fnames(f_ind).name))))
|
||||||
|
ind = ind +1;
|
||||||
|
end
|
||||||
|
if (ind > ind_max)
|
||||||
|
error('Could not find integrated data for raw data file %s in %s.',...
|
||||||
|
filename_raw,filename_integ_data);
|
||||||
|
end
|
||||||
|
data_integ = squeeze(I_all(:,ind));
|
||||||
|
data_integ_std = squeeze(I_std(:,ind));
|
||||||
|
|
||||||
|
% median filtered data for comparison
|
||||||
|
data_integ_med = medfilt1(data_integ,median_size,size(data_integ,1),1);
|
||||||
|
|
||||||
|
% figure(fig_no+2);
|
||||||
|
% hold off;
|
||||||
|
% clf;
|
||||||
|
% semilogy(data_integ);
|
||||||
|
% hold all;
|
||||||
|
% semilogy(data_integ_med);
|
||||||
|
% semilogy(data_integ_med+data_integ_std*threshold_median);
|
||||||
|
% semilogy(data_integ_med-data_integ_std*threshold_median);
|
||||||
|
|
||||||
|
frame_cmp = ones(valid_mask.framesize) -2;
|
||||||
|
frame_cmp_std = zeros(valid_mask.framesize);
|
||||||
|
for (ind_r = radius_from:radius_to)
|
||||||
|
for (ind_seg = 1:no_of_segments)
|
||||||
|
if (integ_masks.norm_sum(ind_r,ind_seg) > 0)
|
||||||
|
frame_cmp(integ_masks.indices{ind_r,ind_seg}) = ...
|
||||||
|
data_integ_med(ind_r);
|
||||||
|
frame_cmp_std(integ_masks.indices{ind_r,ind_seg}) = ...
|
||||||
|
data_integ_std(ind_r);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%
|
||||||
|
ind_dark = union(ind_dark, ...
|
||||||
|
find((frame.data >= 0) & ...
|
||||||
|
(frame_cmp >= 0) & ...
|
||||||
|
(frame.data < frame_cmp - threshold_median*frame_cmp_std)));
|
||||||
|
% only consider pixels of sufficient intensity for being hot
|
||||||
|
ind_hot = union(ind_hot, ...
|
||||||
|
find((frame.data > threshold_hot) & ...
|
||||||
|
(frame_cmp >= 0) & ...
|
||||||
|
(frame.data > frame_cmp + threshold_median*frame_cmp_std)));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% calculate the complementary masks of the valid pixels
|
||||||
|
valid_mask.indices = intersect(valid_mask.indices,...
|
||||||
|
setdiff(1:framesize,union(ind_dark,ind_hot)));
|
||||||
|
|
||||||
|
fprintf('In total %d dark and %d hot pixels found.\n',...
|
||||||
|
length(ind_dark),length(ind_hot));
|
||||||
|
fprintf('%d valid pixels remain.\n',length(valid_mask.indices));
|
||||||
|
|
||||||
|
|
||||||
|
if (save_data)
|
||||||
|
% create a backup of the mask
|
||||||
|
if (exist(filename_valid_mask,'file'))
|
||||||
|
filename_mask_backup = [ filename_valid_mask '.bak' ];
|
||||||
|
fprintf('Copying the current mask %s to %s\n',filename_valid_mask,...
|
||||||
|
filename_mask_backup);
|
||||||
|
copyfile(filename_valid_mask,filename_mask_backup);
|
||||||
|
end
|
||||||
|
|
||||||
|
% save the masks
|
||||||
|
fprintf('Saving valid_mask to %s\n',filename_valid_mask);
|
||||||
|
save(filename_valid_mask,'valid_mask');
|
||||||
|
% plot new valid pixel mask
|
||||||
|
display_valid_mask('FilenameValidMask',filename_valid_mask,...
|
||||||
|
'NoHelp',1,'FigNo',fig_no);
|
||||||
|
else
|
||||||
|
fprintf('The updated valid pixel mask is NOT saved.\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
% plot the additional invalid pixels
|
||||||
|
figure(fig_no+1);
|
||||||
|
|
||||||
|
% mark the valid pixels as 1, leave the invalid at 0
|
||||||
|
frame = zeros(valid_mask.framesize);
|
||||||
|
frame(valid_mask.indices) = 1;
|
||||||
|
frame(ind_dark) = -10;
|
||||||
|
frame(ind_hot) = 10;
|
||||||
|
imagesc(frame);
|
||||||
|
caxis([-10 10]);
|
||||||
|
axis xy;
|
||||||
|
axis equal;
|
||||||
|
axis tight;
|
||||||
|
colorbar;
|
||||||
|
title_str = ['valid pixels, ' ...
|
||||||
|
num2str(length(ind_dark)+length(ind_hot),'%d') ...
|
||||||
|
' update(s) marked with intensity -10/10'];
|
||||||
|
title(title_str);
|
||||||
|
set(gcf,'Name','valid pixels, updates marked');
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
%% UDPATE_MASK
|
||||||
|
% This small script guides you to update an alread existing mask for
|
||||||
|
% ptychography. The main tool for creating a new mask is
|
||||||
|
% beamline.create_mask, a GUI that lets you select bad/hot pixels.
|
||||||
|
% UPDATE_MASK loads the data, specified by file_path, plots it and starts
|
||||||
|
% the GUI. Although you can create a 3D mask, i.e. a mask which varies from
|
||||||
|
% frame to frame, a 2D mask is sufficient for most datasets.
|
||||||
|
|
||||||
|
% You can load an already existing mask within the GUI.
|
||||||
|
|
||||||
|
close all
|
||||||
|
|
||||||
|
|
||||||
|
file_path = '~/Data10/eiger_4/S00000-00999/S00089/run_00089_000000000000.h5';
|
||||||
|
single_file = true; % if you have multiple files use * in file_path
|
||||||
|
H5Location = '/entry/data/eiger_4/'; % check the location within the h5 file in ptycho/+detector
|
||||||
|
orientation = [1 0 0]; % check the detector orientation in ptycho/+detector
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% load the data
|
||||||
|
|
||||||
|
image_read_args = [];
|
||||||
|
|
||||||
|
image_read_args{1} = 'Orientation';
|
||||||
|
image_read_args{2} = orientation;
|
||||||
|
image_read_args{3} = 'OrientByExtension';
|
||||||
|
image_read_args{4} = false;
|
||||||
|
|
||||||
|
if ~single_file
|
||||||
|
image_read_args{end+1} = 'IsFmask';
|
||||||
|
image_read_args{end+1} = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isempty(H5Location)
|
||||||
|
image_read_args{end+1} = 'H5Location';
|
||||||
|
image_read_args{end+1} = H5Location;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
data = io.image_read(file_path, image_read_args(:));
|
||||||
|
|
||||||
|
%% plot the data
|
||||||
|
figure(1),
|
||||||
|
plotting.imagesc3D(abs(log10(double(data.data)+1)));
|
||||||
|
colorbar
|
||||||
|
axis xy equal tight
|
||||||
|
colorbar
|
||||||
|
title('Detector raw data')
|
||||||
|
colormap jet
|
||||||
|
|
||||||
|
%% iterative step for a mask update (add dead pixels to the current mask)
|
||||||
|
mask = beamline.create_mask;
|
||||||
|
|
||||||
|
%% check it again
|
||||||
|
figure (2),
|
||||||
|
imagesc(mask); axis equal tight xy
|
||||||
|
title('Final mask')
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2018 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/* cbf_uncompress.c:
|
||||||
|
|
||||||
|
Compilation from Matlab:
|
||||||
|
mex cbf_uncompress.c
|
||||||
|
maybe a tiny bit faster code is generated by
|
||||||
|
mex -O COPTIMFLAGS='-O2' LDOPTIMFLAGS='-O2' cbf_uncompress.c
|
||||||
|
|
||||||
|
Usage from Matlab:
|
||||||
|
[frame] = ...
|
||||||
|
cbf_uncompress(dat_in,dim1,dim2,no_of_in_bytes,compression_type);
|
||||||
|
|
||||||
|
history:
|
||||||
|
April 24th 2008:
|
||||||
|
1st version based on code snippet from Eric Eikenberry
|
||||||
|
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
| |
|
||||||
|
| Except where otherwise noted, this work is licensed under a |
|
||||||
|
| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
| |
|
||||||
|
| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
| |
|
||||||
|
| Author: CXS group, PSI |
|
||||||
|
*-----------------------------------------------------------------------*
|
||||||
|
You may use this code with the following provisions:
|
||||||
|
|
||||||
|
If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
computing language this notice should be included in the redistribution.
|
||||||
|
|
||||||
|
If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
publication or if it is fully or partially rewritten for another
|
||||||
|
computing language the authors and institution should be acknowledged
|
||||||
|
in written form in the publication: “Data processing was carried out
|
||||||
|
using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
Paul Scherrer Institut, Switzerland.”
|
||||||
|
Variations on the latter text can be incorporated upon discussion with
|
||||||
|
the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
for the published work.
|
||||||
|
|
||||||
|
A publication that focuses on describing features, or parameters, that
|
||||||
|
are already existing in the code should be first discussed with the
|
||||||
|
authors.
|
||||||
|
|
||||||
|
This code and subroutines are part of a continuous development, they
|
||||||
|
are provided “as they are” without guarantees or liability on part
|
||||||
|
of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
proper use and the correctness of the results.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mex.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void mexFunction(int nlhs, mxArray *plhs[],
|
||||||
|
int nrhs, const mxArray *prhs[])
|
||||||
|
{
|
||||||
|
const mxArray *curr_arg;
|
||||||
|
union {
|
||||||
|
unsigned char *uint8;
|
||||||
|
char *int8;
|
||||||
|
unsigned short *uint16;
|
||||||
|
short *int16;
|
||||||
|
unsigned int *uint32;
|
||||||
|
int *int32;
|
||||||
|
} data_in,data_in_start;
|
||||||
|
|
||||||
|
int dim1, dim2, no_of_in_bytes, compression_type;
|
||||||
|
int diff, val_curr;
|
||||||
|
double *frame_out, *frame_out_start;
|
||||||
|
|
||||||
|
/* initialize return argument*/
|
||||||
|
plhs[0] = NULL;
|
||||||
|
|
||||||
|
/* Check for proper number of arguments. */
|
||||||
|
if (nrhs != 5)
|
||||||
|
mexErrMsgTxt("Five input arguments required: dat_in,dim1,dim2,no_of_in_bytes,compression_type.");
|
||||||
|
else if (nlhs != 1)
|
||||||
|
mexErrMsgTxt("One output argument has to be specified.");
|
||||||
|
|
||||||
|
{
|
||||||
|
int ind;
|
||||||
|
for (ind = 0; ind < nrhs; ind++) {
|
||||||
|
if(mxGetNumberOfDimensions(prhs[ind]) != 2) {
|
||||||
|
printf("The %d. input argument must have two dimensions.",ind+1);
|
||||||
|
mexErrMsgTxt("wrong number of dimensions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check 1st input argument: input data */
|
||||||
|
curr_arg = prhs[0];
|
||||||
|
if (mxIsUint8(curr_arg) != 1)
|
||||||
|
mexErrMsgTxt("Input 1 (input data) must be of type uint8.");
|
||||||
|
data_in_start.uint8 = data_in.uint8 = (char *) mxGetPr(curr_arg);
|
||||||
|
|
||||||
|
/* check 2nd input argument: dim1 */
|
||||||
|
curr_arg = prhs[1];
|
||||||
|
if (mxIsDouble(curr_arg) != 1)
|
||||||
|
mexErrMsgTxt("Input 2 (dimension 1) must be of type double.");
|
||||||
|
dim1 = mxGetScalar(curr_arg);
|
||||||
|
if (dim1 < 1) {
|
||||||
|
mexErrMsgTxt("Input 2 (dimension 1) must be at least 1.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check 3rd input argument: dim2 */
|
||||||
|
curr_arg = prhs[2];
|
||||||
|
if (mxIsDouble(curr_arg) != 1)
|
||||||
|
mexErrMsgTxt("Input 3 (dimension 2) must be of type double.");
|
||||||
|
dim2 = mxGetScalar(curr_arg);
|
||||||
|
if (dim2 < 1) {
|
||||||
|
mexErrMsgTxt("Input 3 (dimension 2) must be at least 1.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check 4th input argument: no_of_in_bytes */
|
||||||
|
curr_arg = prhs[3];
|
||||||
|
if (mxIsDouble(curr_arg) != 1)
|
||||||
|
mexErrMsgTxt("Input 4 (no. of input bytes) must be of type double.");
|
||||||
|
no_of_in_bytes = mxGetScalar(curr_arg);
|
||||||
|
|
||||||
|
/* check 5th input argument: compression_type */
|
||||||
|
curr_arg = prhs[4];
|
||||||
|
if (mxIsDouble(curr_arg) != 1)
|
||||||
|
mexErrMsgTxt("Input 5 (compression type) must be of type double.");
|
||||||
|
compression_type = mxGetScalar(curr_arg);
|
||||||
|
if (compression_type != 1) {
|
||||||
|
mexErrMsgTxt("currently only compression type 1, byte-offset compression, is supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate memory for the output data */
|
||||||
|
plhs[0] = mxCreateNumericMatrix(dim1, dim2, mxDOUBLE_CLASS, mxREAL);
|
||||||
|
if (plhs[0] == NULL)
|
||||||
|
mexErrMsgTxt("Could not allocate memory for return data.");
|
||||||
|
frame_out_start = frame_out = mxGetPr(plhs[0]);
|
||||||
|
|
||||||
|
val_curr = 0;
|
||||||
|
while (data_in.uint8-data_in_start.uint8 < no_of_in_bytes) {
|
||||||
|
if (*data_in.uint8 != 0x80) {
|
||||||
|
diff = (int) *data_in.int8++;
|
||||||
|
} else {
|
||||||
|
data_in.uint8++;
|
||||||
|
if (*data_in.uint16 != 0x8000) {
|
||||||
|
diff = (int) *data_in.int16++;
|
||||||
|
} else {
|
||||||
|
data_in.uint16++;
|
||||||
|
diff = (int) *data_in.int32++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val_curr += diff;
|
||||||
|
*frame_out++ = (double) val_curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_out-frame_out_start != dim1*dim2) {
|
||||||
|
printf("%ld bytes after uncompression, %ld bytes expected",
|
||||||
|
frame_out-frame_out_start, dim1*dim2);
|
||||||
|
mexErrMsgTxt("mismatch in number of extracted data bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
% Call function without arguments for a detailed explanation of its use
|
||||||
|
|
||||||
|
% Filename: $RCSfile: cbfread.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.2 $ $Date: 2011/05/09 13:03:07 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Macro for reading Crystallographic Binary File (CBF) files written by the
|
||||||
|
% Pilatus detector control program camserver.
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Compile the C-program cbf_uncompress using mex (see header of
|
||||||
|
% cbf_uncompress.c) to use it for uncompression instead of the slower
|
||||||
|
% Matlab code.
|
||||||
|
% Currently this routine supports only the subset of CBF features needed to
|
||||||
|
% read the Pilatus detector data.
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read_set_default
|
||||||
|
% - fopen_until_exists
|
||||||
|
% - get_hdr_val
|
||||||
|
% - compiling cbf_uncompress.c increases speed but is not mandatory
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% May 9th 2008: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [frame,vararg_remain] = cbfread(filename,varargin)
|
||||||
|
import io.*
|
||||||
|
import io.CBF.*
|
||||||
|
import utils.char_to_cellstr
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import utils.get_hdr_val
|
||||||
|
|
||||||
|
% 0: no debug information
|
||||||
|
% 1: some feedback
|
||||||
|
% 2: a lot of information
|
||||||
|
debug_level = 0;
|
||||||
|
|
||||||
|
% initialize return argument
|
||||||
|
frame = struct('header',[], 'data',[]);
|
||||||
|
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
image_read_sub_help(mfilename,'cbf');
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',value pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% set default values for the variable input arguments and parse the named
|
||||||
|
% parameters:
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
otherwise
|
||||||
|
% pass further arguments on to fopen_until_exists
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% expected maximum length for the text header
|
||||||
|
max_header_length = 4096;
|
||||||
|
|
||||||
|
% end of header signature
|
||||||
|
eoh_signature = char([ 12 26 4 213 ]);
|
||||||
|
|
||||||
|
% CBF file signature
|
||||||
|
cbf_signature = '###CBF: VERSION';
|
||||||
|
|
||||||
|
% Calling an external C routine for uncompressing the data did save about
|
||||||
|
% 30% time on a specific machine.
|
||||||
|
% The C-routine is used if a compiled version of it exists.
|
||||||
|
% See the header of cbf_uncompress.c for information on how to compile the
|
||||||
|
% C file using mex in Matlab.
|
||||||
|
|
||||||
|
c_routine = exist('+io/+CBF/cbf_uncompress.mexa64', 'file') || ...
|
||||||
|
~isempty(which('cbf_uncompress')) ; % faster than which('cbf_uncompress')
|
||||||
|
|
||||||
|
|
||||||
|
% try to open the data file
|
||||||
|
if (debug_level >= 1)
|
||||||
|
fprintf('Opening %s.\n',filename);
|
||||||
|
end
|
||||||
|
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
|
||||||
|
if (fid < 0)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
% read all data at once
|
||||||
|
[fdat,fcount] = fread(fid,'uint8=>uint8');
|
||||||
|
|
||||||
|
% close input data file
|
||||||
|
fclose(fid);
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('%d data bytes read\n',fcount);
|
||||||
|
end
|
||||||
|
|
||||||
|
% search for end of header signature within the expected maximum length of
|
||||||
|
% a header
|
||||||
|
end_of_header_pos = ...
|
||||||
|
strfind( fdat(1:min(max_header_length,length(fdat)))',...
|
||||||
|
eoh_signature );
|
||||||
|
if (length(end_of_header_pos) < 1)
|
||||||
|
cbf_error(filename,'no header end signature found');
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Header length is %d bytes.\n',end_of_header_pos -1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% return the complete header as lines of a cell array
|
||||||
|
frame.header = char_to_cellstr( char(fdat(1:(end_of_header_pos-1))') );
|
||||||
|
|
||||||
|
% check for CBF signature
|
||||||
|
if (~strncmp(cbf_signature,frame.header{1},length(cbf_signature)))
|
||||||
|
cbf_error(filename,[ 'CBF signature ''' cbf_signature ...
|
||||||
|
''' not found in first line ''' frame.header{1} '''' ]);
|
||||||
|
end
|
||||||
|
|
||||||
|
% extract the mandatory information for decompression from the header
|
||||||
|
no_of_bin_bytes = get_hdr_val(frame.header,'X-Binary-Size:','%f',1);
|
||||||
|
dim1 = get_hdr_val(frame.header,'X-Binary-Size-Fastest-Dimension:','%f',1);
|
||||||
|
dim2 = get_hdr_val(frame.header,'X-Binary-Size-Second-Dimension:','%f',1);
|
||||||
|
el_type = get_hdr_val(frame.header,'X-Binary-Element-Type: "','%[^"]',1);
|
||||||
|
switch (el_type)
|
||||||
|
case 'signed 32-bit integer'
|
||||||
|
bytes_per_pixel = 4;
|
||||||
|
otherwise
|
||||||
|
cbf_error(filename,[ 'unknown element type ' el_type ]);
|
||||||
|
end
|
||||||
|
compr_type = get_hdr_val(frame.header,'conversions="','%[^"]',1);
|
||||||
|
switch (compr_type)
|
||||||
|
case 'x-CBF_BYTE_OFFSET'
|
||||||
|
compression_type = 1;
|
||||||
|
case 'x-CBF_NONE'
|
||||||
|
compression_type = 2;
|
||||||
|
otherwise
|
||||||
|
cbf_error(filename,[ 'unknown compression type ' compr_type ]);
|
||||||
|
end
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Frame dimensions are %d x %d.\n',dim2,dim1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% uncompress the binary data
|
||||||
|
[frame.data] = ...
|
||||||
|
extract_frame(fdat((end_of_header_pos+length(eoh_signature)):end),...
|
||||||
|
dim1,dim2,no_of_bin_bytes,compression_type,...
|
||||||
|
filename,...
|
||||||
|
c_routine,debug_level);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [] = cbf_error(filename,text)
|
||||||
|
|
||||||
|
fprintf('cbfread of %s:\n %s\n',filename,text);
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [frame] = ...
|
||||||
|
extract_frame(dat_in,...
|
||||||
|
dim1,dim2,no_of_in_bytes,compression_type,...
|
||||||
|
filename,...
|
||||||
|
c_routine,debug_level)
|
||||||
|
|
||||||
|
import io.*
|
||||||
|
import io.CBF.*
|
||||||
|
import utils.char_to_cellstr
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import utils.get_hdr_val
|
||||||
|
|
||||||
|
|
||||||
|
% uncompressed data are copied directly
|
||||||
|
if (compression_type == 2)
|
||||||
|
% initialize return array
|
||||||
|
frame = zeros(dim1,dim2);
|
||||||
|
% copy uncompressed data
|
||||||
|
for (ind_out = 1:(dim1*dim2))
|
||||||
|
ind_in = ind_out *4 -3;
|
||||||
|
frame(ind_out) = double(dat_in(ind_in)) + ...
|
||||||
|
256 * double(dat_in(ind_in+1)) + ...
|
||||||
|
65536 * double(dat_in(ind_in+2)) + ...
|
||||||
|
16777216 * double(dat_in(ind_in+3));
|
||||||
|
end
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (c_routine)
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('C routine called.\n');
|
||||||
|
end
|
||||||
|
[frame] = ...
|
||||||
|
cbf_uncompress(dat_in,dim1,dim2,no_of_in_bytes,compression_type);
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Matlab routine called.\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% initialize return array
|
||||||
|
frame = zeros(dim1,dim2);
|
||||||
|
|
||||||
|
% only byte-offset compression is supported
|
||||||
|
if (compression_type ~= 1)
|
||||||
|
cbf_error(filename,...
|
||||||
|
['extract_frame does not support compression type no. ' ...
|
||||||
|
num2str(compression_type)]);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% In byte-offset compression the difference to the previous pixel value is
|
||||||
|
% stored as a byte, 16-bit integer or 32-bit integer, depending on its
|
||||||
|
% size.
|
||||||
|
% The sizes above one byte are indicated by the escape sequence -1 in the
|
||||||
|
% previous data format, i.e, a 32-bit integer is preceded by the sequence %
|
||||||
|
% 0x80 (too large for a byte)
|
||||||
|
% 0x8000 (too large for a 16-bit integer).
|
||||||
|
ind_out = 1;
|
||||||
|
ind_in = 1;
|
||||||
|
val_curr = 0;
|
||||||
|
val_diff = 0;
|
||||||
|
while (ind_in <= no_of_in_bytes)
|
||||||
|
val_diff = double(dat_in(ind_in));
|
||||||
|
ind_in = ind_in +1;
|
||||||
|
if (val_diff ~= 128)
|
||||||
|
% if not escaped as -128 (0x80=128) use the current byte as
|
||||||
|
% difference, with manual complement to emulate the sign
|
||||||
|
if (val_diff >= 128)
|
||||||
|
val_diff = val_diff - 256;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% otherwise check for 16-bit integer value
|
||||||
|
if ((dat_in(ind_in) ~= 0) || (dat_in(ind_in+1) ~= 128))
|
||||||
|
% if not escaped as -32768 (0x8000) use the current 16-bit integer
|
||||||
|
% as difference
|
||||||
|
val_diff = double(dat_in(ind_in)) + ...
|
||||||
|
256 * double(dat_in(ind_in+1));
|
||||||
|
% manual complement to emulate the sign
|
||||||
|
if (val_diff >= 32768)
|
||||||
|
val_diff = val_diff - 65536;
|
||||||
|
end
|
||||||
|
ind_in = ind_in +2;
|
||||||
|
else
|
||||||
|
ind_in = ind_in +2;
|
||||||
|
% if everything else failed use the current 32-bit value as
|
||||||
|
% difference
|
||||||
|
val_diff = double(dat_in(ind_in)) + ...
|
||||||
|
256 * double(dat_in(ind_in+1)) + ...
|
||||||
|
65536 * double(dat_in(ind_in+2)) + ...
|
||||||
|
16777216 * double(dat_in(ind_in+3));
|
||||||
|
% manual complement to emulate the sign
|
||||||
|
if (val_diff >= 2147483648)
|
||||||
|
val_diff = val_diff - 4294967296;
|
||||||
|
end
|
||||||
|
ind_in = ind_in +4;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
val_curr = val_curr + val_diff;
|
||||||
|
frame(ind_out) = val_curr;
|
||||||
|
ind_out = ind_out +1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (ind_out-1 ~= dim1*dim2)
|
||||||
|
cbf_error(filename,[ 'mismatch between ' num2str(ind_out-1) ...
|
||||||
|
' bytes after decompression with ' num2str(dim1*dim2) ...
|
||||||
|
' expected ones' ]);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% if (~original_orientation)
|
||||||
|
% frame.data = frame.data(end:-1:1,end:-1:1)';
|
||||||
|
% end
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
% Call function without arguments for a detailed explanation of its use
|
||||||
|
|
||||||
|
% Filename: $RCSfile: cbfwrite.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.2 $ $Date: 2014/04/17 16:49:22 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Macro for writing data to a Crystallographic Binary File (CBF) file.
|
||||||
|
% Assumes that the data have been read from such a file beforehand, i.e.,
|
||||||
|
% that the header exists already.
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% April 10th 2014: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [fcount_total] = cbfwrite(filename,frame,varargin)
|
||||||
|
import io.CBF.*
|
||||||
|
import io.*
|
||||||
|
import utils.default_parameter_value
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import utils.get_hdr_val
|
||||||
|
|
||||||
|
% 0: no debug information
|
||||||
|
% 1: some feedback
|
||||||
|
% 2: a lot of information
|
||||||
|
debug_level = 0;
|
||||||
|
|
||||||
|
% determine default orientation based on the file name extension
|
||||||
|
orient_by_extension = default_parameter_value('image_read','OrientByExtension');
|
||||||
|
|
||||||
|
fcount_total = -1;
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 2)
|
||||||
|
fprintf('\nUsage:\n');
|
||||||
|
fprintf('[bytes_written]=%s( filename, frame-structure [[,<name>,<value>]...]);\n',mfilename);
|
||||||
|
fprintf('Write a CBF file from data that have been read via cbfread.m before.\n');
|
||||||
|
fprintf('Conventions are likely to be specific for the PILATUS detector.\n')
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The optional <name>,<value> pairs are:\n');
|
||||||
|
image_orient_help(mfilename,'ParametersOnly',1);
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The file name should be the name of a single file without wildcards.\n');
|
||||||
|
|
||||||
|
error('At least the filename and the data-structure have to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% check frame structure
|
||||||
|
if (~isstruct(frame))
|
||||||
|
error('The 2nd parameter needs to be a structure as read by cbfread.m');
|
||||||
|
end
|
||||||
|
if (~isfield(frame,'header'))
|
||||||
|
error('The 2nd parameter needs to be a structure with a field ''header'', as read by cbfread.m');
|
||||||
|
end
|
||||||
|
if (~isfield(frame,'data'))
|
||||||
|
error('The 2nd parameter needs to be a structure with a field ''data'', as read by cbfread.m');
|
||||||
|
end
|
||||||
|
if (size(frame.header,2) ~= 1)
|
||||||
|
error('The header has the wrong dimensions. Only single-frame structures are suppoerted.\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 2)
|
||||||
|
error('At least the filename and the frame have to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 3)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 2 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 0)
|
||||||
|
error('The optional parameters have to be specified as ''name'',value pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% set default values for the variable input arguments and parse the named
|
||||||
|
% parameters:
|
||||||
|
vararg_remain = cell(4,1);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'OrientByExtension'
|
||||||
|
orient_by_extension = value;
|
||||||
|
otherwise
|
||||||
|
% pass further arguments on to fopen_until_exists
|
||||||
|
vararg_remain{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg_remain{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vararg_remain{1} = 'OrientByExtension';
|
||||||
|
vararg_remain{2} = orient_by_extension;
|
||||||
|
vararg_remain{3} = 'InvertOrientation';
|
||||||
|
vararg_remain{4} = 1;
|
||||||
|
|
||||||
|
% get the length of the zero-padding at the end of the file
|
||||||
|
padding_length = get_hdr_val(frame.header{1},'X-Binary-Size-Padding:','%d',1);
|
||||||
|
|
||||||
|
% end of header signature
|
||||||
|
eoh_signature = char([ 12 26 4 213 ]);
|
||||||
|
|
||||||
|
% orient image
|
||||||
|
[frame,vararg_remain] = image_orient(frame,vararg_remain);
|
||||||
|
|
||||||
|
|
||||||
|
% open file for write-access, overwrite in case of an existing file
|
||||||
|
[fid] = fopen(filename,'w');
|
||||||
|
if (fid < 0)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% In byte-offset compression the difference to the previous pixel value is
|
||||||
|
% stored as a byte, 16-bit integer or 32-bit integer, depending on its
|
||||||
|
% size.
|
||||||
|
% The sizes above one byte are indicated by the escape sequence -1 in the
|
||||||
|
% previous data format, i.e, a 32-bit integer is preceded by the sequence %
|
||||||
|
% 0x80 (too large for a byte)
|
||||||
|
% 0x8000 (too large for a 16-bit integer).
|
||||||
|
ind_out = 1;
|
||||||
|
no_of_pixels = size(frame.data,1) * size(frame.data,2);
|
||||||
|
|
||||||
|
% initialize output array at maximum size
|
||||||
|
frame_out = zeros(no_of_pixels*4 + padding_length,1,'uint8');
|
||||||
|
val_prev = 0;
|
||||||
|
for ind_in = 1:no_of_pixels
|
||||||
|
val_diff = frame.data(ind_in) - val_prev;
|
||||||
|
if (abs(val_diff) < 128)
|
||||||
|
% write differences in the range from -127 to 127 directly as 8bit
|
||||||
|
% signed integer:
|
||||||
|
% manual complement to emulate the sign
|
||||||
|
if (val_diff < 0)
|
||||||
|
val_diff = 256 + val_diff;
|
||||||
|
end
|
||||||
|
frame_out(ind_out) = val_diff;
|
||||||
|
ind_out = ind_out +1;
|
||||||
|
else
|
||||||
|
% escape with 0x80
|
||||||
|
frame_out(ind_out) = 128;
|
||||||
|
% check for 16-bit integer value
|
||||||
|
if (abs(val_diff) < 32768)
|
||||||
|
% write signed 16bit integer value:
|
||||||
|
% manual complement to emulate the sign
|
||||||
|
if (val_diff < 0)
|
||||||
|
val_diff = 65536 + val_diff;
|
||||||
|
end
|
||||||
|
frame_out(ind_out+1) = bitand(val_diff,255);
|
||||||
|
frame_out(ind_out+2) = bitand(val_diff,65280)/256;
|
||||||
|
ind_out = ind_out +3;
|
||||||
|
else
|
||||||
|
% escape with 0x8000
|
||||||
|
frame_out(ind_out+1) = 0;
|
||||||
|
frame_out(ind_out+2) = 128;
|
||||||
|
% write signed 32bit integer value:
|
||||||
|
% manual complement to emulate the sign
|
||||||
|
if (val_diff < 0)
|
||||||
|
val_diff = 4294967296 + val_diff;
|
||||||
|
end
|
||||||
|
frame_out(ind_out+3) = bitand(val_diff,255);
|
||||||
|
frame_out(ind_out+4) = bitand(val_diff,65280)/256;
|
||||||
|
frame_out(ind_out+5) = bitand(val_diff,16711680)/65536;
|
||||||
|
frame_out(ind_out+6) = bitand(val_diff,4278190080)/16777216;
|
||||||
|
ind_out = ind_out +7;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
% the current intensity value becomes the previous value
|
||||||
|
val_prev = frame.data(ind_in);
|
||||||
|
end
|
||||||
|
|
||||||
|
% calculate length of binary data including zero-padding at the end
|
||||||
|
binary_length = ind_out -1 + padding_length;
|
||||||
|
|
||||||
|
% update this value in the file-header
|
||||||
|
[~, line_no] = get_hdr_val(frame.header{1},'X-Binary-Size:','%f',1);
|
||||||
|
frame.header{1}{line_no} = sprintf('X-Binary-Size: %d',binary_length-padding_length);
|
||||||
|
|
||||||
|
% write header
|
||||||
|
[fcount_total] = fprintf(fid,'%s\r\n',frame.header{1}{:});
|
||||||
|
if (fcount_total == 0)
|
||||||
|
error('Could not write any header data.\n');
|
||||||
|
end
|
||||||
|
% write end-of-header signature
|
||||||
|
[fcount] = fwrite(fid,eoh_signature,'uint8');
|
||||||
|
fcount_total = fcount_total + fcount;
|
||||||
|
if (fcount == 0)
|
||||||
|
error('Could not write end-of-header signature.\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
% write binary data
|
||||||
|
[fcount] = fwrite(fid,frame_out(1:(binary_length)));
|
||||||
|
fcount_total = fcount_total + fcount;
|
||||||
|
if (fcount ~= binary_length)
|
||||||
|
error('Could not write CBF image-data.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% write binary-end signature
|
||||||
|
[fcount] = fprintf(fid,'\r\n--CIF-BINARY-FORMAT-SECTION----\r\n;\r\n\r\n');
|
||||||
|
fcount_total = fcount_total + fcount;
|
||||||
|
if (fcount < 1)
|
||||||
|
error('Could not write CBF binary-end signature');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% close output data file
|
||||||
|
fclose(fid);
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('%d data bytes written\n',fcount_total);
|
||||||
|
end
|
||||||
|
|
||||||
|
return;
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
%ADD_CONTENT write matlab structure to H5 file
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function add_content(data, gid, plist, comp, overwrite)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
fn = fieldnames(data);
|
||||||
|
for jj=1:length(fn)
|
||||||
|
if isstruct(data.(fn{jj}))
|
||||||
|
fn_sub = fieldnames(data.(fn{jj}));
|
||||||
|
if length(fn_sub) <= 2 && isfield(data.(fn{jj}), 'Value')
|
||||||
|
% found dataset
|
||||||
|
if isfield(data.(fn{jj}), 'Attributes')
|
||||||
|
Attributes.MATLAB_class = class(data.(fn{jj}).Value);
|
||||||
|
write_dataset(data.(fn{jj}).Value, gid, fn{jj}, plist, comp, overwrite, data.(fn{jj}).Attributes);
|
||||||
|
else
|
||||||
|
Attributes.MATLAB_class = class(data.(fn{jj}).Value);
|
||||||
|
write_dataset(data.(fn{jj}).Value, gid, fn{jj}, plist, comp, overwrite, Attributes);
|
||||||
|
end
|
||||||
|
elseif strcmpi(fn{jj}, 'Attributes')
|
||||||
|
% add attributes to group
|
||||||
|
fn_attr = fieldnames(data.Attributes);
|
||||||
|
for ii=1:length(fn_attr)
|
||||||
|
write_attribute(gid, data.Attributes.(fn_attr{ii}), fn_attr{ii});
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% found group
|
||||||
|
gid_new = add_groups(gid, fn{jj}, plist, true);
|
||||||
|
if length(data.(fn{jj})) == 1
|
||||||
|
add_content(data.(fn{jj}), gid_new, plist, comp, overwrite)
|
||||||
|
else
|
||||||
|
fn_names = cell(1,length(data.(fn{jj})));
|
||||||
|
for ii=1:length(data.(fn{jj}))
|
||||||
|
fn_names{ii} = sprintf([fn{jj} '_%d'],ii-1);
|
||||||
|
gid_new_sub = add_groups(gid_new, fn_names{ii}, plist, true);
|
||||||
|
add_content(data.(fn{jj})(ii), gid_new_sub, plist, comp, overwrite);
|
||||||
|
end
|
||||||
|
write_attribute(gid_new, 'structure array', 'MATLAB_class');
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% append dataset
|
||||||
|
Attributes.MATLAB_class = class(data.(fn{jj}));
|
||||||
|
write_dataset(data.(fn{jj}), gid, fn{jj}, plist, comp, overwrite, Attributes);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
%ADD_GROUPS add groups or open them if they exist
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function gid = add_groups(fileID, gpath, plist, varargin)
|
||||||
|
|
||||||
|
if nargin > 3
|
||||||
|
single_data = varargin{1};
|
||||||
|
else
|
||||||
|
single_data = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~single_data
|
||||||
|
gpath_depth = length(gpath);
|
||||||
|
gid{1} = fileID;
|
||||||
|
for ii=1:gpath_depth
|
||||||
|
try
|
||||||
|
gid{end+1} = H5G.open(gid{ii}, gpath{ii}, plist);
|
||||||
|
catch
|
||||||
|
gid{end+1} = H5G.create(gid{ii},gpath{ii},plist,plist,plist);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
try
|
||||||
|
gid = H5G.open(fileID, gpath, plist);
|
||||||
|
catch
|
||||||
|
gid = H5G.create(fileID,gpath,plist,plist,plist);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
% Determine datatype for HDF files
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [datatype_h5, data] = get_datatype(data)
|
||||||
|
|
||||||
|
if isempty(data)
|
||||||
|
data = '';
|
||||||
|
end
|
||||||
|
|
||||||
|
switch class(data)
|
||||||
|
case 'uint32'
|
||||||
|
datatype_h5 = 'H5T_STD_U32LE';
|
||||||
|
case 'int32'
|
||||||
|
datatype_h5 = 'H5T_STD_I32LE';
|
||||||
|
case 'int64'
|
||||||
|
datatype_h5 = 'H5T_STD_I64LE';
|
||||||
|
case 'uint64'
|
||||||
|
datatype_h5 = 'H5T_STD_U64LE';
|
||||||
|
case 'double'
|
||||||
|
if isreal(data)
|
||||||
|
datatype_h5 = 'H5T_NATIVE_DOUBLE';
|
||||||
|
else
|
||||||
|
datatype_h5 = 'complex';
|
||||||
|
end
|
||||||
|
case 'single'
|
||||||
|
if isreal(data)
|
||||||
|
datatype_h5 = 'H5T_NATIVE_FLOAT';
|
||||||
|
else
|
||||||
|
datatype_h5 = 'complex';
|
||||||
|
end
|
||||||
|
case 'logical'
|
||||||
|
data = uint32(data);
|
||||||
|
datatype_h5 = 'H5T_STD_U32LE';
|
||||||
|
case 'char'
|
||||||
|
if size(data,1)>1
|
||||||
|
data = cellstr(data);
|
||||||
|
datatype_h5 = 'char_array';
|
||||||
|
else
|
||||||
|
datatype_h5 = 'H5T_UNIX_D32BE'; %'H5T_UNIX_D32LE';
|
||||||
|
end
|
||||||
|
case 'cell'
|
||||||
|
datatype_h5 = 'H5T_C_S1';
|
||||||
|
case 'struct'
|
||||||
|
datatype_h5 = 'struct';
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('Unknown data type %s', class(data))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
%HDF5_APPEND_ATTR Append an attribute to a dataset
|
||||||
|
%
|
||||||
|
% file... HDF filename
|
||||||
|
% attr... structure of attributes
|
||||||
|
% loc... location of the dataset that needs to be removed
|
||||||
|
%
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function hdf5_append_attr( file, attr, loc)
|
||||||
|
import io.HDF.*
|
||||||
|
plist = 'H5P_DEFAULT';
|
||||||
|
|
||||||
|
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
|
||||||
|
|
||||||
|
gpath = strsplit(rm_delimiter(loc), '/');
|
||||||
|
|
||||||
|
gpath_depth = length(gpath);
|
||||||
|
gid{1} = fileID;
|
||||||
|
for ii=1:gpath_depth
|
||||||
|
try
|
||||||
|
gid{end+1} = H5G.open(gid{ii}, gpath{ii}, plist);
|
||||||
|
catch
|
||||||
|
gid{end+1} = H5D.open(gid{ii}, gpath{ii});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fn = fieldnames(attr);
|
||||||
|
for ii=1:length(fn)
|
||||||
|
write_attribute(gid{end}, attr.(fn{ii}), fn{ii}, true);
|
||||||
|
end
|
||||||
|
|
||||||
|
H5F.close(fileID);
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
%HDF5_ATTR_EXISTS check if attribute exists in given file
|
||||||
|
% file... h5 file path
|
||||||
|
% attr... dataset name
|
||||||
|
%
|
||||||
|
% *optional*
|
||||||
|
% gpath... path within the h5 file; default root (/)
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ out ] = hdf5_attr_exists(file, name, varargin)
|
||||||
|
|
||||||
|
out = false;
|
||||||
|
|
||||||
|
% load info
|
||||||
|
if nargin > 2
|
||||||
|
h = h5info(file, varargin{1});
|
||||||
|
else
|
||||||
|
h = h5info(file);
|
||||||
|
end
|
||||||
|
|
||||||
|
% loop through datasets and check if name exists
|
||||||
|
for ii=1:numel(h.Attributes)
|
||||||
|
if strcmpi(h.Attributes(ii).Name, name)
|
||||||
|
out = true;
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
%HDF5_CP_FILE copy HDF files
|
||||||
|
% orig_filename... source file
|
||||||
|
% duplicate_filename... target file
|
||||||
|
%
|
||||||
|
% *optional* given as name/value pair
|
||||||
|
% groups... groups to copy; either string or cell of
|
||||||
|
% strings; default: everything in root
|
||||||
|
% copy_type... 'deep', 'normal' or 'shallow' copy;
|
||||||
|
% 'shallow' creates external links in target file;
|
||||||
|
% 'normal' is similar to linux 'cp' command;
|
||||||
|
% 'deep' dereferences all internal and external links;
|
||||||
|
% default: 'shallow'
|
||||||
|
%
|
||||||
|
% EXAMPLES:
|
||||||
|
% hdf5_cp_file('./test.h5', './test_new.h5')
|
||||||
|
% hdf5_cp_file('./test.h5', './test_new.h5', 'copy_type', 'deep');
|
||||||
|
%
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function hdf5_cp_file(orig_filename, duplicate_filename, varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
% take care of input arguments
|
||||||
|
groups = [];
|
||||||
|
copy_type = 'shallow';
|
||||||
|
|
||||||
|
% parse the variable input arguments vararg = cell(0,0);
|
||||||
|
if ~isempty(varargin)
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch lower(name)
|
||||||
|
case 'groups'
|
||||||
|
groups = value;
|
||||||
|
case 'copy_type'
|
||||||
|
copy_type = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
switch copy_type
|
||||||
|
case 'shallow'
|
||||||
|
if isempty(groups)
|
||||||
|
% if no groups are specified, use h5info to get all datasets and groups
|
||||||
|
% from root
|
||||||
|
h = h5info(orig_filename, '/');
|
||||||
|
lng = length(h.Groups);
|
||||||
|
lnd = length(h.Datasets);
|
||||||
|
lna = length(h.Attributes);
|
||||||
|
|
||||||
|
groups = cell([1 lng+lnd]);
|
||||||
|
attributes = [];
|
||||||
|
|
||||||
|
for ii=1:lng
|
||||||
|
groups{ii} = h.Groups(ii).Name;
|
||||||
|
end
|
||||||
|
for ii=1:lnd
|
||||||
|
groups{ii+lng} = h.Datasets(ii).Name;
|
||||||
|
end
|
||||||
|
for ii=1:lna
|
||||||
|
attributes.(h.Attributes(ii).Name) = h.Attributes(ii).Value;
|
||||||
|
if iscell(h.Attributes(ii).Value)
|
||||||
|
attributes.(h.Attributes(ii).Name) = attributes.(h.Attributes(ii).Name){1};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
attributes = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
s = [];
|
||||||
|
if iscell(groups)
|
||||||
|
for ii=1:length(groups)
|
||||||
|
subgrps = strsplit(rm_delimiter(groups{ii}), '/');
|
||||||
|
s = setfield(s, subgrps{:}, ['ext:' orig_filename ':' groups{ii}]);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
s.groups = ['ext:' orig_filename ':' groups];
|
||||||
|
end
|
||||||
|
|
||||||
|
% append attributes
|
||||||
|
if ~isempty(attributes)
|
||||||
|
s.Attributes = attributes;
|
||||||
|
end
|
||||||
|
|
||||||
|
save2hdf5(duplicate_filename, s, 'overwrite', true, 'iscopy', true);
|
||||||
|
|
||||||
|
case 'deep'
|
||||||
|
s = io.HDF.hdf5_load(orig_filename, '-ca');
|
||||||
|
save2hdf5(duplicate_filename, s, 'overwrite', true, 'iscopy', true);
|
||||||
|
|
||||||
|
case 'normal'
|
||||||
|
copyfile(orig_filename, duplicate_filename)
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('Unknown copy type!')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
%HDF5_DSET_EXISTS check if dataset exists in given file
|
||||||
|
% file... h5 file path
|
||||||
|
% dset... dataset name
|
||||||
|
%
|
||||||
|
% *optional*
|
||||||
|
% gpath... path within the h5 file; default root (/)
|
||||||
|
% check_links... include links; default true
|
||||||
|
%
|
||||||
|
% EXAMPLES:
|
||||||
|
% out = io.HDF.hdf5_dset_exists('./recons.h5',
|
||||||
|
% 'object_phase_unwrapped', '/reconstruction', true);
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [out] = hdf5_dset_exists(file, dset, varargin)
|
||||||
|
|
||||||
|
out = false;
|
||||||
|
|
||||||
|
% load info
|
||||||
|
if nargin > 2
|
||||||
|
h = h5info(file, varargin{1});
|
||||||
|
else
|
||||||
|
h = h5info(file);
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargin > 3
|
||||||
|
check_links = varargin{2};
|
||||||
|
else
|
||||||
|
check_links = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargin > 4
|
||||||
|
check_groups = varargin{3};
|
||||||
|
else
|
||||||
|
check_groups = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
% loop through datasets and check if name exists
|
||||||
|
for ii=1:numel(h.Datasets)
|
||||||
|
if strcmpi(h.Datasets(ii).Name, dset)
|
||||||
|
out = true;
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if check_links
|
||||||
|
for ii=1:numel(h.Links)
|
||||||
|
if strcmpi(h.Links(ii).Name, dset)
|
||||||
|
out = true;
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if check_groups
|
||||||
|
for ii=1:numel(h.Groups)
|
||||||
|
[~, gname] = fileparts(h.Groups(ii).Name);
|
||||||
|
if strcmpi(gname, dset)
|
||||||
|
out = true;
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,642 @@
|
|||||||
|
% HDF5_LOAD Load an hdf5 file
|
||||||
|
%
|
||||||
|
% DATA = HDF5_LOAD(filename) reads a complete file hierarchy recursively, with
|
||||||
|
% file name/path being specified by the 'filename' argument
|
||||||
|
%
|
||||||
|
% DATA = HDF5_LOAD(filename, '-a') reads a complete file hierarchy
|
||||||
|
% recursively, including attributes
|
||||||
|
%
|
||||||
|
% DATA = HDF5_LOAD(filename, location) reads a particular group, link, or a single dataset
|
||||||
|
% specified by the 'location' argument
|
||||||
|
%
|
||||||
|
% ATT = HDF5_LOAD(filename, location, '-a') reads all datasets and attributes associated
|
||||||
|
% with a particular location in the file (group, link or dataset)
|
||||||
|
%
|
||||||
|
% ATT = HDF5_LOAD(filename, location, '-ca') reads all datasets and attributes associated
|
||||||
|
% with a particular location in the file (group, link or dataset) and
|
||||||
|
% converts datasets to a specific matlab class based on attribute 'MATLAB_class'
|
||||||
|
%
|
||||||
|
% SLICE = HDF5_LOAD(filename, location, {rowRange, colRange, frameRange, ...}) reads a
|
||||||
|
% portion of a dataset along specified dimentions, where slicing ranges can be defined in
|
||||||
|
% the following ways (negative indexes count from the end of the corresponding dimensions):
|
||||||
|
% range = scalar_index - reads a particular row/col/frame/... (indentical to
|
||||||
|
% 'range = [scalar_index, scalar_index]')
|
||||||
|
% range = [start_index, end_index] - reads all data between start and end
|
||||||
|
% indexes
|
||||||
|
% range = [start_index, Inf] - reads all data from start_index to the last
|
||||||
|
% existing element in the file
|
||||||
|
% range = [], or range is omitted at the end - reads the full range of values for that
|
||||||
|
% dimention (indentical to 'range = [1, Inf]')
|
||||||
|
%
|
||||||
|
% Examples:
|
||||||
|
% hdf5_load('scan_003.hdf5')
|
||||||
|
% hdf5_load('scan_003.hdf5', '/entry/sample/description')
|
||||||
|
% hdf5_load('scan_003.hdf5', '/entry/collection/data/spec', '-a')
|
||||||
|
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {5})
|
||||||
|
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {[-100, Inf]})
|
||||||
|
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {5, [500, Inf], [1, 100]})
|
||||||
|
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {[], [], [1, 100]})
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group
|
||||||
|
% and the Science IT group, Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function data = hdf5_load(filename, varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
load_attr = false;
|
||||||
|
convert2matlab = false;
|
||||||
|
|
||||||
|
narginchk(1, 3);
|
||||||
|
if nargin == 1
|
||||||
|
% Read the complete file hierarchy recursively
|
||||||
|
try
|
||||||
|
info = h5info(filename);
|
||||||
|
info.Name = ''; % a special case of the root group
|
||||||
|
|
||||||
|
catch ME
|
||||||
|
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
|
||||||
|
ME = MException('hdf5_load:h5info', ...
|
||||||
|
strjoin({'File', filename, 'does not exist'}));
|
||||||
|
end
|
||||||
|
|
||||||
|
throwAsCaller(ME);
|
||||||
|
end
|
||||||
|
|
||||||
|
[data, links] = hdf5_loadGroup(filename, info);
|
||||||
|
data = assign_links(data, info, links);
|
||||||
|
|
||||||
|
elseif nargin == 2
|
||||||
|
if any(strcmp(varargin{1}, {'-a', '-ca', '-c'}))
|
||||||
|
% second argument is an attribute flag
|
||||||
|
try
|
||||||
|
info = h5info(filename);
|
||||||
|
info.Name = ''; % a special case of the root group
|
||||||
|
|
||||||
|
catch ME
|
||||||
|
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
|
||||||
|
ME = MException('hdf5_load:h5info', ...
|
||||||
|
strjoin({'File', filename, 'does not exist or is not valid h5 file'}));
|
||||||
|
end
|
||||||
|
|
||||||
|
throwAsCaller(ME);
|
||||||
|
end
|
||||||
|
|
||||||
|
if any(strcmp(varargin{1}, {'-a', '-ca'}))
|
||||||
|
load_attr = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if any(strcmp(varargin{1}, {'-ca', '-c'}))
|
||||||
|
convert2matlab = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
[data, links] = hdf5_loadGroup(filename, info, convert2matlab, load_attr);
|
||||||
|
data = assign_links(data, info, links, varargin{1});
|
||||||
|
|
||||||
|
else
|
||||||
|
% Read a group or a single dataset
|
||||||
|
location = varargin{1};
|
||||||
|
try
|
||||||
|
info = h5info(filename, location);
|
||||||
|
if strcmp(info.Name, '/') % a special case of the root group
|
||||||
|
info.Name = '';
|
||||||
|
end
|
||||||
|
|
||||||
|
catch ME
|
||||||
|
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
|
||||||
|
ME = MException('hdf5_load:h5info', ...
|
||||||
|
strjoin({'File', filename, 'does not exist'}));
|
||||||
|
|
||||||
|
elseif strcmp(ME.identifier, 'MATLAB:imagesci:h5info:libraryError')
|
||||||
|
ME = MException('hdf5_load:h5info', ...
|
||||||
|
strjoin({'H5Location', location, 'was not found in', filename, 'file'}));
|
||||||
|
end
|
||||||
|
|
||||||
|
throwAsCaller(ME);
|
||||||
|
end
|
||||||
|
|
||||||
|
if isfield(info, 'Groups')
|
||||||
|
% Read a group with its internal hierarchy
|
||||||
|
[data, links] = hdf5_loadGroup(filename, info);
|
||||||
|
data = assign_links(data, info, links);
|
||||||
|
|
||||||
|
elseif isfield(info, 'Datatype')
|
||||||
|
% Read a data set
|
||||||
|
type = info.Datatype.Class;
|
||||||
|
data = hdf5_loadDataset(filename, location, type);
|
||||||
|
|
||||||
|
elseif isfield(info, 'Type')
|
||||||
|
% Read a link
|
||||||
|
data = hdf5_loadLink(info);
|
||||||
|
|
||||||
|
else
|
||||||
|
error('hdf5_load:parse_argument', ...
|
||||||
|
'The 2-nd argument must be a name of a group, dataset, or link');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif nargin == 3
|
||||||
|
% Read attributes of a group or a data set, or slices of a data set
|
||||||
|
location = varargin{1};
|
||||||
|
try
|
||||||
|
info = h5info(filename, location);
|
||||||
|
if strcmp(info.Name, '/') % a special case of the root group
|
||||||
|
info.Name = '';
|
||||||
|
end
|
||||||
|
|
||||||
|
catch ME
|
||||||
|
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
|
||||||
|
ME = MException('hdf5_load:h5info', ...
|
||||||
|
strjoin({'File', filename, 'does not exist or is not HDF5 format'}));
|
||||||
|
|
||||||
|
elseif strcmp(ME.identifier, 'MATLAB:imagesci:h5info:libraryError')
|
||||||
|
ME = MException('hdf5_load:h5info', ...
|
||||||
|
strjoin({'H5Location', location, 'was not found in', filename, 'file'}));
|
||||||
|
end
|
||||||
|
|
||||||
|
throwAsCaller(ME);
|
||||||
|
end
|
||||||
|
|
||||||
|
if iscell(varargin{2})
|
||||||
|
% Read slices of a data set
|
||||||
|
slices = varargin{2};
|
||||||
|
|
||||||
|
% Check if the specified location is a data set
|
||||||
|
if ~isfield(info, 'Dataspace')
|
||||||
|
error('hdf5_load:invalid_location', ...
|
||||||
|
'Slicing ranges are not applicable, the location is not a data set');
|
||||||
|
end
|
||||||
|
|
||||||
|
data_size = info.Dataspace.Size;
|
||||||
|
if length(slices) > length(data_size)
|
||||||
|
error('hdf5_load:invalid_slicing', ...
|
||||||
|
'A number of slicing ranges is larger than a dimention of a data set')
|
||||||
|
end
|
||||||
|
|
||||||
|
% Parse ranges
|
||||||
|
startIndex = ones(1, length(data_size));
|
||||||
|
nElements = Inf(1, length(data_size));
|
||||||
|
for i = 1:length(slices)
|
||||||
|
[startIndex(i), nElements(i)] = parse_range(slices{i}, data_size(i));
|
||||||
|
end
|
||||||
|
|
||||||
|
% Read data
|
||||||
|
data = h5read(filename, location, startIndex, nElements);
|
||||||
|
|
||||||
|
elseif any(strcmp(varargin{2}, {'-a', '-ca', '-c'}))
|
||||||
|
% Read attributes and/or convert to matlab structures
|
||||||
|
if any(strcmp(varargin{2}, {'-a', '-ca'}))
|
||||||
|
load_attr = true;
|
||||||
|
end
|
||||||
|
if any(strcmp(varargin{2}, {'-ca', '-c'}))
|
||||||
|
convert2matlab = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if isfield(info, 'Groups')
|
||||||
|
% Read a group with its internal hierarchy
|
||||||
|
[data, links] = hdf5_loadGroup(filename, info, convert2matlab, load_attr);
|
||||||
|
data = assign_links(data, info, links, varargin{2});
|
||||||
|
|
||||||
|
elseif isfield(info, 'Datatype')
|
||||||
|
% Read a data set
|
||||||
|
type = info.Datatype.Class;
|
||||||
|
dset_val = hdf5_loadDataset(filename, location, type);
|
||||||
|
if load_attr || convert2matlab
|
||||||
|
[dset_attr, ml_class_dset] = hdf5_loadAttributes(info, convert2matlab, load_attr);
|
||||||
|
else
|
||||||
|
ml_class_dset = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isempty(ml_class_dset)
|
||||||
|
switch ml_class_dset
|
||||||
|
case 'complex'
|
||||||
|
dset_val = dset_val.r + 1i*dset_val.i;
|
||||||
|
|
||||||
|
case 'cell'
|
||||||
|
if ~iscell(dset_val)
|
||||||
|
dset_val = {dset_val};
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'char_array'
|
||||||
|
dset_val = char(dset_val);
|
||||||
|
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
conv2ml = str2func(ml_class_dset);
|
||||||
|
dset_val = conv2ml(dset_val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if load_attr
|
||||||
|
data.Attributes = dset_attr;
|
||||||
|
data.Value = dset_val;
|
||||||
|
|
||||||
|
else
|
||||||
|
data = dset_val;
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif isfield(info, 'Type')
|
||||||
|
% Read a link
|
||||||
|
data = hdf5_loadLink(info, convert2matlab, load_attr);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
error('hdf5_load:parse_argument', ...
|
||||||
|
'Incorrect 3-rd argument');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function [data, links] = hdf5_loadGroup(filename, info, varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
if nargin > 2
|
||||||
|
convert2matlab = varargin{1};
|
||||||
|
load_attr = varargin{2};
|
||||||
|
else
|
||||||
|
convert2matlab = false;
|
||||||
|
load_attr = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
data = [];
|
||||||
|
|
||||||
|
% Collect links
|
||||||
|
links = info.Links.'; % transform to a row for easier indexing
|
||||||
|
if ~isempty(links)
|
||||||
|
for link_ind = 1:length(links)
|
||||||
|
links(link_ind).Name = [info.Name, '/', links(link_ind).Name];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Load the datasets
|
||||||
|
for dataset_ind = 1:length(info.Datasets)
|
||||||
|
dset_info = info.Datasets(dataset_ind);
|
||||||
|
dset_name = dset_info.Name;
|
||||||
|
location = [info.Name, '/', dset_name];
|
||||||
|
type = dset_info.Datatype.Class;
|
||||||
|
|
||||||
|
dset_val = hdf5_loadDataset(filename, location, type);
|
||||||
|
|
||||||
|
% Load attributes of a dataset
|
||||||
|
if load_attr || convert2matlab
|
||||||
|
[dset_attr, ml_class_dset] = hdf5_loadAttributes(dset_info, convert2matlab, load_attr);
|
||||||
|
else
|
||||||
|
ml_class_dset = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isempty(ml_class_dset)
|
||||||
|
switch ml_class_dset
|
||||||
|
case 'complex'
|
||||||
|
dset_val = dset_val.r + 1i*dset_val.i;
|
||||||
|
|
||||||
|
case 'cell'
|
||||||
|
if ~iscell(dset_val)
|
||||||
|
dset_val = {dset_val};
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'char_array'
|
||||||
|
dset_val = char(dset_val);
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
conv2ml = str2func(ml_class_dset);
|
||||||
|
dset_val = conv2ml(dset_val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if load_attr
|
||||||
|
data.(dset_name).Attributes = dset_attr;
|
||||||
|
data.(dset_name).Value = dset_val;
|
||||||
|
|
||||||
|
else
|
||||||
|
data.(dset_name) = dset_val;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Load attributes of a group
|
||||||
|
if load_attr || convert2matlab
|
||||||
|
[group_attr, ml_class_group] = hdf5_loadAttributes(info, convert2matlab, load_attr);
|
||||||
|
if load_attr
|
||||||
|
data.Attributes = group_attr;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ml_class_group = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
% Load the internal groups recursively
|
||||||
|
for group_ind = 1:length(info.Groups)
|
||||||
|
[group_data, child_links] = hdf5_loadGroup(filename, info.Groups(group_ind), convert2matlab, load_attr);
|
||||||
|
|
||||||
|
[~, group_name] = fileparts(info.Groups(group_ind).Name);
|
||||||
|
data.(group_name) = group_data;
|
||||||
|
|
||||||
|
% Aggregate links
|
||||||
|
links = [links, child_links]; %#ok<AGROW> There shouldn't be too many links present
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isempty(ml_class_group)
|
||||||
|
% convert the groups
|
||||||
|
data_temp = data;
|
||||||
|
data = [];
|
||||||
|
if isfield(data_temp, 'Attributes')
|
||||||
|
data.Attributes = data_temp.Attributes;
|
||||||
|
data_temp = rmfield(data_temp, 'Attributes');
|
||||||
|
fn = fieldnames(data_temp);
|
||||||
|
for group_ind = 1:length(fn)
|
||||||
|
switch ml_class_group
|
||||||
|
case 'cell'
|
||||||
|
data.Value{group_ind} = data_temp.(fn{group_ind});
|
||||||
|
|
||||||
|
case 'structure array'
|
||||||
|
data.Value(group_ind) = data_temp.(fn{group_ind});
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
keyboard
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fn = fieldnames(data_temp);
|
||||||
|
for group_ind = 1:length(fn)
|
||||||
|
switch ml_class_group
|
||||||
|
case 'cell'
|
||||||
|
data{group_ind} = data_temp.(fn{group_ind});
|
||||||
|
|
||||||
|
case 'structure array'
|
||||||
|
data(group_ind) = data_temp.(fn{group_ind});
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
keyboard
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function [data, ml_class] = hdf5_loadAttributes(info, convert2matlab, load_attr)
|
||||||
|
data = [];
|
||||||
|
ml_class = [];
|
||||||
|
if isfield(info, 'Attributes') % info structure may not contain Attributes field
|
||||||
|
attr_info = info.Attributes;
|
||||||
|
for attr_ind = 1:length(attr_info)
|
||||||
|
attr = attr_info(attr_ind);
|
||||||
|
attr_name = attr.Name;
|
||||||
|
if ~isvarname(attr_name)
|
||||||
|
if ~any(strcmpi({attr_info.Name}, ['MATLAB' attr_name])) && ~strcmpi(attr_name, '_class')
|
||||||
|
warning('Invalid attribute name! Added "MATLAB" prefix to %s.', attr_name)
|
||||||
|
attr_name = ['MATLAB' attr_name];
|
||||||
|
else
|
||||||
|
error('Invalid attribute name.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if convert2matlab && strcmpi(attr_name, 'MATLAB_class')
|
||||||
|
ml_class = attr.Value{1};
|
||||||
|
|
||||||
|
elseif load_attr
|
||||||
|
if iscell(attr.Value)
|
||||||
|
data.(attr_name) = attr.Value{1};
|
||||||
|
else
|
||||||
|
data.(attr_name) = attr.Value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function data = hdf5_loadDataset(filename, location, type)
|
||||||
|
if strcmp(type, 'H5T_ENUM')
|
||||||
|
% Workaround for a bug in h5postprocessenums (part of h5read) function
|
||||||
|
data = read_enum(filename, location);
|
||||||
|
|
||||||
|
else
|
||||||
|
data = h5read(filename, location);
|
||||||
|
if iscell(data) && numel(data) == 1 && ischar(data{1})
|
||||||
|
data = data{1}; % utility string unwrapping from a single cell
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function data = hdf5_loadLink(link, varargin)
|
||||||
|
|
||||||
|
if nargin > 2
|
||||||
|
convert2matlab = varargin{1};
|
||||||
|
load_attr = varargin{2};
|
||||||
|
else
|
||||||
|
convert2matlab = false;
|
||||||
|
load_attr = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
switch link.Type
|
||||||
|
case {'hard link', 'soft link'}
|
||||||
|
filename = link.Filename;
|
||||||
|
location = link.Value{1};
|
||||||
|
|
||||||
|
case 'external link'
|
||||||
|
filename = absolute_path(link.Value{1}, link.Filename);
|
||||||
|
location = link.Value{2};
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('hdf5_load:hdf5_loadLink', ...
|
||||||
|
strjoin({'Unknown link type at', link.Name}));
|
||||||
|
end
|
||||||
|
|
||||||
|
link_info = h5info(filename, location);
|
||||||
|
if strcmp(link_info.Name, '/') % a special case of the root group
|
||||||
|
link_info.Name = '';
|
||||||
|
end
|
||||||
|
|
||||||
|
if isfield(link_info, 'Groups')
|
||||||
|
[data, links] = hdf5_loadGroup(filename, link_info, convert2matlab, load_attr);
|
||||||
|
data = assign_links(data, link_info, links);
|
||||||
|
|
||||||
|
elseif isfield(link_info, 'Datatype')
|
||||||
|
type = link_info.Datatype.Class;
|
||||||
|
data = hdf5_loadDataset(filename, location, type);
|
||||||
|
|
||||||
|
elseif isfield(link_info, 'Type')
|
||||||
|
data = hdf5_loadLink(link_info, convert2matlab, load_attr);
|
||||||
|
|
||||||
|
else
|
||||||
|
error('hdf5_load:hdf5_loadLink', ...
|
||||||
|
strjoin({'A link at', link_info.Name, 'must be a name of a group, dataset, or link'}));
|
||||||
|
end
|
||||||
|
|
||||||
|
function data = assign_links(data, info, links, varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
if ~isempty(varargin)
|
||||||
|
flag = varargin{1};
|
||||||
|
else
|
||||||
|
flag = [];
|
||||||
|
end
|
||||||
|
if ~isempty(links)
|
||||||
|
cut_start = length(info.Name) + 1;
|
||||||
|
|
||||||
|
while true
|
||||||
|
resolved_links = false(size(links));
|
||||||
|
|
||||||
|
for ind = 1:length(links)
|
||||||
|
link = links(ind);
|
||||||
|
place = strrep(link.Name(cut_start:end), '/', '.');
|
||||||
|
target = [];
|
||||||
|
target_struc = [];
|
||||||
|
if ~isempty(flag) && contains(flag, 'a') && contains(flag, 'c')
|
||||||
|
target_struc = ['.Value'];
|
||||||
|
end
|
||||||
|
switch link.Type
|
||||||
|
case {'hard link', 'soft link'}
|
||||||
|
try
|
||||||
|
parent = strsplit(link.Value{1}, '/');
|
||||||
|
parent = strjoin(parent(1:end-1), '/');
|
||||||
|
parent_info = h5info(info.Filename, parent);
|
||||||
|
if isfield(parent_info, 'Attributes') && ~isempty(parent_info.Attributes)
|
||||||
|
for ii=1:numel(parent_info.Attributes)
|
||||||
|
if strcmp(parent_info.Attributes(ii).Name, 'MATLAB_class') && ~isempty(flag) && contains(flag, 'c')
|
||||||
|
% get pointer index
|
||||||
|
pnt_indx = strsplit(link.Value{1}, '_');
|
||||||
|
pnt_indx = str2double(pnt_indx(end));
|
||||||
|
target_add = [];
|
||||||
|
switch parent_info.Attributes(ii).Value{1}
|
||||||
|
case 'cell'
|
||||||
|
target_add = sprintf('{%d}', pnt_indx+1);
|
||||||
|
|
||||||
|
case 'structure array'
|
||||||
|
target_add = sprintf('(%d)', pnt_indx+1);
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
keyboard
|
||||||
|
end
|
||||||
|
target = [strrep(parent, '/', '.') target_struc target_add];
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if isempty(target)
|
||||||
|
target = [strrep(link.Value{1}(cut_start:end), '/', '.') target_struc];
|
||||||
|
end
|
||||||
|
|
||||||
|
evalc(['data', place, ' = data', target]);
|
||||||
|
|
||||||
|
catch
|
||||||
|
continue % postpone this link resolution
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'external link'
|
||||||
|
ext_link = absolute_path(link.Value{1}, info.Filename);
|
||||||
|
|
||||||
|
% make sure to reference the same variable in evalc!
|
||||||
|
if ~isempty(flag)
|
||||||
|
target_data = hdf5_load(ext_link, link.Value{2}, flag); %#ok<NASGU>
|
||||||
|
else
|
||||||
|
target_data = hdf5_load(ext_link, link.Value{2});
|
||||||
|
end
|
||||||
|
evalc(['data', place, ' = target_data']);
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('hdf5_load:assign_links', ...
|
||||||
|
strjoin({'Unknown link type at', place}));
|
||||||
|
end
|
||||||
|
|
||||||
|
resolved_links(ind) = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if all(resolved_links)
|
||||||
|
% all links have been assigned
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~any(resolved_links)
|
||||||
|
% none of the links has been assigned in this iteration
|
||||||
|
error('hdf5_load:assign_links', ...
|
||||||
|
strjoin({'Cannot assign link(s) at', ''}));
|
||||||
|
end
|
||||||
|
|
||||||
|
links = links(~resolved_links);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filepath = absolute_path(filepath, current_filepath)
|
||||||
|
if ~startsWith(filepath, '/')
|
||||||
|
path = fileparts(current_filepath);
|
||||||
|
filepath = fullfile(path, filepath);
|
||||||
|
end
|
||||||
|
|
||||||
|
function [startVal, nVals] = parse_range(valRange, maxVal)
|
||||||
|
if isempty(valRange) % empty
|
||||||
|
startVal = 1;
|
||||||
|
nVals = Inf;
|
||||||
|
|
||||||
|
elseif isscalar(valRange) % single value
|
||||||
|
if valRange <= -1
|
||||||
|
valRange = maxVal + valRange + 1;
|
||||||
|
end
|
||||||
|
startVal = valRange;
|
||||||
|
nVals = 1;
|
||||||
|
|
||||||
|
elseif isvector(valRange) && numel(valRange) == 2 % vector with two values
|
||||||
|
if valRange(1) <= -1
|
||||||
|
if isinf(valRange(1))
|
||||||
|
valRange(1) = 1; % = -Inf
|
||||||
|
else
|
||||||
|
valRange(1) = maxVal + valRange(1) + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
startVal = valRange(1);
|
||||||
|
|
||||||
|
if valRange(2) <= -1
|
||||||
|
if isinf(valRange(2))
|
||||||
|
valRange(2) = 1; % = -Inf
|
||||||
|
else
|
||||||
|
valRange(2) = maxVal + valRange(2) + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nVals = valRange(2) - startVal + 1;
|
||||||
|
|
||||||
|
else
|
||||||
|
error('hdf5_load:parse_range', ...
|
||||||
|
'A range should be specified with <= 2 parameters');
|
||||||
|
end
|
||||||
|
|
||||||
|
if startVal < 1 || startVal > maxVal || nVals < 1 || (nVals > maxVal && ~isinf(nVals))
|
||||||
|
error('hdf5_load:parse_range', ...
|
||||||
|
'The resulting range is out of data borders');
|
||||||
|
end
|
||||||
|
|
||||||
|
function data = read_enum(filename, location)
|
||||||
|
file_id = H5F.open(filename);
|
||||||
|
dset_id = H5D.open(file_id, location);
|
||||||
|
type_id = H5D.get_type(dset_id);
|
||||||
|
|
||||||
|
data = H5D.read(dset_id); % numerical member of enumeration
|
||||||
|
data = H5T.enum_nameof(type_id, data); % associated symbol name
|
||||||
|
|
||||||
|
H5T.close(type_id);
|
||||||
|
H5D.close(dset_id);
|
||||||
|
H5F.close(file_id);
|
||||||
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
%HDF5_MV_DATA Move data within an HDF5 file
|
||||||
|
% hdf5_mv_data creates a new (UNIX-like) hard link at loc_dest to the dataset at
|
||||||
|
% loc_origin and deletes the hard link to the dataset at loc_origin.
|
||||||
|
%
|
||||||
|
% file... HDF filename
|
||||||
|
% loc_origin... location of the data that needs to be moved
|
||||||
|
% loc_dest... destination and name of the new data
|
||||||
|
%
|
||||||
|
% EXAMPLE:
|
||||||
|
% % move dataset probe from root to group measurements
|
||||||
|
% hdf5_mv_data('./awesome_file.h5', 'probe', 'measurements/probe')
|
||||||
|
%
|
||||||
|
% Please notice that all groups and datasets have to exist before running
|
||||||
|
% the script!
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
function hdf5_mv_data( file, loc_origin, loc_dest)
|
||||||
|
import io.HDF.*
|
||||||
|
plist = 'H5P_DEFAULT';
|
||||||
|
|
||||||
|
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
|
||||||
|
|
||||||
|
gpath1 = strsplit(rm_delimiter(loc_origin), '/');
|
||||||
|
gid1 = add_groups(fileID, gpath1(1:end-1), plist, false);
|
||||||
|
|
||||||
|
gpath2 = strsplit(rm_delimiter(loc_dest), '/');
|
||||||
|
gid2 = add_groups(fileID, gpath2(1:end-1), plist, false);
|
||||||
|
|
||||||
|
try
|
||||||
|
datasetID = H5D.open(gid1{end}, gpath1{end});
|
||||||
|
dataset = true;
|
||||||
|
catch
|
||||||
|
gid1 = add_groups(fileID,gpath1,plist, false);
|
||||||
|
datasetID = gid1{end};
|
||||||
|
dataset = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
H5O.link(datasetID,gid2{end},gpath2{end},plist,plist);
|
||||||
|
if dataset
|
||||||
|
H5L.delete(gid1{end}, gpath1{end}, plist);
|
||||||
|
else
|
||||||
|
H5L.delete(gid1{end-1}, gpath1{end}, plist);
|
||||||
|
end
|
||||||
|
|
||||||
|
H5F.close(fileID);
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
%HDF5_RM_ATTR Delete attribute(s) from HDF file
|
||||||
|
%
|
||||||
|
% file... HDF filename
|
||||||
|
% loc... location within the HDF file
|
||||||
|
% attr_name... string or cell of strings containing the names of the
|
||||||
|
% obsolete attributes
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function hdf5_rm_attr( file, loc, attr_name)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
plist = 'H5P_DEFAULT';
|
||||||
|
% open file
|
||||||
|
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
|
||||||
|
|
||||||
|
% get group ID
|
||||||
|
gpath = strsplit(rm_delimiter(loc), '/');
|
||||||
|
gid = add_groups(fileID, gpath(1:end-1), plist, false);
|
||||||
|
|
||||||
|
% delete attributes
|
||||||
|
if iscell(attr_name)
|
||||||
|
for ii=1:length(attr_name)
|
||||||
|
H5A.delete(gid{end}, attr_name{ii})
|
||||||
|
end
|
||||||
|
else
|
||||||
|
H5A.delete(gid{end}, attr_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
%HDF5_RM_DATA Delete a dataset within an HDF5 file
|
||||||
|
%
|
||||||
|
% file... HDF filename
|
||||||
|
% loc... location of the dataset that needs to be removed
|
||||||
|
%
|
||||||
|
% Please notice that HDF5 does not free the space after removing datasets!
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function hdf5_rm_data( file, loc)
|
||||||
|
import io.HDF.*
|
||||||
|
plist = 'H5P_DEFAULT';
|
||||||
|
|
||||||
|
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
|
||||||
|
|
||||||
|
gpath1 = strsplit(rm_delimiter(loc), '/');
|
||||||
|
gid1 = add_groups(fileID, gpath1(1:end-1), plist, false);
|
||||||
|
|
||||||
|
H5L.delete(gid1{end}, gpath1{end}, plist);
|
||||||
|
|
||||||
|
H5F.close(fileID);
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: hdf5read_main.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.1 $ $Date: 2010/10/02 07:58:50 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Macro for reading HDF5 files written for example by the EIGER server
|
||||||
|
% program cbd_server
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% So far this is mainly a place holder for a thorough implementation.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read_set_default
|
||||||
|
% - fopen_until_exists
|
||||||
|
% - get_hdr_val
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% September 30th 2010: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [frame,vararg_remain] = hdf5read_main(filename,varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
import io.image_read
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import utils.get_hdr_val
|
||||||
|
|
||||||
|
% 0: no debug information
|
||||||
|
% 1: some feedback
|
||||||
|
% 2: a lot of information
|
||||||
|
debug_level = 0;
|
||||||
|
|
||||||
|
% initialize return argument
|
||||||
|
frame = struct('header',[], 'data',[]);
|
||||||
|
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
image_read_sub_help(mfilename,'h5');
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',value pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% set default values for the variable input arguments and parse the named
|
||||||
|
% parameters:
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
otherwise
|
||||||
|
% pass further arguments on to fopen_until_exists
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% try to open the data file
|
||||||
|
if (debug_level >= 1)
|
||||||
|
fprintf('Opening %s.\n',filename);
|
||||||
|
end
|
||||||
|
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
|
||||||
|
if (fid < 0)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
% close input data file
|
||||||
|
fclose(fid);
|
||||||
|
|
||||||
|
% get file header
|
||||||
|
hdr = hdf5info(filename);
|
||||||
|
|
||||||
|
% store part of the file header in the return argument
|
||||||
|
frame.header = {};
|
||||||
|
frame.header{end+1} = 'Exposure_time 1.0';
|
||||||
|
% add the file modification date to the header
|
||||||
|
dir_entry = dir(filename);
|
||||||
|
frame.header{end+1} = [ 'DateTime ' dir_entry.date ];
|
||||||
|
|
||||||
|
% read all data of first data set at once
|
||||||
|
frame.data = hdf5read(hdr.GroupHierarchy(1).Groups(1).Datasets(1));
|
||||||
|
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('%dx%dx%dx%s data bytes read\n',...
|
||||||
|
size(fdat,1),size(fdat,2),size(fdat,3),size(fdat,4));
|
||||||
|
end
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
%RM_DELIMITER makes sure that the path does not start with /
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function path = rm_delimiter(path)
|
||||||
|
% make sure that the path does not start with /
|
||||||
|
if strcmp(path(1), '/')
|
||||||
|
path = path(2:end);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
%SAVE2HDF5 saves matlab data to a Hierarchical Data Format file (hdf5)
|
||||||
|
%
|
||||||
|
% filename... full path to file, including file extension
|
||||||
|
% data... matlab structure or array or link
|
||||||
|
% data_name... needed if input data is not a matlab structure, needs
|
||||||
|
% to be given as name/value pair
|
||||||
|
%
|
||||||
|
% *optional*
|
||||||
|
% overwrite... replace existing file if it exists
|
||||||
|
% gpath... specify the group to which you want to append the data
|
||||||
|
% (only if data is an array); default root ('/')
|
||||||
|
% Attributes... structure of attributes; will be appended to current
|
||||||
|
% gpath
|
||||||
|
% comp... compression level; default 0 (no compression)
|
||||||
|
% creator... attribute in root; default 'ptycho_recons'
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% If you want to save a structure, everything declared within an 'Attributes'
|
||||||
|
% fieldname will be treated as an attribute to the current group.
|
||||||
|
% If you want to add attributes to a dataset, you have to define your
|
||||||
|
% data within .Value and your attributes within .Attributes.
|
||||||
|
%
|
||||||
|
% A simple structure could look like:
|
||||||
|
% h5_struc = [];
|
||||||
|
% h5_struc.probe_mask = ones(256,256);
|
||||||
|
% h5_struc.Attributes.probe_id = 1;
|
||||||
|
% h5_struc.measurement.n0.diff = fmag(:,:,1);
|
||||||
|
% h5_struc.measurement.n0.Attributes.detector = 0;
|
||||||
|
% h5_struc.measurement.n1.diff.Value = fmag(:,:,2);
|
||||||
|
% h5_struc.measurement.n1.diff.Attributes.slice = 2;
|
||||||
|
%
|
||||||
|
% fmag(:,:,1) will be written to dataset 'diff' in group '/measurement/n0'
|
||||||
|
% fmag(:,:,2) with attribute 'slice' will be written to dataset 'diff' in
|
||||||
|
% group '/measurement/n1'
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% EXAMPLES:
|
||||||
|
% -) if data is a matlab structure:
|
||||||
|
% save2hdf5('./awesome_file.h5', data);
|
||||||
|
% save2hdf5('./awesome_file.h5', data, 'overwrite', true);
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% -) if data is a matlab array:
|
||||||
|
% save2hdf5('./awesome_file.h5', data, 'data_name', data_name);
|
||||||
|
% save2hdf5('./awesome_file.h5', data, 'data_name', 'my_dataset',...
|
||||||
|
% 'gpath', 'group1/group2', 'Attributes', attr_struc);
|
||||||
|
%
|
||||||
|
% -) if data is a link:
|
||||||
|
% currently, only external links ('ext') and internal soft links
|
||||||
|
% ('int_soft') are supported
|
||||||
|
%
|
||||||
|
% external links have to be specified by a single string with
|
||||||
|
% 3 sections: '<link_type>:<file_path>:<target_object>'
|
||||||
|
%
|
||||||
|
% e.g.: 'ext:./awesome_file2.h5:/data'
|
||||||
|
% save2hdf5('./awesome_file.h5',...
|
||||||
|
% 'ext:./awesome_file2.h5:/data', 'data_name', data_name)
|
||||||
|
%
|
||||||
|
% will create a link called $data_name to dataset (or group) '/data'
|
||||||
|
% in './awesome_file2.h5'
|
||||||
|
%
|
||||||
|
% internal links have to be specified by a single string with
|
||||||
|
% 2 sections: '<link_type>:<target_object>'
|
||||||
|
%
|
||||||
|
% e.g.: 'int_soft:/data'
|
||||||
|
% save2hdf5('./awesome_file.h5',...
|
||||||
|
% 'int_soft:/data', 'data_name', data_name, 'gpath', 'g1/g2')
|
||||||
|
%
|
||||||
|
% will create a link called $data_name to dataset (or group) '/data'
|
||||||
|
% in '/g1/g2'
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% Please notice that structures are not supported as attributes, i.e.
|
||||||
|
% h5_struc = [];
|
||||||
|
% h5_struc.attr.probe.probe_id = 1;
|
||||||
|
%
|
||||||
|
% save2hdf5('./awesome_file.h5', h5_struc)
|
||||||
|
%
|
||||||
|
% will crash!
|
||||||
|
%
|
||||||
|
%
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function save2hdf5( filename, data, varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
% take care of input arguments
|
||||||
|
overwrite = false;
|
||||||
|
gpath_full = '';
|
||||||
|
attr = [];
|
||||||
|
data_name = '';
|
||||||
|
comp = 0;
|
||||||
|
creator = 'ptycho_recons';
|
||||||
|
iscopy = false;
|
||||||
|
extend_dim = 0;
|
||||||
|
extendable = false;
|
||||||
|
extend_offset = 0;
|
||||||
|
extend_maxdims = 0;
|
||||||
|
|
||||||
|
vararg = cell(0,0);
|
||||||
|
% parse the variable input arguments vararg = cell(0,0);
|
||||||
|
if ~isempty(varargin)
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch lower(name)
|
||||||
|
case 'data_name'
|
||||||
|
data_name = value;
|
||||||
|
case 'overwrite'
|
||||||
|
overwrite = value;
|
||||||
|
case 'gpath'
|
||||||
|
gpath_full = value;
|
||||||
|
case 'attr'
|
||||||
|
attr = value;
|
||||||
|
case 'comp'
|
||||||
|
comp = value;
|
||||||
|
case 'creator'
|
||||||
|
creator = value;
|
||||||
|
case 'iscopy'
|
||||||
|
iscopy = value;
|
||||||
|
case 'extend_dim'
|
||||||
|
extend_dim = value;
|
||||||
|
case 'extendable'
|
||||||
|
extendable = value;
|
||||||
|
case 'extend_offset'
|
||||||
|
extend_offset = value;
|
||||||
|
case 'extend_maxdims'
|
||||||
|
extend_maxdims = value;
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isstruct(data)
|
||||||
|
full_data = false;
|
||||||
|
else
|
||||||
|
full_data = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~isstruct(data) && isempty(data_name)
|
||||||
|
data_name = inputname(2);
|
||||||
|
if isempty(data_name)
|
||||||
|
error('Please specify the data_name.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if extendable && extend_dim
|
||||||
|
error('Extending the dimension of an unlimited dataset is currently not supported.');
|
||||||
|
end
|
||||||
|
|
||||||
|
plist = 'H5P_DEFAULT';
|
||||||
|
|
||||||
|
%%% create file if it does not exist
|
||||||
|
if exist(filename, 'file')&&~overwrite
|
||||||
|
fileID = H5F.open(filename,'H5F_ACC_RDWR',plist);
|
||||||
|
else
|
||||||
|
fileID = H5F.create(filename,'H5F_ACC_TRUNC','H5P_DEFAULT','H5P_DEFAULT');
|
||||||
|
if ~iscopy
|
||||||
|
write_attribute(fileID, filename, 'filename');
|
||||||
|
write_attribute(fileID, creator,'creator');
|
||||||
|
write_attribute(fileID, datestr(now),'file_time');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if full_data
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%% data as structure %%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
add_content(data, fileID, plist, comp, overwrite)
|
||||||
|
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%% data as array %%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
% prepare group handles
|
||||||
|
if ~isempty(gpath_full)
|
||||||
|
gpath = strsplit(rm_delimiter(gpath_full), '/');
|
||||||
|
gid = add_groups(fileID, gpath, plist, false);
|
||||||
|
else
|
||||||
|
gid{1} = fileID;
|
||||||
|
end
|
||||||
|
|
||||||
|
% write data to file
|
||||||
|
write_dataset(data, gid{end}, data_name, plist, comp, overwrite, [], extend_dim, extendable, extend_offset, extend_maxdims);
|
||||||
|
|
||||||
|
% append attributes
|
||||||
|
if ~isempty(attr)
|
||||||
|
attr_fn = fieldnames(attr);
|
||||||
|
for ii=1:length(attr_fn)
|
||||||
|
write_attribute(gid{end}, attr.(attr_fn{ii}), attr_fn{ii}, true);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% close handles
|
||||||
|
H5F.close(fileID);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
%WRITE_ATTRIBUTE write attribute data_name with value data to ID gid
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function write_attribute(gid, data, data_name, varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
if nargin > 3
|
||||||
|
safe = varargin{1};
|
||||||
|
else
|
||||||
|
safe = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
[datatypeID, data] = get_datatype(data);
|
||||||
|
if ischar(data)
|
||||||
|
% The ptycho C++ code expects strings as H5S_SCALAR, so we have to
|
||||||
|
% convert it
|
||||||
|
data = {data};
|
||||||
|
filetype = H5T.copy ('H5T_FORTRAN_S1');
|
||||||
|
H5T.set_size (filetype,'H5T_VARIABLE');
|
||||||
|
memtype = H5T.copy ('H5T_C_S1');
|
||||||
|
H5T.set_size (memtype, 'H5T_VARIABLE');
|
||||||
|
space = H5S.create ('H5S_SCALAR');
|
||||||
|
if safe
|
||||||
|
try
|
||||||
|
attr = H5A.create (gid, data_name, filetype, space, 'H5P_DEFAULT');
|
||||||
|
catch
|
||||||
|
H5A.delete(gid, data_name);
|
||||||
|
attr = H5A.create (gid, data_name, filetype, space, 'H5P_DEFAULT');
|
||||||
|
end
|
||||||
|
else
|
||||||
|
attr = H5A.create (gid, data_name, filetype, space, 'H5P_DEFAULT');
|
||||||
|
end
|
||||||
|
|
||||||
|
H5A.write (attr, memtype, data);
|
||||||
|
|
||||||
|
elseif iscell(data)
|
||||||
|
% If it is a cell, save it as 1D dataset
|
||||||
|
H5T.set_size(datatypeID,'H5T_VARIABLE');
|
||||||
|
agcv = H5ML.get_constant_value('H5S_UNLIMITED');
|
||||||
|
dspace = H5S.create_simple(1,numel(data),agcv);
|
||||||
|
|
||||||
|
plist = H5P.create('H5P_ATTRIBUTE_CREATE');
|
||||||
|
if safe
|
||||||
|
try
|
||||||
|
attr = H5A.create(gid,data_name,datatypeID,dspace,plist);
|
||||||
|
catch
|
||||||
|
H5A.delete(gid, data_name);
|
||||||
|
attr = H5A.create(gid,data_name,datatypeID,dspace,plist);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
attr = H5A.create(gid,data_name,datatypeID,dspace,plist);
|
||||||
|
end
|
||||||
|
H5A.write(attr,'H5ML_DEFAULT',data);
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
acpl = H5P.create('H5P_ATTRIBUTE_CREATE');
|
||||||
|
dims = size(data);
|
||||||
|
if length(dims)>1 && dims(2)~=1
|
||||||
|
if dims(1) == 1
|
||||||
|
space_id = H5S.create_simple(dims(1), dims(2), []);
|
||||||
|
else
|
||||||
|
space_id = H5S.create_simple(dims(1), dims, []);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
space_id = H5S.create('H5S_SCALAR');
|
||||||
|
end
|
||||||
|
if safe
|
||||||
|
try
|
||||||
|
attr = H5A.create(gid,data_name,datatypeID,space_id,acpl);
|
||||||
|
catch
|
||||||
|
H5A.delete(gid, data_name);
|
||||||
|
attr = H5A.create(gid,data_name,datatypeID,space_id,acpl);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
attr = H5A.create(gid,data_name,datatypeID,space_id,acpl);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
H5A.write(attr,'H5ML_DEFAULT',data)
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
H5A.close(attr);
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,370 @@
|
|||||||
|
%WRITE_DATASET write dataset data_name, containing data to ID gid
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function write_dataset(data, gid, data_name, plist, varargin)
|
||||||
|
import io.HDF.*
|
||||||
|
|
||||||
|
extend_data = false;
|
||||||
|
link = false;
|
||||||
|
link_type = '';
|
||||||
|
cellstrdata = false;
|
||||||
|
write_data = true;
|
||||||
|
|
||||||
|
if ~isempty(varargin)
|
||||||
|
comp = varargin{1};
|
||||||
|
else
|
||||||
|
comp = true;
|
||||||
|
end
|
||||||
|
if nargin > 5
|
||||||
|
overwrite = varargin{2};
|
||||||
|
else
|
||||||
|
overwrite = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargin > 6
|
||||||
|
data_attr = varargin{3};
|
||||||
|
else
|
||||||
|
data_attr = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargin > 7
|
||||||
|
extend_dim = varargin{4};
|
||||||
|
else
|
||||||
|
extend_dim = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargin > 8
|
||||||
|
extendable = varargin{5};
|
||||||
|
else
|
||||||
|
extendable = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargin > 9
|
||||||
|
extend_offset = varargin{6};
|
||||||
|
else
|
||||||
|
extend_offset = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if nargin > 10
|
||||||
|
extend_maxdims = varargin{7};
|
||||||
|
else
|
||||||
|
extend_maxdims = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
[datatype, data] = get_datatype(data);
|
||||||
|
filespaceID = [];
|
||||||
|
|
||||||
|
function create_dataspace()
|
||||||
|
|
||||||
|
if extendable
|
||||||
|
unlimited = H5ML.get_constant_value('H5S_UNLIMITED');
|
||||||
|
dims_max = repmat(unlimited, 1, numel(dims));
|
||||||
|
else
|
||||||
|
dims_max = dims;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~extend_dim
|
||||||
|
if ~extendable
|
||||||
|
dataspaceID = H5S.create_simple(length(dims), fliplr(dims), fliplr(dims_max));
|
||||||
|
else
|
||||||
|
try
|
||||||
|
datasetID = H5D.open(gid, data_name);
|
||||||
|
filespaceID = H5D.get_space(datasetID);
|
||||||
|
[~, spaceDims] = H5S.get_simple_extent_dims(filespaceID);
|
||||||
|
% spaceDims = fliplr(spaceDims);
|
||||||
|
|
||||||
|
start = ones(1,numel(dims))-1;
|
||||||
|
count = dims;
|
||||||
|
|
||||||
|
stride = ones(1, numel(start));
|
||||||
|
boundsEnd = start + (count).*stride;
|
||||||
|
new_dims = fliplr(boundsEnd);
|
||||||
|
H5S.close(filespaceID);
|
||||||
|
H5D.set_extent(datasetID,new_dims);
|
||||||
|
filespaceID = H5D.get_space(datasetID);
|
||||||
|
H5S.select_hyperslab(filespaceID, 'H5S_SELECT_SET', fliplr(start), fliplr(stride), ...
|
||||||
|
fliplr(count), ones(1,length(start)));
|
||||||
|
|
||||||
|
dataspaceID = H5S.create_simple(numel(count),fliplr(count),[]);
|
||||||
|
|
||||||
|
extend_data = true;
|
||||||
|
|
||||||
|
catch
|
||||||
|
dataspaceID = H5S.create_simple(length(dims), fliplr(dims), fliplr(dims_max));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
else
|
||||||
|
try
|
||||||
|
datasetID = H5D.open(gid, data_name);
|
||||||
|
filespaceID = H5D.get_space(datasetID);
|
||||||
|
[~, spaceDims] = H5S.get_simple_extent_dims(filespaceID);
|
||||||
|
spaceDims = fliplr(spaceDims);
|
||||||
|
if extend_offset
|
||||||
|
start = [ones(1,extend_dim-1) extend_offset+1]-1;
|
||||||
|
else
|
||||||
|
start = [ones(1,extend_dim-1) spaceDims(end)+1]-1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if numel(spaceDims) > numel(dims)
|
||||||
|
count = [dims 1];
|
||||||
|
else
|
||||||
|
count = dims;
|
||||||
|
end
|
||||||
|
stride = ones(1, numel(start));
|
||||||
|
boundsEnd = start + (count-1).*stride;
|
||||||
|
if extend_maxdims
|
||||||
|
boundsStart = spaceDims;
|
||||||
|
boundsStart(end) = extend_maxdims;
|
||||||
|
else
|
||||||
|
boundsStart = spaceDims;
|
||||||
|
end
|
||||||
|
new_dims = fliplr(max(boundsStart,boundsEnd+1));
|
||||||
|
H5S.close(filespaceID);
|
||||||
|
H5D.set_extent(datasetID,new_dims);
|
||||||
|
filespaceID = H5D.get_space(datasetID);
|
||||||
|
H5S.select_hyperslab(filespaceID, 'H5S_SELECT_SET', fliplr(start), fliplr(stride), ...
|
||||||
|
fliplr(count), ones(1,length(start)));
|
||||||
|
|
||||||
|
dataspaceID = H5S.create_simple(numel(count),fliplr(count),[]);
|
||||||
|
|
||||||
|
extend_data = true;
|
||||||
|
|
||||||
|
|
||||||
|
catch
|
||||||
|
unlimited = H5ML.get_constant_value('H5S_UNLIMITED');
|
||||||
|
maxdims = [dims(1:extend_dim-1) unlimited];
|
||||||
|
% maxdims = repmat(-1, 1, extend_dim);
|
||||||
|
if numel(maxdims) > numel(dims)
|
||||||
|
dims = [dims 1];
|
||||||
|
end
|
||||||
|
dataspaceID = H5S.create_simple(length(dims), [fliplr(dims)], fliplr(maxdims));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if strcmp(datatype, 'complex')
|
||||||
|
|
||||||
|
%%% prepare compound dataset for complex input data
|
||||||
|
dims = size(data);
|
||||||
|
|
||||||
|
data_temp = data;
|
||||||
|
data = [];
|
||||||
|
data.r = real(data_temp);
|
||||||
|
data.i = imag(data_temp);
|
||||||
|
|
||||||
|
create_dataspace();
|
||||||
|
|
||||||
|
% Create the required data types
|
||||||
|
complexType = H5T.copy(get_datatype(data.r));
|
||||||
|
sz = H5T.get_size(complexType);
|
||||||
|
|
||||||
|
% Create the compound datatype for memory.
|
||||||
|
datatypeID = H5T.create ('H5T_COMPOUND', 2*sz);
|
||||||
|
H5T.insert (datatypeID, 'r',0, complexType);
|
||||||
|
H5T.insert (datatypeID, 'i',sz, complexType);
|
||||||
|
memtype = datatypeID;
|
||||||
|
|
||||||
|
data_attr.MATLAB_class = 'complex';
|
||||||
|
|
||||||
|
|
||||||
|
elseif ischar(data)
|
||||||
|
% check if char is a link
|
||||||
|
ch_entrs = strsplit(data, ':');
|
||||||
|
if length(ch_entrs) >= 2
|
||||||
|
link = true;
|
||||||
|
if strcmp(ch_entrs{1}, 'ext')
|
||||||
|
% prepare external link
|
||||||
|
link_type = 'ext';
|
||||||
|
elseif strcmp(ch_entrs{1}, 'int_soft')
|
||||||
|
% prepare internal soft link
|
||||||
|
link_type = 'int_soft';
|
||||||
|
elseif strcmp(ch_entrs{1}, 'int_hard')
|
||||||
|
% prepare internal hard link
|
||||||
|
link_type = 'int_hard';
|
||||||
|
end
|
||||||
|
else
|
||||||
|
data = {data};
|
||||||
|
datatypeID = H5T.copy ('H5T_FORTRAN_S1');
|
||||||
|
H5T.set_size (datatypeID,'H5T_VARIABLE');
|
||||||
|
memtype = H5T.copy ('H5T_C_S1');
|
||||||
|
H5T.set_size (memtype, 'H5T_VARIABLE');
|
||||||
|
dataspaceID = H5S.create ('H5S_SCALAR');
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif iscell(data) || strcmp(datatype, 'char_array')
|
||||||
|
|
||||||
|
|
||||||
|
if iscellstr(data)
|
||||||
|
cellstrdata = true;
|
||||||
|
datatypeID = H5T.copy ('H5T_C_S1');
|
||||||
|
H5T.set_size (datatypeID, 'H5T_VARIABLE');
|
||||||
|
|
||||||
|
dgcv = H5ML.get_constant_value('H5S_UNLIMITED');
|
||||||
|
dataspaceID = H5S.create_simple(1,numel(data),dgcv);
|
||||||
|
memtype = datatypeID;
|
||||||
|
plist_cr = H5P.create('H5P_DATASET_CREATE');
|
||||||
|
H5P.set_chunk(plist_cr,1);
|
||||||
|
if strcmp(datatype, 'char_array')
|
||||||
|
data_attr.MATLAB_class = 'char_array';
|
||||||
|
end
|
||||||
|
else
|
||||||
|
write_data = false;
|
||||||
|
fn_names = cell(1,length(data));
|
||||||
|
cell_gid = add_groups(gid, data_name, plist, true);
|
||||||
|
for ii=1:length(data)
|
||||||
|
fn_names{ii} = sprintf([data_name '_%d'],ii-1);
|
||||||
|
write_dataset(data{ii}, cell_gid, fn_names{ii}, plist, comp, overwrite);
|
||||||
|
end
|
||||||
|
write_attribute(cell_gid, 'cell', 'MATLAB_class');
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif isstruct(data)
|
||||||
|
|
||||||
|
write_data = false;
|
||||||
|
struct_gid = add_groups(gid, data_name, plist, true);
|
||||||
|
add_content(data, struct_gid, plist, comp, overwrite);
|
||||||
|
|
||||||
|
else
|
||||||
|
datatypeID = H5T.copy(datatype);
|
||||||
|
dims = size(data);
|
||||||
|
if isfield(data_attr, 'save2hdf5DataShape')
|
||||||
|
dims = data_attr.save2hdf5DataShape;
|
||||||
|
end
|
||||||
|
|
||||||
|
% prepare dataspace
|
||||||
|
create_dataspace();
|
||||||
|
|
||||||
|
memtype = 'H5ML_DEFAULT';
|
||||||
|
end
|
||||||
|
|
||||||
|
%%% create groups and write data
|
||||||
|
if comp && ~iscell(data) && ~ischar(data) && write_data || extend_dim || extendable
|
||||||
|
% define compression and chunk size
|
||||||
|
plist_ch = H5P.create('H5P_DATASET_CREATE');
|
||||||
|
if length(dims)>=3
|
||||||
|
chunk_dims = [dims(1) dims(2) ones(1, numel(dims)-2)];
|
||||||
|
else
|
||||||
|
chunk_dims = dims;
|
||||||
|
end
|
||||||
|
|
||||||
|
h5_chunk_dims = fliplr(chunk_dims);
|
||||||
|
H5P.set_chunk(plist_ch,h5_chunk_dims);
|
||||||
|
H5P.set_shuffle(plist_ch);
|
||||||
|
if comp
|
||||||
|
H5P.set_deflate(plist_ch,comp);
|
||||||
|
end
|
||||||
|
|
||||||
|
% Try to create a new dataset. If it exists, try to open it.
|
||||||
|
try
|
||||||
|
if ~extend_data
|
||||||
|
if cellstrdata
|
||||||
|
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist_cr);
|
||||||
|
else
|
||||||
|
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist_ch);
|
||||||
|
% create_dataspace();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
if ~overwrite
|
||||||
|
try
|
||||||
|
datasetID = H5D.open(gid, data_name);
|
||||||
|
catch
|
||||||
|
error('Could not create dataset %s! Try a different name or overwrite the already existing file.', data_name);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
keyboard
|
||||||
|
error('Dataset %s already exists! Try a different name or overwrite the already existing file.', data_name);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ~link && write_data
|
||||||
|
% Same as above but without compression:
|
||||||
|
% Try to create a new dataset. If it exists, try to open it.
|
||||||
|
try
|
||||||
|
if cellstrdata
|
||||||
|
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist_cr);
|
||||||
|
else
|
||||||
|
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist);
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
if ~overwrite
|
||||||
|
try
|
||||||
|
datasetID = H5D.open(gid, data_name);
|
||||||
|
catch
|
||||||
|
error('Could not open dataset %s! Try a different name or overwrite the already existing file.', data_name);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error('Dataset %s already exists! Try a different name or overwrite the already existing file.', data_name);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if write_data
|
||||||
|
% write data to disk or link data
|
||||||
|
|
||||||
|
if ~link && ~extend_data
|
||||||
|
H5D.write(datasetID,memtype,'H5S_ALL','H5S_ALL',plist ,data);
|
||||||
|
% append attributes if needed
|
||||||
|
if ~isempty(data_attr)
|
||||||
|
fn = fieldnames(data_attr);
|
||||||
|
for ii=1:length(fn)
|
||||||
|
write_attribute(datasetID, data_attr.(fn{ii}), fn{ii}, true);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
H5D.close(datasetID);
|
||||||
|
elseif extend_data
|
||||||
|
H5D.write(datasetID,memtype,dataspaceID, filespaceID, plist, data)
|
||||||
|
elseif strcmp(link_type, 'ext')
|
||||||
|
H5L.create_external(ch_entrs{2},ch_entrs{3},gid,data_name,plist,plist);
|
||||||
|
elseif strcmp(link_type, 'int_hard')
|
||||||
|
error('Currently not supported, sorry!')
|
||||||
|
% H5L.create_hard(ch_entrs{2},'g3',gid1,'g4',plist,plist);
|
||||||
|
elseif strcmp(link_type, 'int_soft')
|
||||||
|
H5L.create_soft(ch_entrs{2},gid,data_name,plist,plist);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
% Call function without arguments for a detailed explanation of its use
|
||||||
|
|
||||||
|
% Filename: $RCSfile: common_header_value.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.7 $ $Date: 2013/01/25 10:22:26 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% return header information which are common to most file formats used at
|
||||||
|
% the cSAXS beamline
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - get_hdr_val
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% September 30th 2010:
|
||||||
|
% add HDF5
|
||||||
|
%
|
||||||
|
% October 3rd 2008:
|
||||||
|
% update FLI date-field since version 1.20 provides a time stamp string
|
||||||
|
%
|
||||||
|
% August 28th 2008:
|
||||||
|
% correct error display for unknown extensions,
|
||||||
|
% add extension .dat
|
||||||
|
%
|
||||||
|
% July 17th 2008: add mar extension
|
||||||
|
%
|
||||||
|
% May 7th 2008: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [value] = common_header_value(header,extension,signature)
|
||||||
|
import io.image_read
|
||||||
|
import utils.get_hdr_val
|
||||||
|
|
||||||
|
% initialize return value
|
||||||
|
value = [];
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (nargin ~= 3)
|
||||||
|
common_header_value_help();
|
||||||
|
error('invalid number of input arguments');
|
||||||
|
end
|
||||||
|
|
||||||
|
switch extension
|
||||||
|
case 'cbf'
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'Exposure_time',' %f',1);
|
||||||
|
case 'Date'
|
||||||
|
% The date is available in the Pilatus comments, without
|
||||||
|
% any signature. Searching for the 20 string will fail
|
||||||
|
% beyond the year 2099
|
||||||
|
value = [ '20' get_hdr_val(header,'# 20',' %[^\r]',1) ];
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case {'h5', 'hdf5'}
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'Exposure_time',' %f',1);
|
||||||
|
case 'Date'
|
||||||
|
value = get_hdr_val(header,'DateTime',' %[^\n]',1);
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case 'dat'
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'Exposure_time',' %f',1);
|
||||||
|
case 'Date'
|
||||||
|
value = get_hdr_val(header,'DateTime',' %[^\n]',1);
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case 'edf'
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'count_time',' = %f',1);
|
||||||
|
case 'Date'
|
||||||
|
value = get_hdr_val(header,'Date',' = %[^;]',1);
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case {'mar','mccd'}
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'ExposureTime_ms',' %f',1)/1000;
|
||||||
|
case 'Date'
|
||||||
|
value = get_hdr_val(header,'DateTime',' %[^\n]',1);
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case {'mat'}
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'Exposure_time',' %f',1);
|
||||||
|
case 'Date'
|
||||||
|
value = get_hdr_val(header,'DateTime',' %[^\n]',1);
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case 'raw'
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'exptimesec',' %f',1);
|
||||||
|
case 'Date'
|
||||||
|
value = get_hdr_val(header,'version',' %[^\n]',1);
|
||||||
|
if (version < 1.20)
|
||||||
|
value = get_hdr_val(header,'FileTimestamp',' %[^\n]',1);
|
||||||
|
else
|
||||||
|
value = get_hdr_val(header,'timestamp_string',' %[^\n]',1);
|
||||||
|
end
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case 'spe'
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'exposure',' %f',1);
|
||||||
|
case 'Date'
|
||||||
|
value = [ get_hdr_val(header,'date',' %[^\n]',1)'; ' ';
|
||||||
|
get_hdr_val(header,'ExperimentTimeLocal',' %[^\n]',1)' ]';
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
case {'tif', 'tiff'}
|
||||||
|
switch signature
|
||||||
|
case 'ExposureTime'
|
||||||
|
value = get_hdr_val(header,'Exposure_time',' %f',1);
|
||||||
|
case 'Date'
|
||||||
|
value = get_hdr_val(header,'DateTime',' %[^\n]',1);
|
||||||
|
otherwise
|
||||||
|
error('unknown signature %s for extension %s',...
|
||||||
|
signature,extension);
|
||||||
|
end
|
||||||
|
otherwise
|
||||||
|
common_header_value_help();
|
||||||
|
error('unknown extension ''%s''',extension);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function [] = common_header_value_help()
|
||||||
|
|
||||||
|
fprintf('Usage:\n');
|
||||||
|
fprintf('[value]=%s(header,extension,signature);',mfilename);
|
||||||
|
fprintf('header and extension are returned by image_read\n');
|
||||||
|
fprintf('The following signatures are recognized:\n');
|
||||||
|
fprintf('ExposureTime exposure time in seconds\n');
|
||||||
|
fprintf('Date date string in detector specific format\n');
|
||||||
|
fprintf('Example:\n');
|
||||||
|
fprintf('exp_time_sec=common_header_value(frame.header{1},frame.extension{1},''ExposureTime'');\n');
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
% convert_radial_2_dat converts all radial integration mat files in
|
||||||
|
% readpahtmask into dat files, pauses 10 minutes and repeats
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% **readpathmask A cell containing the input file string masks
|
||||||
|
% **outpathmask A cel containint the corresponding output
|
||||||
|
% directories
|
||||||
|
%
|
||||||
|
% Example:
|
||||||
|
% readpathmask{1} = '~/Data10/analysis/radial_integration/*.mat';
|
||||||
|
% outpathmask{1} = '~/Data10/analysis/radial_integration_dat/';
|
||||||
|
% readpathmask{2} = '~/Data10/analysis/radial_integration_waxs/*.mat';
|
||||||
|
% outpathmask{2} = '~/Data10/analysis/radial_integration_waxs_dat/';
|
||||||
|
% convert_radial_2_dat(readpathmask, outpathmask)
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2019 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
% clear
|
||||||
|
|
||||||
|
% readpathmask{1} = '~/Data10/analysis/radial_integration/*.mat';
|
||||||
|
% outpathmask{1} = '~/Data10/analysis/radial_integration_dat/';
|
||||||
|
%
|
||||||
|
% readpathmask{2} = '~/Data10/analysis/radial_integration_waxs/*.mat';
|
||||||
|
% outpathmask{2} = '~/Data10/analysis/radial_integration_waxs_dat/';
|
||||||
|
|
||||||
|
function convert_radial_2_dat(readpathmask, outpathmask)
|
||||||
|
|
||||||
|
while 1==1
|
||||||
|
for ii = 1:numel(readpathmask)
|
||||||
|
if ~exist(outpathmask{ii},'dir')
|
||||||
|
mkdir(outpathmask{ii})
|
||||||
|
end
|
||||||
|
files = dir(readpathmask{ii});
|
||||||
|
for jj = 1:numel(files)
|
||||||
|
currentradial = fullfile(files(jj).folder,files(jj).name);
|
||||||
|
[auxpath, auxname, auxext] = fileparts(currentradial);
|
||||||
|
outputradial = fullfile(outpathmask{ii},[auxname '.dat']);
|
||||||
|
s = load(currentradial);
|
||||||
|
|
||||||
|
save_data = [s.q.', ...
|
||||||
|
reshape(s.I_all , [size(s.I_all,1) size(s.I_all,2)*size(s.I_all,3) ]) , ...
|
||||||
|
reshape(s.I_std , [size(s.I_std,1) size(s.I_std,2)*size(s.I_std,3) ]) , ...
|
||||||
|
reshape(s.norm_sum , [size(s.norm_sum,1) size(s.norm_sum,2)*size(s.norm_sum,3) ]) , ...
|
||||||
|
];
|
||||||
|
|
||||||
|
fprintf('Saving %s\n',outputradial);
|
||||||
|
save( outputradial , 'save_data', '-ascii','-double');
|
||||||
|
end
|
||||||
|
clear files
|
||||||
|
end
|
||||||
|
fprintf('Pausing 10 minutes\n')
|
||||||
|
pause(60*10)
|
||||||
|
end
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
function [rgb_data] = convert_to_rgb(data)
|
||||||
|
%Convert complex data into rgb image showing both magnitude and phase
|
||||||
|
% Detailed explanation goes here
|
||||||
|
|
||||||
|
import math.sp_quantile
|
||||||
|
|
||||||
|
[W,H] = size(data);
|
||||||
|
adata = abs(data);
|
||||||
|
|
||||||
|
alpha = 1e-3;
|
||||||
|
tmp= sort(adata(:));
|
||||||
|
MAX = tmp(ceil(end*(1-alpha)));
|
||||||
|
ind = adata > MAX;
|
||||||
|
data(ind) = MAX * data(ind) ./ abs(data(ind));
|
||||||
|
adata = abs(data);
|
||||||
|
range = sp_quantile(adata(:), [1e-2, 1-1e-2],10);
|
||||||
|
adata = (adata - range(1) ) ./ ( range(2) - range(1) );
|
||||||
|
|
||||||
|
ang_data = angle(data);
|
||||||
|
hue = mod(ang_data+2.5*pi, 2*pi)/(2*pi);
|
||||||
|
hsv_data = [ hue(:) , ones(W*H,1), adata(:) ];
|
||||||
|
|
||||||
|
hsv_data = min(max(0, hsv_data),1);
|
||||||
|
|
||||||
|
|
||||||
|
rgb_data = hsv2rgb(hsv_data);
|
||||||
|
|
||||||
|
rgb_data = reshape(rgb_data, W,H,3);
|
||||||
|
rgb_data = min(1,rgb_data);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
% Call function without arguments for a detailed explanation of its use
|
||||||
|
|
||||||
|
% Filename: $RCSfile: datread.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.2 $ $Date: 2009/02/20 19:33:01 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Macro for reading .dat files in self-defined data formats
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read_set_default
|
||||||
|
% - fopen_until_exists
|
||||||
|
% - get_hdr_val
|
||||||
|
% - compiling cbf_uncompress.c increases speed but is not mandatory
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% February 18th 2009: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [frame,vararg_remain] = datread(filename,varargin)
|
||||||
|
import io.*
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import utils.get_hdr_val
|
||||||
|
import utils.char_to_cellstr
|
||||||
|
|
||||||
|
% 0: no debug information
|
||||||
|
% 1: some feedback
|
||||||
|
% 2: a lot of information
|
||||||
|
debug_level = 0;
|
||||||
|
|
||||||
|
% initialize return argument
|
||||||
|
frame = struct('header',[], 'data',[]);
|
||||||
|
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
image_read_sub_help(mfilename,'cbf');
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',value pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% set default values for the variable input arguments and parse the named
|
||||||
|
% parameters:
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
otherwise
|
||||||
|
% pass further arguments on to fopen_until_exists
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% expected maximum length for the text header
|
||||||
|
max_header_length = 4096;
|
||||||
|
|
||||||
|
% end-of-header signature
|
||||||
|
eoh_signature = [ '# end-of-header' char(10) ];
|
||||||
|
|
||||||
|
% try to open the data file
|
||||||
|
if (debug_level >= 1)
|
||||||
|
fprintf('Opening %s.\n',filename);
|
||||||
|
end
|
||||||
|
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
|
||||||
|
if (fid < 0)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
% read all data at once
|
||||||
|
[fdat,fcount] = fread(fid,'uint8=>uint8');
|
||||||
|
|
||||||
|
% close input data file
|
||||||
|
fclose(fid);
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('%d data bytes read\n',fcount);
|
||||||
|
end
|
||||||
|
|
||||||
|
% files with header start with a has sign, otherwise just a series of
|
||||||
|
% numbers is expected
|
||||||
|
if (~strcmp(fdat(1),'#'))
|
||||||
|
% convert the array to cell strings
|
||||||
|
cell_values = char_to_cellstr( char(fdat)' );
|
||||||
|
% convert the strings to double precision values
|
||||||
|
frame.data = zeros(length(cell_values),1);
|
||||||
|
for (ind = 1:length(cell_values))
|
||||||
|
frame.data(ind) = str2double(cell_values{ind});
|
||||||
|
end
|
||||||
|
|
||||||
|
% No header information are available.
|
||||||
|
% Fake exposure time information to avoid problems in other
|
||||||
|
% macros.
|
||||||
|
frame.header{end+1} = 'Exposure_time 1.0';
|
||||||
|
% add the file modification date to the header
|
||||||
|
dir_entry = dir(filename);
|
||||||
|
frame.header{end+1} = [ 'DateTime ' dir_entry.date ];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% search for end of header signature within the expected maximum length of
|
||||||
|
% a header
|
||||||
|
end_of_header_pos = ...
|
||||||
|
strfind( fdat(1:min(max_header_length,length(fdat)))',...
|
||||||
|
eoh_signature );
|
||||||
|
if (length(end_of_header_pos) < 1)
|
||||||
|
error( [ filename,': no header end signature found' ] );
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Header length is %d bytes.\n',end_of_header_pos -1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% return the complete header as lines of a cell array
|
||||||
|
frame.header = char_to_cellstr( char(fdat(1:(end_of_header_pos-1))') );
|
||||||
|
|
||||||
|
% increase the index to the first data byte
|
||||||
|
end_of_header_pos = end_of_header_pos + length(eoh_signature);
|
||||||
|
|
||||||
|
% check for information on the various dimensions in ascending speed order
|
||||||
|
dim1 = get_hdr_val(frame.header,'dim2','%d',1);
|
||||||
|
dim2 = get_hdr_val(frame.header,'dim1','%d',1);
|
||||||
|
dim3 = get_hdr_val(frame.header,'number-of-exposures','%d',1);
|
||||||
|
dim4 = get_hdr_val(frame.header,'channels','%d',1);
|
||||||
|
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Frame dimensions are %d x %d % %d x %d.\n', ...
|
||||||
|
dim4,dim3,dim2,dim1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% store the numbers in the array, fastest axis first
|
||||||
|
frame.data = zeros(dim4,dim3,dim2,dim1);
|
||||||
|
|
||||||
|
% convert the strings to double precision values
|
||||||
|
data_1d = sscanf(char(fdat(end_of_header_pos:end))','%f');
|
||||||
|
frame.no_of_el_read = length(data_1d);
|
||||||
|
if (length(data_1d) > numel(frame.data))
|
||||||
|
frame.data = zeros(dim4,dim3,dim2,ceil(length(data_1d)/(dim4*dim3*dim2)));
|
||||||
|
end
|
||||||
|
frame.data(1:frame.no_of_el_read) = data_1d;
|
||||||
|
|
||||||
+234
@@ -0,0 +1,234 @@
|
|||||||
|
% Call function without arguments for a detailed explanation of its use
|
||||||
|
|
||||||
|
% Filename: $RCSfile: edfread.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.1 $ $Date: 2008/06/10 17:05:14 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Macro for reading ESRF Data Format (EDF) files written by the
|
||||||
|
% Pilatus detector control program camserver.
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Currently this routine supports only the subset of EDF features needed to
|
||||||
|
% read the Pilatus detector data.
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - fopen_until_exists
|
||||||
|
% - get_hdr_val
|
||||||
|
% - image_read_set_default
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% May 9th 2008: 1st version after redesign
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [frame,vararg_remain] = edfread(filename,varargin)
|
||||||
|
import io.*
|
||||||
|
import utils.char_to_cellstr
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import utils.get_hdr_val
|
||||||
|
|
||||||
|
% 0: no debug information
|
||||||
|
% 1: some feedback
|
||||||
|
% 2: a lot of information
|
||||||
|
debug_level = 0;
|
||||||
|
|
||||||
|
% initialize return argument
|
||||||
|
frame = struct('header',[], 'data',[]);
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
image_read_sub_help(mfilename,'edf');
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% set default values for the variable input arguments and parse the named
|
||||||
|
% parameters:
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
otherwise
|
||||||
|
% pass further arguments on to fopen_until_exists
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% expected maximum length for the text header
|
||||||
|
max_header_length = 4096;
|
||||||
|
|
||||||
|
|
||||||
|
% try to open the data file
|
||||||
|
if (debug_level >= 1)
|
||||||
|
fprintf('Opening %s.\n',filename);
|
||||||
|
end
|
||||||
|
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
|
||||||
|
if (fid < 0)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
% read all data at once
|
||||||
|
[fdat,fcount] = fread(fid,'uint8=>uint8');
|
||||||
|
|
||||||
|
% close input data file
|
||||||
|
fclose(fid);
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('%d data bytes read\n',fcount);
|
||||||
|
end
|
||||||
|
|
||||||
|
% search for end of header signature within the expected maximum length of
|
||||||
|
% a header
|
||||||
|
end_of_header_pos = 1024;
|
||||||
|
max_pos = min( max_header_length,length(fdat) );
|
||||||
|
|
||||||
|
while ((end_of_header_pos < max_pos) && (fdat(end_of_header_pos-1) ~= '}'))
|
||||||
|
end_of_header_pos = end_of_header_pos +1024;
|
||||||
|
end
|
||||||
|
if (end_of_header_pos >= max_pos)
|
||||||
|
error('no header end signature found');
|
||||||
|
end
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Header length is %d bytes.\n',end_of_header_pos);
|
||||||
|
end
|
||||||
|
data_length = fcount - end_of_header_pos;
|
||||||
|
|
||||||
|
% convert the header to lines of a cell array
|
||||||
|
frame.header = char_to_cellstr( char(fdat(1:(end_of_header_pos-1))') );
|
||||||
|
|
||||||
|
% check for opening parenthesis
|
||||||
|
if (frame.header{1} ~= '{')
|
||||||
|
error([filename ': EDF start ,''{'' not found in first line ''' ...
|
||||||
|
frame.header{1} '''' ]);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% extract the mandatory information for data extraction from the header:
|
||||||
|
byte_order = get_hdr_val(frame.header,'ByteOrder',' = %s',1);
|
||||||
|
dim1 = get_hdr_val(frame.header,'Dim_1',' = %d',1);
|
||||||
|
dim2 = get_hdr_val(frame.header,'Dim_2',' = %d',1);
|
||||||
|
data_type = get_hdr_val(frame.header,'DataType',' = %s',1);
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Byte order is %s\n',byte_order);
|
||||||
|
fprintf('Frame dimensions are %d x %d.\n',dim2,dim1);
|
||||||
|
fprintf('Data type is %s\n',data_type);
|
||||||
|
end
|
||||||
|
|
||||||
|
% determine number of bytes per pixel
|
||||||
|
switch data_type
|
||||||
|
case 'UnsignedByte',
|
||||||
|
bytes_per_pixel = 1;
|
||||||
|
data_class = 'uint8';
|
||||||
|
case 'UnsignedShort',
|
||||||
|
bytes_per_pixel = 2;
|
||||||
|
data_class = 'uint16';
|
||||||
|
case {'SignedInteger','UnsignedInteger','UnsignedInt','UnsignedLong'}
|
||||||
|
bytes_per_pixel = 4;
|
||||||
|
data_class = 'uint32';
|
||||||
|
case {'Float','FloatValue','Real'}
|
||||||
|
bytes_per_pixel = 4;
|
||||||
|
data_class = 'single';
|
||||||
|
case 'DoubleValue'
|
||||||
|
bytes_per_pixel = 8;
|
||||||
|
data_class = 'double';
|
||||||
|
otherwise
|
||||||
|
error('unsupported data type %s',data_type);
|
||||||
|
end
|
||||||
|
no_of_bytes = bytes_per_pixel * dim1 * dim2;
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('%d bytes per pixel, %d in total expected, %d available\n',...
|
||||||
|
bytes_per_pixel,no_of_bytes,data_length);
|
||||||
|
end
|
||||||
|
|
||||||
|
% check length of available data
|
||||||
|
if (no_of_bytes > data_length)
|
||||||
|
error('%d data bytes expected, %d are available',...
|
||||||
|
no_of_bytes,data_length);
|
||||||
|
end
|
||||||
|
|
||||||
|
% compare file with machine byte order, swap if necessary
|
||||||
|
[str,maxsize,endian] = computer;
|
||||||
|
if (((strcmp(byte_order,'HighByteFirst')) && (endian == 'L')) || ...
|
||||||
|
((strcmp(byte_order,'LowByteFirst')) && (endian == 'H')))
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('Machine byte order is %s: swapping data bytes\n',...
|
||||||
|
endian,bytes_per_pixel);
|
||||||
|
end
|
||||||
|
dat = fdat(end_of_header_pos+1:end_of_header_pos+no_of_bytes);
|
||||||
|
dat = reshape(dat,bytes_per_pixel,[]);
|
||||||
|
dat = flipud(dat);
|
||||||
|
fdat(end_of_header_pos+1:end_of_header_pos+no_of_bytes) = dat(:);
|
||||||
|
end
|
||||||
|
|
||||||
|
% extract the frame from the binary data
|
||||||
|
[frame.data] = ...
|
||||||
|
double(reshape(typecast(fdat(end_of_header_pos+1:end_of_header_pos+no_of_bytes),...
|
||||||
|
data_class),...
|
||||||
|
dim1,dim2));
|
||||||
|
|
||||||
|
|
||||||
|
% conversion to standard view on Pilatus 2M data at the SLS/cSAXS beamline
|
||||||
|
% if (~original_orientation)
|
||||||
|
% % this is slow, even slower is fliplr(flipud(frame.'))
|
||||||
|
% frame.data = frame.data(end:-1:1,end:-1:1)';
|
||||||
|
% end
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
% This script is to plot, correct and export solution SAXS data to SASfit
|
||||||
|
% accounts for transmission, time and thickness correction
|
||||||
|
% scales the data to a calibration factor
|
||||||
|
% background correction, removal of bad pixels
|
||||||
|
% not suitable for anisotropic data
|
||||||
|
% saves the output to be used in SASfit
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
% EDIT HERE
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
% give the calibration factor for absolute intensity, calculated previously
|
||||||
|
cal_factor_SAXS = 2.91e-4;
|
||||||
|
cal_factor_WAXS = 2.01e-5 ;
|
||||||
|
|
||||||
|
% where the data is saved (Data10, afs, p-account)
|
||||||
|
base_dir = '~/Data10/';%'/sls/X12SA/Data20/e16598/';
|
||||||
|
save_dir = '~/Data10/';%'/mnt/das-gpfs/work/p16598/';
|
||||||
|
eaccount = beamline.identify_eaccount; % 'e16598';
|
||||||
|
|
||||||
|
% samples and thicknesses
|
||||||
|
Air = 15; % scan used for transmission calculation
|
||||||
|
sample_scan = [34:38]; % should be given
|
||||||
|
sample_thickness = 0.15; % in cm: important for absolute scattering
|
||||||
|
back_scan = []; % used as background, leave it empty [] for no subtraction !!NOT TESTED!!
|
||||||
|
back_thickness = 0.01; % in cm: important for absolute scattering
|
||||||
|
|
||||||
|
% export data for SASfit?
|
||||||
|
export_sasfit = 1;
|
||||||
|
|
||||||
|
%plot curves?
|
||||||
|
plot_curves = 0;
|
||||||
|
|
||||||
|
% save figures?
|
||||||
|
save_fig = 0;
|
||||||
|
|
||||||
|
% average the scan points? 1 = yes, 0 = no
|
||||||
|
average_scan = 1;
|
||||||
|
% scale also the waxs data? yes = 1; no = 0;
|
||||||
|
use_waxs = 0;
|
||||||
|
|
||||||
|
% which bad pixels should be removed
|
||||||
|
bad_pixel = []; %given as a vector [811, 825]
|
||||||
|
|
||||||
|
% use all data measurement points or skip some (faster)
|
||||||
|
skip_measurements = [100]; % use 1 to show all
|
||||||
|
|
||||||
|
% used to reduce noise at the beginning and end of scattering curve
|
||||||
|
skip_first_points = 55;
|
||||||
|
skip_last_points = 150;
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
%% load the diode value for the air
|
||||||
|
S_air = io.spec_read(base_dir,'ScanNr',Air);
|
||||||
|
%scale in case the exposure times are different
|
||||||
|
exp_time = S_air.sec(1,1);
|
||||||
|
scale_air = 1/exp_time;
|
||||||
|
Air_data = load(sprintf('%s/analysis/radial_integration/%s_1_%05d_00000_00000_integ.mat', base_dir, eaccount, Air));
|
||||||
|
I_air = mean(Air_data.I_all, 3);
|
||||||
|
% average over the segments when needed
|
||||||
|
if size(I_air, 2) > 1
|
||||||
|
I_air = (I_air .* Air_data.norm_sum)./sum(Air_data.norm_sum, 2);
|
||||||
|
I_air = sum(I_air, 2);
|
||||||
|
end
|
||||||
|
|
||||||
|
if use_waxs
|
||||||
|
Air_waxs = load(sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat', base_dir, eaccount, Air));
|
||||||
|
I_air_waxs = mean(squeeze(Air_waxs.I_all), 2);
|
||||||
|
end
|
||||||
|
%% background correction
|
||||||
|
if ~isempty(back_scan)
|
||||||
|
for b = 1:length(back_scan)
|
||||||
|
bgr = load(sprintf('%s/analysis/radial_integration/%s_1_%05d_00000_00000_integ.mat', base_dir, eaccount, back_scan(b)));
|
||||||
|
S_back = spec_read(base_dir,'ScanNr',back_scan(b));
|
||||||
|
% in case the burst scan takes place, the transmission is
|
||||||
|
% calculated differently
|
||||||
|
if ~isempty(findstr(S_back.S, 'burst_scan'))
|
||||||
|
delimiter = ' ';
|
||||||
|
formatSpec = '%*s%*s%s%[^\n\r]';
|
||||||
|
fileID = fopen(sprintf('%smcs/S00000-00999/S%05d/%s_%05d.dat', base_dir,back_scan(b), eaccount, back_scan(b)), 'r');
|
||||||
|
dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'ReturnOnError', false);
|
||||||
|
exp_time = dataArray{1,1}{7,1};
|
||||||
|
scale_back = 1/str2num(exp_time);
|
||||||
|
diode = mean(str2num(dataArray{1,1}{9,end}));
|
||||||
|
transm_back = ((diode*scale_back)/(mean(S_air.diode)*scale_air));
|
||||||
|
fclose(fileID);
|
||||||
|
else
|
||||||
|
%scale in case the exposure times are different
|
||||||
|
exp_time = S_back.sec(1,1);
|
||||||
|
scale_back = 1/exp_time;
|
||||||
|
transm_back = (mean(S_back.diode)/mean(S_back.bpm4i))/(mean(S_air.diode)/mean(S_air.bpm4i));
|
||||||
|
end
|
||||||
|
%average background
|
||||||
|
I_bgr = mean(bgr.I_all, 3);
|
||||||
|
if size(I_bgr, 2) > 1
|
||||||
|
I_bgr = (I_bgr .* bgr.norm_sum)./sum(bgr.norm_sum, 2);
|
||||||
|
I_bgr = sum(I_bgr, 2);
|
||||||
|
end
|
||||||
|
I_bgr = ((((I_bgr*scale_back)*1/transm_back)-(I_air*scale_air))*1/back_thickness);
|
||||||
|
I_bgr = I_bgr * cal_factor_SAXS;
|
||||||
|
if use_waxs
|
||||||
|
%average background_WAXS
|
||||||
|
bgr_waxs = importdata(sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat', base_dir, eaccount, back_scan(b)));
|
||||||
|
I_bgr_waxs = mean(squeeze(bgr_waxs.I_all), 2);
|
||||||
|
I_bgr_waxs = ((((I_bgr_waxs*scale_back)*1/transm_back)-(I_air_waxs*scale_air))*1/back_thickness);
|
||||||
|
I_bgr_waxs = I_bgr_waxs * cal_factor_WAXS;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
I_bgr_waxs = 0;
|
||||||
|
I_bgr = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
%% load and correct the sample
|
||||||
|
for s = 1:length(sample_scan)
|
||||||
|
sample_filename=sprintf('%s/analysis/radial_integration/%s_1_%05d_00000_00000_integ.mat', base_dir, eaccount, sample_scan(s));
|
||||||
|
if exist(sample_filename) == 2
|
||||||
|
display(['reading file ',sample_filename])
|
||||||
|
sample = load(sample_filename);
|
||||||
|
else
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
S_s = io.spec_read(base_dir,'ScanNr',sample_scan(s));
|
||||||
|
if ~isempty(findstr(S_s.S, 'burst_scan'))
|
||||||
|
delimiter = ' ';
|
||||||
|
formatSpec = '%*s%*s%s%[^\n\r]';
|
||||||
|
fileID = fopen(sprintf('%smcs/S00000-00999/S%05d/%s_%05d.dat', base_dir,sample_scan(s), eaccount,sample_scan(s)), 'r');
|
||||||
|
dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'ReturnOnError', false);
|
||||||
|
exp_time = dataArray{1,1}{7,1};
|
||||||
|
scale_s = 1/str2num(exp_time);
|
||||||
|
diode = mean(str2num(dataArray{1,1}{9,end}));
|
||||||
|
transm_sample = ((diode*scale_s)/(mean(S_air.diode)*scale_air));
|
||||||
|
fclose(fileID);
|
||||||
|
else
|
||||||
|
%scale in case the exposure times are different
|
||||||
|
exp_time = S_s.sec(1,1);
|
||||||
|
scale_s = 1/exp_time;
|
||||||
|
transm_sample = (mean(S_s.diode)/mean(S_s.bpm4i))/(mean(S_air.diode)/mean(S_air.bpm4i));
|
||||||
|
end
|
||||||
|
%load the sample
|
||||||
|
I_sample = squeeze(sample.I_all);
|
||||||
|
q_sample = sample.q';
|
||||||
|
|
||||||
|
if use_waxs
|
||||||
|
%average background_WAXS
|
||||||
|
sample_waxs = load(sprintf('%s/analysis/radial_integration_waxs/%s_2_%05d_00000_00000_integ.mat', base_dir, eaccount, sample_scan(s)));
|
||||||
|
I_sample_waxs = (sample_waxs.I_all);
|
||||||
|
q_sample_waxs = sample_waxs.q';
|
||||||
|
else
|
||||||
|
q_sample_waxs = [];
|
||||||
|
I_sample_waxs = [];
|
||||||
|
end
|
||||||
|
if average_scan
|
||||||
|
I_sample = mean(I_sample, 3);
|
||||||
|
I_std = mean(sample.I_std, 3);
|
||||||
|
if size(I_sample, 2) > 1
|
||||||
|
I_sample = (I_sample .* sample.norm_sum)./sum(sample.norm_sum, 2);
|
||||||
|
I_std = (I_std .* sample.norm_sum)./sum(sample.norm_sum, 2);
|
||||||
|
I_std = sum(I_std, 2).*cal_factor_SAXS;
|
||||||
|
I_sample = sum(I_sample, 2);
|
||||||
|
end
|
||||||
|
I_std = I_std(skip_first_points:end-skip_last_points,:);
|
||||||
|
I_sample = ((((I_sample*scale_s)*1/transm_sample)-(I_air*scale_air))*1/sample_thickness);
|
||||||
|
if ~isempty(bad_pixel)
|
||||||
|
I_sample(bad_pixel,1) = (I_sample(bad_pixel-1,1)+I_sample(bad_pixel+1,1))/2;
|
||||||
|
end
|
||||||
|
I_sample = I_sample * cal_factor_SAXS;
|
||||||
|
I_cor = (I_sample-I_bgr);
|
||||||
|
I_cor = I_cor(skip_first_points:end-skip_last_points,:);
|
||||||
|
|
||||||
|
if use_waxs
|
||||||
|
hold on
|
||||||
|
I_sample_waxs = median(I_sample_waxs,3);
|
||||||
|
I_sample_waxs = ((((I_sample_waxs.*scale_s).*1/transm_sample)-(I_air_waxs.*scale_air)).*1/sample_thickness);
|
||||||
|
I_sample_waxs = I_sample_waxs * cal_factor_WAXS;
|
||||||
|
I_cor_waxs = (I_sample_waxs-I_bgr_waxs);
|
||||||
|
|
||||||
|
else
|
||||||
|
I_cor_waxs = [];
|
||||||
|
end
|
||||||
|
I_total = [I_cor; I_cor_waxs];
|
||||||
|
|
||||||
|
q_total = [q_sample(skip_first_points: end-skip_last_points,:); q_sample_waxs];
|
||||||
|
[q_total, index] = sort(q_total);
|
||||||
|
I_total = I_total(index);
|
||||||
|
|
||||||
|
if plot_curves
|
||||||
|
figure
|
||||||
|
plot(q_total*10, I_total);
|
||||||
|
set(gca,'XScale','log', 'YScale','log');
|
||||||
|
grid on;
|
||||||
|
box on;
|
||||||
|
xlabel('scattering vector q (nm^{-1})');
|
||||||
|
ylabel('differential scattering cross-section (cm^{-1})');
|
||||||
|
hold on
|
||||||
|
end
|
||||||
|
if export_sasfit
|
||||||
|
save_data = [q_total*10, I_total, I_std];
|
||||||
|
filename = sprintf('scan_%05d_avg', sample_scan);
|
||||||
|
save(sprintf('%sanalysis/dat_files/%s.dat', save_dir , filename) , 'save_data', '-ascii');
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if plot_curves
|
||||||
|
figure
|
||||||
|
hold on
|
||||||
|
end
|
||||||
|
for i = 1:skip_measurements:size(sample.I_all, 3)
|
||||||
|
I_point = sample.I_all(:,:,i);
|
||||||
|
I_point_std = sample.I_std(:,:, i);
|
||||||
|
if size(I_point, 2) > 1
|
||||||
|
I_point = (I_point .* sample.norm_sum)./sum(sample.norm_sum, 2);
|
||||||
|
I_point = sum(I_point, 2);
|
||||||
|
I_point_std = (I_point_std .* sample.norm_sum)./sum(sample.norm_sum, 2);
|
||||||
|
I_point_std = sum(I_point_std, 2).*cal_factor_SAXS;
|
||||||
|
end
|
||||||
|
I_point_std = I_point_std(skip_first_points:end-skip_last_points,:);
|
||||||
|
if ~isempty(bad_pixel)
|
||||||
|
I_point(bad_pixel,1) = (I_point(bad_pixel-1,1) + I_point(bad_pixel+1,1))/2;
|
||||||
|
end
|
||||||
|
I_point = ((((I_point*scale_s)*1/transm_sample)-(I_air*scale_air))*1/sample_thickness);
|
||||||
|
I_point = I_point * cal_factor_SAXS;
|
||||||
|
I_cor = (I_point-I_bgr);
|
||||||
|
I_cor = I_cor(skip_first_points: end-skip_last_points,:);
|
||||||
|
|
||||||
|
if use_waxs
|
||||||
|
I_point_waxs = I_sample_waxs(:,i);
|
||||||
|
I_point_waxs = ((((I_point_waxs*scale_s)*1/transm_sample)-(I_air_waxs*scale_air))*1/sample_thickness);
|
||||||
|
I_point_waxs = I_point_waxs * cal_factor_WAXS;
|
||||||
|
I_cor_waxs = (I_point_waxs-I_bgr_waxs);
|
||||||
|
I_point_std_WAXS = I_sample_waxs(:,:, i);
|
||||||
|
I_point_std_WAXS = I_point_std_WAXS.*cal_factor_WAXS;
|
||||||
|
I_point_std_WAXS = sum(I_point_std_WAXS, 2).*cal_factor_SAXS;
|
||||||
|
else
|
||||||
|
I_cor_waxs = [];
|
||||||
|
end
|
||||||
|
I_total = [I_cor; I_cor_waxs];
|
||||||
|
q_total = [q_sample(skip_first_points: end-skip_last_points,:); q_sample_waxs];
|
||||||
|
[q_total, index] = sort(q_total);
|
||||||
|
I_total = I_total(index);
|
||||||
|
I_point_std_total= [I_point_std; I_point_std_WAXS];
|
||||||
|
if plot_curves
|
||||||
|
plot(q_total*10, I_total);
|
||||||
|
grid on;
|
||||||
|
box on;
|
||||||
|
set(gca,'XScale','log', 'YScale','log');
|
||||||
|
xlabel('scattering vector q (nm^{-1})');
|
||||||
|
ylabel('differential scattering cross-section (cm^{-1})');
|
||||||
|
axis tight
|
||||||
|
hold on
|
||||||
|
drawnow
|
||||||
|
end
|
||||||
|
if export_sasfit
|
||||||
|
save_data = [q_total*10, I_total, I_point_std_total];
|
||||||
|
filename = sprintf('scan_%05d_pt_%05d', sample_scan(s), i);
|
||||||
|
save(sprintf('%sanalysis/dat-files/%s.dat', save_dir , filename) , 'save_data', '-ascii');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
if save_fig
|
||||||
|
%save the results
|
||||||
|
saveas(gcf, sprintf('%sanalysis/scanNr_%05d.jpg', save_dir , sample_scan))
|
||||||
|
end
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
% Read data from Falcon readout electronics
|
||||||
|
% Input is the filename with path
|
||||||
|
% Output is a structure containing fields:
|
||||||
|
% Data contains one spectrum per measurement point
|
||||||
|
% Metadata contains some other information like the number of points per
|
||||||
|
% data transfer and the total number of points
|
||||||
|
% 12 March 2019
|
||||||
|
%
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function dataout = falcon_read(filename)
|
||||||
|
|
||||||
|
data1 = io.HDF.hdf5_load(filename);
|
||||||
|
|
||||||
|
spectra_per_transfer = data1.entry.instrument.FalconX1.PixelsPerBuffer(end);%meta.spectra_per_transfer; % aka pixels per buffer in the MEDM
|
||||||
|
numberofpositions = data1.entry.instrument.FalconX1.CurrentPixel(end);%data1.entry.instrument.NDAttributes.CurrentPixel(end);%meta.numberofpositions;
|
||||||
|
data = data1.entry.data.data;
|
||||||
|
|
||||||
|
data = data(1+256:end,1,:);
|
||||||
|
|
||||||
|
N = size(data);
|
||||||
|
if size(data,3) > 1
|
||||||
|
data = reshape(data,N(1)/spectra_per_transfer,spectra_per_transfer*N(3));
|
||||||
|
else
|
||||||
|
data = reshape(data,N(1)/spectra_per_transfer,spectra_per_transfer);
|
||||||
|
end
|
||||||
|
|
||||||
|
dataout.data = data(1:2:end,1:numberofpositions);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
%FIND_BASE_PACKAGE
|
||||||
|
% finds the path to the cSAXS base package by looking for a specific file (+math)
|
||||||
|
% the code goes up to 3 levels down in the folder structure and it tries to find any folder matching ./*/+math/
|
||||||
|
%
|
||||||
|
% returns:
|
||||||
|
% ++ base_package_path path to the cSAXS base package
|
||||||
|
%
|
||||||
|
% Example how to use it: addpath(find_base_package())
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function base_package_path = find_base_package()
|
||||||
|
maxdepth = 3;
|
||||||
|
test_path = '+math'; % one file to find them all
|
||||||
|
|
||||||
|
lvl = 1;
|
||||||
|
cpath = '';
|
||||||
|
ret = '';
|
||||||
|
while isempty(ret) && ~contains(strtrim(ret), test_path)
|
||||||
|
[~, ret] = system(sprintf('find -L %s -maxdepth 2 -type d -name "%s"', cpath, test_path));
|
||||||
|
if lvl > maxdepth
|
||||||
|
break
|
||||||
|
end
|
||||||
|
lvl = lvl + 1;
|
||||||
|
cpath = [cpath '../'];
|
||||||
|
end
|
||||||
|
ret = split(ret);
|
||||||
|
base_package_path = strtrim(ret{1});
|
||||||
|
base_package_path = base_package_path(1:end-length(test_path));
|
||||||
|
|
||||||
|
if isempty(base_package_path)
|
||||||
|
error('cSAXS base package was not found')
|
||||||
|
end
|
||||||
|
end
|
||||||
+202
@@ -0,0 +1,202 @@
|
|||||||
|
% Call function without arguments for a detailed explanation of its use
|
||||||
|
|
||||||
|
% Filename: $RCSfile: fliread.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.4 $ $Date: 2008/10/03 13:50:04 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% read a data file in the format stored by the program ccdfli.c
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% The image files have the extension raw and the file format is home
|
||||||
|
% defined.
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - image_read_set_default
|
||||||
|
% - fopen_until_exists
|
||||||
|
% - get_hdr_val
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% Pctober 3rd 2008:
|
||||||
|
% add new end-of-header signature search for version 1.20 files
|
||||||
|
%
|
||||||
|
% October 1st 2008: Exchange width and height in reshape command
|
||||||
|
%
|
||||||
|
% May 9th 2008: adapt to call from image_read
|
||||||
|
%
|
||||||
|
% November 3, 2005: include new fields of data format 1.1:
|
||||||
|
% exposure time Spec, exposure time measured, monitor counts
|
||||||
|
%
|
||||||
|
% October 2005: include optional from-to line reading
|
||||||
|
%
|
||||||
|
% March 2005: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [frame,vararg_remain] = fliread(filename, varargin)
|
||||||
|
import io.*
|
||||||
|
import utils.char_to_cellstr
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import utils.get_hdr_val
|
||||||
|
|
||||||
|
% 0: no debug information
|
||||||
|
% 1: some feedback
|
||||||
|
% 2: a lot of information
|
||||||
|
debug_level = 0;
|
||||||
|
|
||||||
|
% initialize return argument
|
||||||
|
frame = struct('header',[], 'data',[]);
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
image_read_sub_help(mfilename,'raw');
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% set default values for the variable input arguments and parse the named
|
||||||
|
% parameters:
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
otherwise
|
||||||
|
% pass further arguments on to fopen_until_exists
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% expected maximum length for the text header
|
||||||
|
max_header_length = 1024;
|
||||||
|
|
||||||
|
% try to open the data file
|
||||||
|
if (debug_level >= 1)
|
||||||
|
fprintf('Opening %s.\n',filename);
|
||||||
|
end
|
||||||
|
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
|
||||||
|
if (fid < 0)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
% read all data at once
|
||||||
|
[fdat,fcount] = fread(fid,'uint8=>uint8');
|
||||||
|
|
||||||
|
% close input data file
|
||||||
|
fclose(fid);
|
||||||
|
if (debug_level >= 2)
|
||||||
|
fprintf('%d data bytes read\n',fcount);
|
||||||
|
end
|
||||||
|
|
||||||
|
% return the complete header as lines of a cell array
|
||||||
|
frame.header = char_to_cellstr( char(fdat(1:max_header_length)'),1 );
|
||||||
|
|
||||||
|
version_no = get_hdr_val(frame.header,'% version','%f',1);
|
||||||
|
if ((version_no ~= 1.00) && (version_no ~= 1.10) && (version_no ~= 1.20))
|
||||||
|
fprintf('%s: File version number %.2f may not be supported\n',...
|
||||||
|
mfilename,version_no);
|
||||||
|
end
|
||||||
|
|
||||||
|
[frameHeight,line_number] = get_hdr_val(frame.header,'% rows','%d',1);
|
||||||
|
[frameWidth,line_number] = get_hdr_val(frame.header,'% columns','%d',1);
|
||||||
|
|
||||||
|
if (version_no < 1.20)
|
||||||
|
if (version_no == 1.10)
|
||||||
|
[monCounts,line_number] = get_hdr_val(frame.header,'% monitorcounts','%d',1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% cut off non-header lines
|
||||||
|
frame.header = frame.header(1:line_number);
|
||||||
|
|
||||||
|
% find start of data
|
||||||
|
eol_ind = regexp(char(fdat(1:max_header_length)'),'\n');
|
||||||
|
data_start = eol_ind(line_number) +1;
|
||||||
|
else
|
||||||
|
eoh_signature = sprintf('%% EOH%c%c',10,26);
|
||||||
|
end_of_header_pos = ...
|
||||||
|
strfind( fdat(1:min(max_header_length,length(fdat)))',...
|
||||||
|
eoh_signature );
|
||||||
|
data_start = end_of_header_pos + length(eoh_signature);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% calculate end of data (should be end of file)
|
||||||
|
data_end = data_start + frameWidth * frameHeight *2 -1;
|
||||||
|
if (data_end > fcount)
|
||||||
|
error('%d bytes read but %d are needed',fcount,data_end);
|
||||||
|
end
|
||||||
|
if (data_end ~= fcount)
|
||||||
|
fprintf('%s warning: %d bytes read vs. %d needed\n',mfilename,...
|
||||||
|
fcount,data_end);
|
||||||
|
end
|
||||||
|
% cut out frame data
|
||||||
|
frame.data = double( reshape(typecast(fdat(data_start:data_end),'uint16'), ...
|
||||||
|
frameWidth,frameHeight) );
|
||||||
|
|
||||||
|
% conversion to standard view on FLI-CCD data at the SLS/cSAXS beamline
|
||||||
|
% (to be determined)
|
||||||
|
% if (~original_orientation)
|
||||||
|
% % frame = flipud(frame');
|
||||||
|
% frame.data = frame.data';
|
||||||
|
% end
|
||||||
|
|
||||||
|
% add the file modification date to the header
|
||||||
|
dir_entry = dir(filename);
|
||||||
|
frame.header{end+1} = [ 'FileTimestamp ' dir_entry.date ];
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
function [name] = get_host_name()
|
||||||
|
%Return host name
|
||||||
|
% Written by YJ for I/O
|
||||||
|
if isunix()
|
||||||
|
name = getenv('HOSTNAME');
|
||||||
|
else
|
||||||
|
name = getenv('hostname');
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
function [name] = get_user_name()
|
||||||
|
%Return account username
|
||||||
|
% Written by YJ for I/O
|
||||||
|
if isunix()
|
||||||
|
name = getenv('USER');
|
||||||
|
else
|
||||||
|
name = getenv('username');
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
function [ ] = imExportTiff( matrix_input,name,section,varargin)
|
||||||
|
%Wirte a image stack as a 'Tiff' file
|
||||||
|
%imExportTiff( matrix,name,section )
|
||||||
|
% matrix: 3D matrix(y,x,z)
|
||||||
|
% name: output file name
|
||||||
|
% section: choose corss sections
|
||||||
|
% 'XY' matrix(:,:,i)
|
||||||
|
% 'YZ' matrix(:,i,:)
|
||||||
|
% 'ZX' matrix(i,:,:)
|
||||||
|
%
|
||||||
|
|
||||||
|
matrix = matrix_input;
|
||||||
|
matrix = matrix-min(min(min(matrix)));
|
||||||
|
s = size(matrix);
|
||||||
|
m = double(max(max(max(matrix))));
|
||||||
|
|
||||||
|
if isempty(varargin) %gray
|
||||||
|
switch section
|
||||||
|
case 'XY'
|
||||||
|
imwrite(double(matrix(:,:,1))./m, name,'tiff')
|
||||||
|
for i=2:s(3)
|
||||||
|
imwrite(double(matrix(:,:,i))./m, name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
case 'ZY'
|
||||||
|
imwrite(double(squeeze(matrix(:,1,:))./m), name,'tiff')
|
||||||
|
for i=2:s(2)
|
||||||
|
imwrite(double(squeeze(matrix(:,i,:))./m), name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
case 'ZYs'
|
||||||
|
imwrite(mat2gray(double(squeeze(matrix(:,1,:)))), name,'tiff')
|
||||||
|
for i=2:s(2)
|
||||||
|
imwrite(mat2gray(double(squeeze(matrix(:,i,:)))), name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
case 'ZX'
|
||||||
|
imwrite(double(squeeze(matrix(1,:,:)))./m, name,'tiff')
|
||||||
|
for i=2:s(1)
|
||||||
|
imwrite(double(squeeze(matrix(i,:,:)))./m, name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
case 'XYs'
|
||||||
|
imwrite(mat2gray(matrix(:,:,1)), name,'tiff')
|
||||||
|
for i=2:s(3)
|
||||||
|
imwrite(mat2gray(matrix(:,:,i)), name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
case 'ZXs'
|
||||||
|
imwrite(squeeze(matrix(1,:,:))./m, name,'tiff')
|
||||||
|
for i=2:s(1)
|
||||||
|
imwrite(mat2gray(squeeze(matrix(i,:,:))), name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
a = varargin{1}; %color
|
||||||
|
switch section
|
||||||
|
case 'XY'
|
||||||
|
imwrite(double(matrix(:,:,1))*a*64/m,jet, name,'tiff')
|
||||||
|
for i=2:s(3)
|
||||||
|
imwrite(double(matrix(:,:,i))*a*64/m,jet, name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
case 'ZY'
|
||||||
|
imwrite(squeeze(matrix(:,1,:))*a*64/m,jet, name,'tiff')
|
||||||
|
for i=2:s(2)
|
||||||
|
imwrite(squeeze(matrix(:,i,:))*a*64/m,jet, name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'ZX'
|
||||||
|
imwrite(squeeze(matrix(1,:,:))*a*64/m,jet, name,'tiff')
|
||||||
|
for i=2:s(1)
|
||||||
|
imwrite(squeeze(matrix(i,:,:))*a*64/m,jet, name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
case 'XYs'
|
||||||
|
imwrite(mat2gray(matrix(:,:,1))*a*64,parula, name,'tiff')
|
||||||
|
for i=2:s(3)
|
||||||
|
imwrite(mat2gray(matrix(:,:,i))*a*64,parula, name,'tiff', 'WriteMode','append')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
% [orient_vec] = image_default_orientation(header, extension, varargin)
|
||||||
|
% Determine default orientation for an image_orient.m call based on the
|
||||||
|
% file extension
|
||||||
|
|
||||||
|
% Filename: $RCSfile: image_default_orientation.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.11 $ $Date: 2013/03/23 15:01:09 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Determine default orientation for an image_orient.m call based on the
|
||||||
|
% file extension
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% ---
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% September 30th 2010:
|
||||||
|
% add orientation for HDF5 files
|
||||||
|
%
|
||||||
|
% November 19th 2008:
|
||||||
|
% add .mat files
|
||||||
|
%
|
||||||
|
% August 28th 2008:
|
||||||
|
% add orientation for extension .dat
|
||||||
|
%
|
||||||
|
% July 17th 2008:
|
||||||
|
% add mar extension, raw default orientation changed before
|
||||||
|
%
|
||||||
|
% June 19th 2008:
|
||||||
|
% add header to call parameters
|
||||||
|
%
|
||||||
|
% June 10th 2008:
|
||||||
|
% 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [orient_vec] = ...
|
||||||
|
image_default_orientation(header, extension, varargin)
|
||||||
|
import io.*
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
fprintf('Usage:\n')
|
||||||
|
fprintf('[orientation_vector]=%s(extension);\n',...
|
||||||
|
m_file_name);
|
||||||
|
fprintf('The vector contains three values which can be 0 or 1 for transpose, flip-left-right, flip-up-down\n');
|
||||||
|
error('At least one input parameter has to be specified.');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 3)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 2 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 0)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
% vararg_remain = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
% value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
otherwise
|
||||||
|
error('Do not know how to handle parameter %s\n',name);
|
||||||
|
% vararg_remain{end+1} = name;
|
||||||
|
% vararg_remain{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% image_read calls this function prior to converting the single frame
|
||||||
|
% to a cell array of frames
|
||||||
|
if (~iscell(header))
|
||||||
|
fprintf('Warning (%s): header is not a cell array\n',mfilename);
|
||||||
|
fprintf('If this is an image_spec call then please report to Oliver:\n')
|
||||||
|
whos header
|
||||||
|
header
|
||||||
|
else
|
||||||
|
if ((~isempty(header)) && (iscell(header{1})))
|
||||||
|
header = header{1};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% set the default orientation as a function of the filename extension
|
||||||
|
switch extension
|
||||||
|
case 'dat'
|
||||||
|
orient_vec = [ 0 0 0 ];
|
||||||
|
case 'edf'
|
||||||
|
orient_vec = [ 1 1 1 ];
|
||||||
|
case 'cbf'
|
||||||
|
orient_vec = [ 1 1 1 ];
|
||||||
|
case {'h5', 'hdf5', 'nxs', 'cxs'}
|
||||||
|
orient_vec = [ 0 0 1 ];
|
||||||
|
case {'tif', 'tiff'}
|
||||||
|
if (strcmp(header{1}(1:5),'Andor'))
|
||||||
|
orient_vec = [ 1 0 0 ];
|
||||||
|
else
|
||||||
|
orient_vec = [ 0 0 0 ];
|
||||||
|
end
|
||||||
|
case {'mar','mccd'}
|
||||||
|
orient_vec = [ 1 0 1 ];
|
||||||
|
case 'mat'
|
||||||
|
orient_vec = [ 0 0 0 ];
|
||||||
|
case 'raw'
|
||||||
|
% FLI CCD at ICON
|
||||||
|
% orient_vec = [ 0 1 0 ];
|
||||||
|
% FLI CCD at laser setup
|
||||||
|
orient_vec = [ 1 0 1 ];
|
||||||
|
case 'spe'
|
||||||
|
orient_vec = [ 0 0 0 ];
|
||||||
|
otherwise
|
||||||
|
error([ 'unknown extension ''' extension '''' ]);
|
||||||
|
end
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
% [im_info,vararg_remain] = image_info(filenames,varargin)
|
||||||
|
% Get information like the dimensions of the data stored in an image file
|
||||||
|
|
||||||
|
% Filename: $RCSfile: image_info.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.3 $ $Date: 2013/01/25 10:23:07 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Get information like the dimensions of the data stored in an image file
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% November 11th 2010:
|
||||||
|
% 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [im_info,vararg_remain] = image_info(filenames,varargin)
|
||||||
|
import io.*
|
||||||
|
import utils.default_parameter_value
|
||||||
|
import utils.find_files
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
|
||||||
|
% initialize return arguments
|
||||||
|
im_info = struct('no_of_frames',[]);
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
% image_read_help('ext',mfilename);
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% % set default values for the variable input arguments:
|
||||||
|
% % default data type for the returned frames
|
||||||
|
% data_type = default_parameter_value(mfilename,'DataType');
|
||||||
|
% % recognize file type by file name extension
|
||||||
|
% force_file_type = default_parameter_value(mfilename,'ForceFileType');
|
||||||
|
% % determine default orientation based on the file name extension
|
||||||
|
% orient_by_extension = default_parameter_value(mfilename,'OrientByExtension');
|
||||||
|
% % filename is actually a mask that may include wildcards
|
||||||
|
% filename_is_fmask = default_parameter_value(mfilename,'IsFmask');
|
||||||
|
% % display file name of the file to be loaded
|
||||||
|
% display_filename = default_parameter_value(mfilename,'DisplayFilename');
|
||||||
|
|
||||||
|
% exit with an error message if unhandled named parameters are left at the
|
||||||
|
% end of this macro
|
||||||
|
unhandled_par_error = 1;
|
||||||
|
filename_is_fmask = 0;
|
||||||
|
force_file_type = [];
|
||||||
|
display_filename = 0;
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'ForceFileType'
|
||||||
|
force_file_type = lower(value);
|
||||||
|
case 'OrientByExtension'
|
||||||
|
orient_by_extension = value;
|
||||||
|
case 'UnhandledParError'
|
||||||
|
unhandled_par_error = value;
|
||||||
|
case 'IsFmask'
|
||||||
|
filename_is_fmask = value;
|
||||||
|
case 'DisplayFilename'
|
||||||
|
display_filename = value;
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% initialize the list of unhandled parameters
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
|
||||||
|
% convert the filename to a cell array to use the same loop for single and
|
||||||
|
% multiple file names
|
||||||
|
if (~iscell(filenames))
|
||||||
|
filenames = { filenames };
|
||||||
|
end
|
||||||
|
|
||||||
|
% loop over all specified file names
|
||||||
|
file_ind_max = length(filenames);
|
||||||
|
for (file_ind=1:file_ind_max)
|
||||||
|
filename = filenames{file_ind};
|
||||||
|
vararg_remain = vararg;
|
||||||
|
|
||||||
|
% in case of file name mask get a list of all matching file names
|
||||||
|
data_dir = '';
|
||||||
|
if (filename_is_fmask)
|
||||||
|
% sub macros must not complain about unknown arguments
|
||||||
|
vararg_remain{end+1} = 'UnhandledParError';
|
||||||
|
vararg_remain{end+1} = 0;
|
||||||
|
|
||||||
|
[data_dir, fnames, vararg_remain] = ...
|
||||||
|
find_files( filename, vararg_remain );
|
||||||
|
else
|
||||||
|
fnames = struct('name',filename);
|
||||||
|
end
|
||||||
|
|
||||||
|
for (sub_file_ind = 1:length(fnames))
|
||||||
|
% pick out the current filename
|
||||||
|
filename = [ data_dir fnames(sub_file_ind).name ];
|
||||||
|
|
||||||
|
% check for minimum filename length
|
||||||
|
if (length(filename) < 5)
|
||||||
|
error([ mfilename ': invalid filename ' filename ]);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (isempty(force_file_type))
|
||||||
|
% get the extension from the last three to four characters
|
||||||
|
extension = lower(filename((end-4):end));
|
||||||
|
pos = strfind(extension,'.');
|
||||||
|
if (length(pos) < 1)
|
||||||
|
error([ mfilename ': invalid extension in ' filename ]);
|
||||||
|
end
|
||||||
|
extension = extension(pos(end)+1:end);
|
||||||
|
else
|
||||||
|
% the file name extension is ignored since the file type is
|
||||||
|
% forced to a specific one
|
||||||
|
extension = force_file_type;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (display_filename)
|
||||||
|
fprintf('file information on %s\n',filename);
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((strcmp(extension,'dat')) || ...
|
||||||
|
(strcmp(extension,'tif')) || (strcmp(extension,'tiff')) || ...
|
||||||
|
(strcmp(extension,'mat')))
|
||||||
|
% open the file to support functionality like
|
||||||
|
% wait-until-exists
|
||||||
|
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
|
||||||
|
if (fid >= 0)
|
||||||
|
fclose(fid);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% interprete file in the format indicated by the filename extension
|
||||||
|
switch extension
|
||||||
|
case {'h5', 'hdf5'}
|
||||||
|
fi = hdf5info(filename);
|
||||||
|
im_info.no_of_frames = fi.GroupHierarchy.Groups.Datasets.Dims(3);
|
||||||
|
case {'cbf', 'dat', 'edf', 'mar', 'mccd', 'mat', 'raw', 'spe', 'tif', 'tiff'}
|
||||||
|
[frame,vararg_remain] = image_read(filename,vararg_remain);
|
||||||
|
im_info.no_of_frames = size(frame.data,3);
|
||||||
|
otherwise
|
||||||
|
error([ 'unknown extension of ' filename ]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: image_orient.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.5 $ $Date: 2014/04/11 12:47:09 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Macro for mirroring or rotating images or stacks of images.
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
% In case of image stacks the first two dimensions are treated as the image
|
||||||
|
% dimensions.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% ---
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% January 16th 2009:
|
||||||
|
% return the complete structure rather than just the data array
|
||||||
|
%
|
||||||
|
% June 19th 2008:
|
||||||
|
% change call to complete frame rather than data only
|
||||||
|
%
|
||||||
|
% May 27th 2008:
|
||||||
|
% 1st version based on orientm.m by Tilman Donath
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [frame_out,vararg_remain] = image_orient(frame, varargin)
|
||||||
|
import io.*
|
||||||
|
import utils.default_parameter_value
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
image_orient_help(mfilename);
|
||||||
|
error('At least one input parameter has to be specified.');
|
||||||
|
end
|
||||||
|
|
||||||
|
if (ndims(frame.data) < 2)
|
||||||
|
error('The input data array must have at least two dimensions.');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
orient_extension = frame.extension{1};
|
||||||
|
do_transpose = default_parameter_value(mfilename,'Transpose');
|
||||||
|
do_fliplr = default_parameter_value(mfilename,'FlipLR');
|
||||||
|
do_flipud = default_parameter_value(mfilename,'FlipUD');
|
||||||
|
invert_orientation = 0;
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'Transpose'
|
||||||
|
do_transpose = value;
|
||||||
|
case 'FlipLR'
|
||||||
|
do_fliplr = value;
|
||||||
|
case 'FlipUD'
|
||||||
|
do_flipud = value;
|
||||||
|
case 'Orientation'
|
||||||
|
if (length(value) ~= 3)
|
||||||
|
error('Invalid Orientation parameter of length %d',length(value));
|
||||||
|
end
|
||||||
|
do_transpose = value(1);
|
||||||
|
do_fliplr = value(2);
|
||||||
|
do_flipud = value(3);
|
||||||
|
case 'OrientExtension'
|
||||||
|
orient_extension = value;
|
||||||
|
case 'OrientByExtension'
|
||||||
|
if (value)
|
||||||
|
orient_vec = image_default_orientation(frame.header,orient_extension);
|
||||||
|
do_transpose = orient_vec(1);
|
||||||
|
do_fliplr = orient_vec(2);
|
||||||
|
do_flipud = orient_vec(3);
|
||||||
|
end
|
||||||
|
case 'InvertOrientation'
|
||||||
|
invert_orientation = value;
|
||||||
|
otherwise
|
||||||
|
vararg_remain{end+1} = name;
|
||||||
|
vararg_remain{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% initialize return arguments
|
||||||
|
frame_out = frame;
|
||||||
|
|
||||||
|
if (invert_orientation)
|
||||||
|
% apply orientation modifications in inverse order, e.g., to revert the
|
||||||
|
% original orientation prior to writing a file
|
||||||
|
if (do_flipud)
|
||||||
|
frame_out.data = flip(frame_out.data,1);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (do_fliplr)
|
||||||
|
frame_out.data = flip(frame_out.data,2);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (do_transpose)
|
||||||
|
dim_order = 1:ndims(frame_out.data);
|
||||||
|
dim_order(1) = 2;
|
||||||
|
dim_order(2) = 1;
|
||||||
|
frame_out.data = permute(frame_out.data,dim_order);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (~invert_orientation)
|
||||||
|
if (do_fliplr)
|
||||||
|
frame_out.data = flip(frame_out.data,2);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (do_flipud)
|
||||||
|
frame_out.data = flip(frame_out.data,1);
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,728 @@
|
|||||||
|
% Call function without arguments for instructions on how to use it
|
||||||
|
|
||||||
|
% Filename: $RCSfile: image_read.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.17 $ $Date: 2013/01/25 10:23:23 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% Macro for reading image data formats used at the SLS / cSAXS beamline.
|
||||||
|
% The data are returned in double precision floating point format.
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% Call without arguments for a brief help text.
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% - edfread
|
||||||
|
% - cbfread
|
||||||
|
% - hdf5read
|
||||||
|
% - fliread
|
||||||
|
% - speread
|
||||||
|
% - char_to_cellstr
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% September 30th 2010:
|
||||||
|
% add a call to hdf5read_main
|
||||||
|
%
|
||||||
|
% June 5th 2009:
|
||||||
|
% disable UhandledParError before calling sub-macros
|
||||||
|
%
|
||||||
|
% January 16th 2009:
|
||||||
|
% adapt to image_orient returning the complete structure rather than just
|
||||||
|
% the data array
|
||||||
|
%
|
||||||
|
% November 19th 2008:
|
||||||
|
% add reading of Matlab files
|
||||||
|
%
|
||||||
|
% September 5th 2008:
|
||||||
|
% skip further processing for a frame if it was not possible to read it
|
||||||
|
%
|
||||||
|
% September 4th 2008:
|
||||||
|
% add the rowcol-from field to the frames structure as origin information
|
||||||
|
%
|
||||||
|
% June 19th 2008: adapt call to image_orient
|
||||||
|
%
|
||||||
|
% May 16th 2008: send variable arguments through find files
|
||||||
|
%
|
||||||
|
% May 9th 2008: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group
|
||||||
|
% and Computing Department, Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [frames,vararg_remain] = image_read(filenames,varargin)
|
||||||
|
import io.*
|
||||||
|
import io.HDF.*
|
||||||
|
import io.CBF.*
|
||||||
|
import plotting.*
|
||||||
|
import utils.char_to_cellstr
|
||||||
|
import utils.default_parameter_value
|
||||||
|
import utils.find_files
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
|
||||||
|
% initialize return arguments
|
||||||
|
frames = struct('data',[], ...
|
||||||
|
'img_full_size',[], 'rowcol_from',[], ...
|
||||||
|
'no_of_el_read', [], ...
|
||||||
|
'header',[], 'filename',[], 'extension', []);
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 1)
|
||||||
|
image_read_help('ext',mfilename);
|
||||||
|
error('At least the filename has to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 2)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 1 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 1)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% convert the filename to a cell array to use the same loop for single and
|
||||||
|
% multiple file names
|
||||||
|
if (~iscell(filenames))
|
||||||
|
filenames = { filenames };
|
||||||
|
end
|
||||||
|
|
||||||
|
% hdf5 files are read via a separate sub-routine
|
||||||
|
% if length(filenames) == 1 % accept only one file name
|
||||||
|
filename = filenames{1};
|
||||||
|
[~, ~, ext] = fileparts(filename);
|
||||||
|
|
||||||
|
if any(strcmp(ext, {'.h5', '.hdf5', '.nxs', '.cxs'}))
|
||||||
|
if length(filenames) == 1
|
||||||
|
frames = hdf5read(filename, varargin);
|
||||||
|
else
|
||||||
|
frames = hdf5read(filenames, varargin);
|
||||||
|
end
|
||||||
|
vararg_remain = [];
|
||||||
|
|
||||||
|
return % image_read ends here for hdf5 image files
|
||||||
|
end
|
||||||
|
% end
|
||||||
|
|
||||||
|
% set default values for the variable input arguments:
|
||||||
|
% default data type for the returned frames
|
||||||
|
data_type = default_parameter_value(mfilename,'DataType');
|
||||||
|
% recognize file type by file name extension
|
||||||
|
force_file_type = default_parameter_value(mfilename,'ForceFileType');
|
||||||
|
% from/to row 0 means all rows
|
||||||
|
row_from = default_parameter_value(mfilename,'RowFrom');
|
||||||
|
row_to = default_parameter_value(mfilename,'RowTo');
|
||||||
|
% from/to column 0 means all lines
|
||||||
|
column_from = default_parameter_value(mfilename,'ColumnFrom');
|
||||||
|
column_to = default_parameter_value(mfilename,'ColumnTo');
|
||||||
|
% determine default orientation based on the file name extension
|
||||||
|
orient_by_extension = default_parameter_value(mfilename,'OrientByExtension');
|
||||||
|
% filename is actually a mask that may include wildcards
|
||||||
|
filename_is_fmask = default_parameter_value(mfilename,'IsFmask');
|
||||||
|
% display file name of the file to be loaded
|
||||||
|
display_filename = default_parameter_value(mfilename,'DisplayFilename');
|
||||||
|
% variable to load from Matlab files
|
||||||
|
matlab_var = default_parameter_value(mfilename,'MatlabVar');
|
||||||
|
|
||||||
|
% exit with an error message if unhandled named parameters are left at the
|
||||||
|
% end of this macro
|
||||||
|
unhandled_par_error = 1;
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'DataType'
|
||||||
|
if (~ischar(value))
|
||||||
|
error('The DataType must be string defining a valid Matlab data type.');
|
||||||
|
end
|
||||||
|
data_type = value;
|
||||||
|
case 'ForceFileType'
|
||||||
|
force_file_type = lower(value);
|
||||||
|
case 'MatlabVar'
|
||||||
|
matlab_var = value;
|
||||||
|
case 'RowFrom'
|
||||||
|
row_from = value;
|
||||||
|
case 'ROI'
|
||||||
|
if (length(value) ~= 4)
|
||||||
|
error('The ROI parameter needs a vector of length four as argument.');
|
||||||
|
end
|
||||||
|
column_from = value(1);
|
||||||
|
row_from = value(2);
|
||||||
|
column_to = value(3);
|
||||||
|
row_to = value(4);
|
||||||
|
case 'RowTo'
|
||||||
|
row_to = value;
|
||||||
|
case 'ColumnFrom'
|
||||||
|
column_from = value;
|
||||||
|
case 'ColumnTo'
|
||||||
|
column_to = value;
|
||||||
|
case 'OrientByExtension'
|
||||||
|
orient_by_extension = value;
|
||||||
|
case 'UnhandledParError'
|
||||||
|
unhandled_par_error = value;
|
||||||
|
case 'IsFmask'
|
||||||
|
filename_is_fmask = value;
|
||||||
|
case 'DisplayFilename'
|
||||||
|
display_filename = value;
|
||||||
|
otherwise
|
||||||
|
vararg{end+1} = name; %#ok<AGROW>
|
||||||
|
vararg{end+1} = value; %#ok<AGROW>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% initialize the list of unhandled parameters
|
||||||
|
vararg_remain = cell(0,0);
|
||||||
|
|
||||||
|
% loop over all specified file names
|
||||||
|
file_ind_max = length(filenames);
|
||||||
|
store_ind = 1;
|
||||||
|
for (file_ind=1:file_ind_max)
|
||||||
|
filename = filenames{file_ind};
|
||||||
|
vararg_remain = vararg;
|
||||||
|
|
||||||
|
% in case of file name mask get a list of all matching file names
|
||||||
|
data_dir = '';
|
||||||
|
if (filename_is_fmask)
|
||||||
|
% sub macros must not complain about unknown arguments
|
||||||
|
vararg_remain{end+1} = 'UnhandledParError';
|
||||||
|
vararg_remain{end+1} = 0;
|
||||||
|
|
||||||
|
[data_dir, fnames, vararg_remain] = ...
|
||||||
|
find_files( filename, vararg_remain );
|
||||||
|
else
|
||||||
|
fnames = struct('name',filename);
|
||||||
|
end
|
||||||
|
|
||||||
|
for (sub_file_ind = 1:length(fnames))
|
||||||
|
% pick out the current filename
|
||||||
|
filename = [ data_dir fnames(sub_file_ind).name ];
|
||||||
|
|
||||||
|
% check for minimum filename length
|
||||||
|
if (length(filename) < 5)
|
||||||
|
error([ mfilename ': invalid filename ' filename ]);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (isempty(force_file_type))
|
||||||
|
% get the extension from the last three to four characters
|
||||||
|
extension = lower(filename((end-4):end));
|
||||||
|
pos = strfind(extension,'.');
|
||||||
|
if (length(pos) < 1)
|
||||||
|
error([ mfilename ': invalid extension in ' filename ]);
|
||||||
|
end
|
||||||
|
extension = extension(pos(end)+1:end);
|
||||||
|
else
|
||||||
|
% the file name extension is ignored since the file type is
|
||||||
|
% forced to a specific one
|
||||||
|
extension = force_file_type;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (display_filename)
|
||||||
|
fprintf('loading %s\n',filename);
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((strcmp(extension,'dat')) || ...
|
||||||
|
(strcmp(extension,'tif')) || (strcmp(extension,'tiff')) || ...
|
||||||
|
(strcmp(extension,'mat')))
|
||||||
|
% open the file to support functionality like
|
||||||
|
% wait-until-exists
|
||||||
|
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
|
||||||
|
if (fid >= 0)
|
||||||
|
fclose(fid);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% interprete file in the format indicated by the filename extension
|
||||||
|
switch extension
|
||||||
|
case 'cbf'
|
||||||
|
[frame,vararg_remain] = cbfread(filename,vararg_remain);
|
||||||
|
case {'hdf5', 'h5', 'nxs', 'cxs'}
|
||||||
|
[frame,vararg_remain] = hdf5read_main(filename,vararg_remain);
|
||||||
|
case 'dat'
|
||||||
|
[frame,vararg_remain] = datread(filename,vararg_remain);
|
||||||
|
case 'edf'
|
||||||
|
[frame,vararg_remain] = edfread(filename,vararg_remain);
|
||||||
|
case {'mar', 'mccd'}
|
||||||
|
[frame,vararg_remain] = marread(filename,vararg_remain);
|
||||||
|
case 'mat'
|
||||||
|
tmp_data = load(filename);
|
||||||
|
frame.data = tmp_data.(matlab_var);
|
||||||
|
frame.header = {};
|
||||||
|
% No header information are available.
|
||||||
|
% Fake exposure time information to avoid problems in other
|
||||||
|
% macros.
|
||||||
|
frame.header{end+1} = 'Exposure_time 1.0';
|
||||||
|
% add the file modification date to the header
|
||||||
|
dir_entry = dir(filename);
|
||||||
|
frame.header{end+1} = [ 'DateTime ' dir_entry.date ];
|
||||||
|
case 'raw'
|
||||||
|
[frame,vararg_remain] = fliread(filename,vararg_remain);
|
||||||
|
case 'spe'
|
||||||
|
[frame,vararg_remain] = speread(filename,vararg_remain);
|
||||||
|
case {'tif', 'tiff'}
|
||||||
|
% reading higher bit depths than 16bit needs a sufficiently
|
||||||
|
% up-to-date Matlab version
|
||||||
|
frame.data = imread(filename,'tif');
|
||||||
|
hdr = imfinfo(filename);
|
||||||
|
frame.header = {};
|
||||||
|
if (isfield(hdr,'ImageDescription'))
|
||||||
|
frame.header = char_to_cellstr(hdr.ImageDescription);
|
||||||
|
end
|
||||||
|
if ((isfield(hdr,'Model')) && ...
|
||||||
|
(strcmp(hdr.Model(1:7),'PILATUS')))
|
||||||
|
frame.header{end+1} = [ 'DateTime ' hdr.DateTime ];
|
||||||
|
frame.header{end+1} = [ 'Software ' hdr.Software ];
|
||||||
|
frame.header{end+1} = [ 'Model ' hdr.Model ];
|
||||||
|
else
|
||||||
|
% the exposure time is not available
|
||||||
|
if (isfield(hdr,'exptimesec'))
|
||||||
|
frame.header{end+1} = [ 'Exposure_time' hdr.exptimesec ];
|
||||||
|
else
|
||||||
|
frame.header{end+1} = 'Exposure_time 1.0';
|
||||||
|
end
|
||||||
|
if (isfield(hdr,'DateTime'))
|
||||||
|
frame.header{end+1} = [ 'DateTime ' hdr.DateTime ];
|
||||||
|
else
|
||||||
|
if (isfield(hdr,'FileModDate'))
|
||||||
|
frame.header{end+1} = [ 'DateTime ' hdr.FileModDate ];
|
||||||
|
else
|
||||||
|
% add the file modification date to the header
|
||||||
|
dir_entry = dir(filename);
|
||||||
|
frame.header{end+1} = ...
|
||||||
|
[ 'DateTime ' dir_entry.date ];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
otherwise
|
||||||
|
error([ 'unknown extension of ' filename ]);
|
||||||
|
end
|
||||||
|
|
||||||
|
% the remaining code is not needed if no file was read
|
||||||
|
if (isempty(frame.data))
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
% determine the orientation from the filename extension
|
||||||
|
vararg_remain_prev = vararg_remain;
|
||||||
|
vararg_remain = cell(1,length(vararg_remain)+2);
|
||||||
|
vararg_remain(3:end) = vararg_remain_prev;
|
||||||
|
vararg_remain{1} = 'OrientByExtension';
|
||||||
|
vararg_remain{2} = orient_by_extension;
|
||||||
|
% set the extension since image_orient is called prior
|
||||||
|
% to defining the return variables frames
|
||||||
|
frame.extension = cell(1,1);
|
||||||
|
frame.extension{1} = extension;
|
||||||
|
|
||||||
|
% orient image
|
||||||
|
[frame,vararg_remain] = image_orient(frame,vararg_remain);
|
||||||
|
|
||||||
|
% cut out region of interest
|
||||||
|
full_size = size(frame.data);
|
||||||
|
if ((row_from > 0) || (row_to > 0) ||...
|
||||||
|
(column_from > 0) || (column_to > 0))
|
||||||
|
if (row_from <= 0)
|
||||||
|
row_from = 1;
|
||||||
|
end
|
||||||
|
if (row_from > size(frame.data,1))
|
||||||
|
error('The RowFrom specification is beyond the maximum value of %d',...
|
||||||
|
size(frame.data,1));
|
||||||
|
end
|
||||||
|
if (row_to <= row_from)
|
||||||
|
row_to = full_size(1);
|
||||||
|
end
|
||||||
|
if (row_to > full_size(1))
|
||||||
|
error('The RowTo specification is beyond the maximum value of %d',...
|
||||||
|
full_size(1));
|
||||||
|
end
|
||||||
|
|
||||||
|
if (column_from <= 0)
|
||||||
|
column_from = 1;
|
||||||
|
end
|
||||||
|
if (column_from > full_size(2))
|
||||||
|
error('The ColumnFrom specification is beyond the maximum value of %d',...
|
||||||
|
full_size(2));
|
||||||
|
end
|
||||||
|
if (column_to <= column_from)
|
||||||
|
column_to = full_size(2);
|
||||||
|
end
|
||||||
|
if (column_to > size(frame.data,2))
|
||||||
|
error('The ColumnTo specification is beyond the maximum value of %d',...
|
||||||
|
full_size(2));
|
||||||
|
end
|
||||||
|
frame.data = frame.data(row_from:row_to,column_from:column_to,:);
|
||||||
|
end
|
||||||
|
|
||||||
|
% initialize the return array with the now known dimensions
|
||||||
|
if (store_ind == 1)
|
||||||
|
% in case of file name masks or multiple images in one data
|
||||||
|
% file the final array dimensions can only be estimated
|
||||||
|
init_guess = file_ind_max -1 + length(fnames);
|
||||||
|
frames.data = zeros( [ size(frame.data) init_guess ], data_type );
|
||||||
|
frames.rowcol_from = cell(1,init_guess);
|
||||||
|
frames.no_of_el_read = cell(1,init_guess);
|
||||||
|
frames.img_full_size = cell(1,init_guess);
|
||||||
|
frames.filename = cell(1,init_guess);
|
||||||
|
frames.extension = cell(1,init_guess);
|
||||||
|
frames.header = cell(1,init_guess);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% store the frame(s)
|
||||||
|
if ((size(frame.data,1) ~= size(frames.data,1)) || ...
|
||||||
|
(size(frame.data,2) ~= size(frames.data,2)))
|
||||||
|
error('Expected frame dimension is %d x %d, frame read has %d x %d',...
|
||||||
|
size(frames.data,2),size(frames.data,1),...
|
||||||
|
size(frame.data,2),size(frame.data,1));
|
||||||
|
end
|
||||||
|
|
||||||
|
% in some cases multiple frames are stored in a single file
|
||||||
|
if (ndims(frame.data) == 4)
|
||||||
|
store_ind_to = (store_ind+size(frame.data,4)-1);
|
||||||
|
frames.data(:,:,:,store_ind:store_ind_to) = cast(frame.data,data_type);
|
||||||
|
else
|
||||||
|
store_ind_to = (store_ind+size(frame.data,3)-1);
|
||||||
|
frames.data(:,:,store_ind:store_ind_to) = cast(frame.data,data_type);
|
||||||
|
end
|
||||||
|
|
||||||
|
% store the filename, extension and the header in the return argument
|
||||||
|
for (ind=store_ind:store_ind_to)
|
||||||
|
frames.img_full_size{ind} = full_size;
|
||||||
|
frames.rowcol_from{ind} = [ row_from column_from ];
|
||||||
|
if (isfield(frame,'no_of_el_read'))
|
||||||
|
frames.no_of_el_read{ind} = frame.no_of_el_read;
|
||||||
|
else
|
||||||
|
frames.no_of_el_read{ind} = size(frame.data,3);
|
||||||
|
end
|
||||||
|
% zero means no ROI, i.e., starting at point (1,1)
|
||||||
|
if (frames.rowcol_from{ind}(1) < 1)
|
||||||
|
frames.rowcol_from{ind}(1) = 1;
|
||||||
|
end
|
||||||
|
if (frames.rowcol_from{ind}(2) < 1)
|
||||||
|
frames.rowcol_from{ind}(2) = 1;
|
||||||
|
end
|
||||||
|
frames.filename{ind} = filename;
|
||||||
|
frames.extension{ind} = extension;
|
||||||
|
frames.header{ind} = frame.header;
|
||||||
|
end
|
||||||
|
|
||||||
|
% update index to free space in the output arrays
|
||||||
|
store_ind = store_ind_to + 1;
|
||||||
|
|
||||||
|
% exit in case of unhandled named parameters, if this has not been switched
|
||||||
|
% off
|
||||||
|
if ((unhandled_par_error) && (~isempty(vararg_remain)))
|
||||||
|
vararg_remain
|
||||||
|
error('Not all named parameters have been handled.');
|
||||||
|
end
|
||||||
|
% restore parameters for next iteration
|
||||||
|
vararg_remain = vararg_remain_prev;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% resize the output arrays in case the initial size is too large
|
||||||
|
store_ind = store_ind -1;
|
||||||
|
if (size(frames.data,3) > store_ind)
|
||||||
|
frames.data = frames.data(:,:,1:store_ind);
|
||||||
|
frames.img_full_size = frames.img_full_size(1:store_ind);
|
||||||
|
frames.rowcol_from = frames.rowcol_from(1:store_ind);
|
||||||
|
frames.filename = frames.filename(1:store_ind);
|
||||||
|
frames.extension = frames.extension(1:store_ind);
|
||||||
|
frames.header = frames.header(1:store_ind);
|
||||||
|
end
|
||||||
|
|
||||||
|
function frames = hdf5read(filename, params)
|
||||||
|
import utils.fopen_until_exists
|
||||||
|
import io.image_default_orientation
|
||||||
|
import io.HDF.hdf5_load
|
||||||
|
import io.image_orient
|
||||||
|
import utils.find_files
|
||||||
|
|
||||||
|
frames = struct('data', [], 'img_full_size', [], 'rowcol_from', [], ...
|
||||||
|
'no_of_el_read', [], 'header',[], 'filename',[], 'extension', []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
p = inputParser;
|
||||||
|
p.KeepUnmatched = true;
|
||||||
|
p.FunctionName = 'image_read';
|
||||||
|
|
||||||
|
addParameter(p, 'H5Location', '/');
|
||||||
|
addParameter(p, 'ReadAttr', false);
|
||||||
|
|
||||||
|
addParameter(p, 'FrameRange', [1, Inf], @(x) isvector(x) && numel(x) <= 2 && isnumeric(x));
|
||||||
|
addParameter(p, 'RowFrom', 1, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
addParameter(p, 'RowTo', Inf, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
addParameter(p, 'ColumnFrom', 1, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
addParameter(p, 'ColumnTo', Inf, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
|
||||||
|
addParameter(p, 'OrientByExtension', 1, @(x) isscalar(x) && (isnumeric(x) || islogical(x)));
|
||||||
|
addParameter(p, 'Orientation', [0, 0, 0], @(x) isvector(x) && numel(x) == 3 && isnumeric(x));
|
||||||
|
addParameter(p, 'InvertOrientation', 0, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
addParameter(p, 'Transpose', 0, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
addParameter(p, 'FlipLR', 0, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
addParameter(p, 'FlipUD', 0, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
addParameter(p, 'CatDim', -1, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
|
||||||
|
addParameter(p, 'DisplayFilename', 1, @(x) isscalar(x) && isnumeric(x));
|
||||||
|
|
||||||
|
% No support for filename wildcards, i.e. ('IsMask', 1)
|
||||||
|
addParameter(p, 'IsFmask', true, ...
|
||||||
|
@islogical);%@(x) assert(~x, 'Filename wildcards, i.e. (''IsFmask'', 1), are not supported for hdf5 files'));
|
||||||
|
|
||||||
|
parse(p, params{:});
|
||||||
|
r = p.Results;
|
||||||
|
vararg_remain = [fieldnames(p.Unmatched)'; struct2cell(p.Unmatched)'];
|
||||||
|
|
||||||
|
if (r.IsFmask)
|
||||||
|
[data_dir, fnames, vararg_remain] = ...
|
||||||
|
find_files( filename, vararg_remain );
|
||||||
|
filename = [];
|
||||||
|
for ii=1:length(fnames)
|
||||||
|
filename{ii} = fullfile(data_dir, fnames(ii).name);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if iscell(filename)
|
||||||
|
dir_entry = dir(filename{1});
|
||||||
|
frames.header{1} = {['DateTime ' dir_entry.date], 'Exposure_time 0.0'};
|
||||||
|
[~, ~, frames.extension{1}] = fileparts(filename{1});
|
||||||
|
frames.extension{1} = frames.extension{1}(2:end); % truncate a leading dot
|
||||||
|
frames.filename{1} = '*multiple_frames*';
|
||||||
|
else
|
||||||
|
dir_entry = dir(filename);
|
||||||
|
frames.header{1} = {['DateTime ' dir_entry.date], 'Exposure_time 0.0'};
|
||||||
|
[~, frames.filename{1}, frames.extension{1}] = fileparts(filename);
|
||||||
|
frames.extension{1} = frames.extension{1}(2:end); % truncate a leading dot
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
inputs_orient = {'OrientByExtension', r.OrientByExtension, 'InvertOrientation', r.InvertOrientation};
|
||||||
|
|
||||||
|
if r.OrientByExtension
|
||||||
|
orient_vec = image_default_orientation(frames.header{1}, frames.extension{1});
|
||||||
|
do_transpose = orient_vec(1);
|
||||||
|
do_fliplr = orient_vec(2);
|
||||||
|
do_flipud = orient_vec(3);
|
||||||
|
|
||||||
|
% Warn user if they also provided either of 'Orientation', 'Transpose', 'FlipLR' or 'FlipUD'
|
||||||
|
if ~all(ismember({'Orientation', 'Transpose', 'FlipLR', 'FlipUD'}, p.UsingDefaults))
|
||||||
|
warning(['Default hdf5 image orientation is potentially modified by either ' ...
|
||||||
|
'''Orientation'', or any of ''Transpose'', ''FlipLR'', or ''FlipUD'' parameters. ' ...
|
||||||
|
'To supress this warning set ''OrientByExtension'' to 0.']);
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
do_transpose = 0;
|
||||||
|
do_fliplr = 0;
|
||||||
|
do_flipud = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~ismember({'Orientation'}, p.UsingDefaults)
|
||||||
|
do_transpose = r.Orientation(1);
|
||||||
|
do_fliplr = r.Orientation(2);
|
||||||
|
do_flipud = r.Orientation(3);
|
||||||
|
|
||||||
|
inputs_orient = [inputs_orient, {'Orientation', r.Orientation}];
|
||||||
|
|
||||||
|
% Warn user if they also provided either of 'Transpose', 'FlipLR' or 'FlipUD'
|
||||||
|
if ~all(ismember({'Transpose', 'FlipLR', 'FlipUD'}, p.UsingDefaults))
|
||||||
|
warning(['Image orientation specified via ''Orientation'' parameter is potentially ' ...
|
||||||
|
'modified by either ''Transpose'', ''FlipLR'', and/or ''FlipUD''. ' ...
|
||||||
|
'To supress this warning use either ''Orientation'' or a combination of ' ...
|
||||||
|
'''Transpose'', ''FlipLR'', and/or ''FlipUD'' parameters.']);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if r.Transpose || r.FlipLR || r.FlipUD
|
||||||
|
do_transpose = r.Transpose;
|
||||||
|
do_fliplr = r.FlipLR;
|
||||||
|
do_flipud = r.FlipUD;
|
||||||
|
inputs_orient = [inputs_orient, {'Transpose', r.Transpose}];
|
||||||
|
inputs_orient = [inputs_orient, {'FlipLR', r.FlipLR}];
|
||||||
|
inputs_orient = [inputs_orient, {'FlipUD', r.FlipUD}];
|
||||||
|
end
|
||||||
|
|
||||||
|
inputs = {};
|
||||||
|
if ~isempty(r.H5Location) && ischar(r.H5Location)
|
||||||
|
inputs{end+1} = r.H5Location;
|
||||||
|
end
|
||||||
|
|
||||||
|
if r.ReadAttr
|
||||||
|
inputs{end+1} = '-sa';
|
||||||
|
end
|
||||||
|
|
||||||
|
% Add slicing indexes if a user specified any of them
|
||||||
|
if ~all(ismember({'FrameRange', 'RowFrom', 'RowTo', 'ColumnFrom', 'ColumnTo'}, ...
|
||||||
|
p.UsingDefaults))
|
||||||
|
|
||||||
|
% Support 0's as start/end index -> full left/right range
|
||||||
|
if numel(r.FrameRange) == 1
|
||||||
|
r.FrameRange(2) = r.FrameRange(1);
|
||||||
|
end
|
||||||
|
if r.FrameRange(1) == 0; r.FrameRange(1) = 1; end
|
||||||
|
if r.FrameRange(2) == 0; r.FrameRange(2) = Inf; end
|
||||||
|
if r.RowFrom == 0; r.RowFrom = 1; end
|
||||||
|
if r.RowTo == 0; r.RowTo = Inf; end
|
||||||
|
if r.ColumnFrom == 0; r.ColumnFrom = 1; end
|
||||||
|
if r.ColumnTo == 0; r.ColumnTo = Inf; end
|
||||||
|
|
||||||
|
% Adjust range values according to the consequent image orientation procedure
|
||||||
|
if r.InvertOrientation % Transpose -> FlipLR/FlipUD
|
||||||
|
if do_transpose; [r.ColumnTo, r.ColumnFrom, r.RowTo, r.RowFrom] = ...
|
||||||
|
deal(r.RowTo, r.RowFrom, r.ColumnTo, r.ColumnFrom); end
|
||||||
|
if do_fliplr; [r.ColumnTo, r.ColumnFrom] = deal(-r.ColumnFrom, -r.ColumnTo); end
|
||||||
|
if do_flipud; [r.RowTo, r.RowFrom] = deal(-r.RowFrom, -r.RowTo); end
|
||||||
|
|
||||||
|
else % FlipLR/FlipUD -> Transpose
|
||||||
|
if do_fliplr; [r.ColumnTo, r.ColumnFrom] = deal(-r.ColumnFrom, -r.ColumnTo); end
|
||||||
|
if do_flipud; [r.RowTo, r.RowFrom] = deal(-r.RowFrom, -r.RowTo); end
|
||||||
|
if do_transpose; [r.ColumnTo, r.ColumnFrom, r.RowTo, r.RowFrom] = ...
|
||||||
|
deal(r.RowTo, r.RowFrom, r.ColumnTo, r.ColumnFrom); end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Form the input
|
||||||
|
inputs{end+1} = {[r.RowFrom, r.RowTo],[r.ColumnFrom, r.ColumnTo], r.FrameRange};
|
||||||
|
end
|
||||||
|
if iscell(filename)
|
||||||
|
|
||||||
|
if (r.DisplayFilename)
|
||||||
|
fprintf('loading %s\n', filename{1});
|
||||||
|
end
|
||||||
|
tmp = frames;
|
||||||
|
tmp.data = hdf5_load(filename{1}, inputs{:});
|
||||||
|
% Orient image frame(s)
|
||||||
|
[tmp, vararg_remain] = image_orient(tmp, [inputs_orient, vararg_remain]);
|
||||||
|
|
||||||
|
% let's handle the 2D (or 3d with singleton) case first
|
||||||
|
if isnumeric(tmp.data) && ndims(tmp.data==3) && size(tmp.data,3)==1
|
||||||
|
frames.data = zeros([size(tmp.data(:,:,1)) length(filename)*size(tmp.data,3)]);
|
||||||
|
frames.data(:,:,1:size(tmp.data,3)) = tmp.data;
|
||||||
|
if length(filename)>1
|
||||||
|
for frame=2:length(filename)
|
||||||
|
if (r.DisplayFilename)
|
||||||
|
fprintf('loading %s\n', filename{frame});
|
||||||
|
end
|
||||||
|
tmp.data = hdf5_load(filename{frame}, inputs{:});
|
||||||
|
|
||||||
|
% Orient image frame(s)
|
||||||
|
[tmp, vararg_remain] = image_orient(tmp, [inputs_orient, vararg_remain]);
|
||||||
|
frames.data(:,:,frame) = tmp.data;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% in case of more than 2 dimensions, concatenate along the
|
||||||
|
% specified dimension, or return a cell array
|
||||||
|
if length(filename)>1
|
||||||
|
frames.data{1} = tmp.data;
|
||||||
|
framedim = ndims(frames.data{1});
|
||||||
|
for frameID=2:length(filename)
|
||||||
|
if (r.DisplayFilename)
|
||||||
|
fprintf('loading %s\n', filename{frameID});
|
||||||
|
end
|
||||||
|
frames.data{frameID} = hdf5_load(filename{frameID}, inputs{:});
|
||||||
|
if ndims(frames.data{frameID})~=framedim
|
||||||
|
framedim = -1;
|
||||||
|
end
|
||||||
|
% Orient image frame(s)
|
||||||
|
[frames, vararg_remain] = image_orient(frames, [inputs_orient, vararg_remain]);
|
||||||
|
end
|
||||||
|
if framedim > 0
|
||||||
|
try
|
||||||
|
if r.CatDim == -1
|
||||||
|
frames.data = cat(ndims(frames.data{1}),frames.data{:});
|
||||||
|
else
|
||||||
|
frames.data = cat(r.CatDim, frames.data{:});
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
warning('Failed to concatenate frames.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
frames.data = tmp.data;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% Support wait-until-exist functionality
|
||||||
|
[fid, vararg_remain] = fopen_until_exists(filename, vararg_remain(:));
|
||||||
|
if fid >= 0
|
||||||
|
fclose(fid);
|
||||||
|
else
|
||||||
|
% Silently exit if a file was not found and ('ErrorIfNotFound', 0)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (r.DisplayFilename)
|
||||||
|
fprintf('loading %s\n', filename);
|
||||||
|
end
|
||||||
|
frames.data = hdf5_load(filename, inputs{:});
|
||||||
|
|
||||||
|
% Orient image frame(s)
|
||||||
|
[frames, vararg_remain] = image_orient(frames, [inputs_orient, vararg_remain]);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% If its a dataset then fill these fields for further showing with
|
||||||
|
% image_show.m or image_spec.m
|
||||||
|
if isnumeric(frames.data)
|
||||||
|
frames.img_full_size = {[size(frames.data, 1), size(frames.data, 2)]};
|
||||||
|
frames.rowcol_from = {[r.RowFrom, r.ColumnFrom]};
|
||||||
|
frames.no_of_el_read = {size(frames.data, 3)};
|
||||||
|
elseif (do_fliplr||do_flipud||do_transpose)
|
||||||
|
warning(['H5Location points to a group, not a dataset. Orientation/OrientByExtension/Transpose/FlipUD/FlipLR will be ignored. \n '...
|
||||||
|
'To remove this warning, set ''OrientByExtension'' to 0 and ''Orientation'' to [0 0 0]'])
|
||||||
|
end
|
||||||
|
|
||||||
|
% Show a warning message for unsupported input parameters
|
||||||
|
unmatched = vararg_remain(1:2:end);
|
||||||
|
if ~isempty(unmatched)
|
||||||
|
warning('These input parameters are not supported for hdf5 files and will be ignored: %s', ...
|
||||||
|
strjoin(unmatched, ', '));
|
||||||
|
end
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
% image_read_help(extension,m_file_name,varargin)
|
||||||
|
% parameter help for image_read
|
||||||
|
|
||||||
|
% Filename: $RCSfile: image_read_help.m,v $
|
||||||
|
%
|
||||||
|
% $Revision: 1.3 $ $Date: 2013/01/25 10:23:47 $
|
||||||
|
% $Author: $
|
||||||
|
% $Tag: $
|
||||||
|
%
|
||||||
|
% Description:
|
||||||
|
% parameter help for image_read
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% none
|
||||||
|
%
|
||||||
|
% Dependencies:
|
||||||
|
% none
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% history:
|
||||||
|
%
|
||||||
|
% July 17th 2008:
|
||||||
|
% add ForceFileType parameter and support for MAR CCD TIFF
|
||||||
|
%
|
||||||
|
% May 9th 2008: 1st version
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [] = image_read_help(extension,m_file_name,varargin)
|
||||||
|
import io.*
|
||||||
|
|
||||||
|
% check minimum number of input arguments
|
||||||
|
if (nargin < 2)
|
||||||
|
error('At least the extension and m-file name have to be specified as input parameter.');
|
||||||
|
end
|
||||||
|
|
||||||
|
% accept cell array with name/value pairs as well
|
||||||
|
no_of_in_arg = nargin;
|
||||||
|
if (nargin == 3)
|
||||||
|
if (isempty(varargin))
|
||||||
|
% ignore empty cell array
|
||||||
|
no_of_in_arg = no_of_in_arg -1;
|
||||||
|
else
|
||||||
|
if (iscell(varargin{1}))
|
||||||
|
% use a filled one given as first and only variable parameter
|
||||||
|
varargin = varargin{1};
|
||||||
|
no_of_in_arg = 2 + length(varargin);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% check number of input arguments
|
||||||
|
if (rem(no_of_in_arg,2) ~= 0)
|
||||||
|
error('The optional parameters have to be specified as ''name'',''value'' pairs');
|
||||||
|
end
|
||||||
|
|
||||||
|
% parse the variable input arguments
|
||||||
|
examples = 1;
|
||||||
|
vararg = cell(0,0);
|
||||||
|
for ind = 1:2:length(varargin)
|
||||||
|
name = varargin{ind};
|
||||||
|
value = varargin{ind+1};
|
||||||
|
switch name
|
||||||
|
case 'Examples'
|
||||||
|
examples = value;
|
||||||
|
otherwise
|
||||||
|
% pass unknown parameters to image_read_sub_help
|
||||||
|
vararg{end+1} = name;
|
||||||
|
vararg{end+1} = value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% do not display examples from image_read_sub_help
|
||||||
|
vararg{end+1} = 'Examples';
|
||||||
|
vararg{end+1} = 0;
|
||||||
|
|
||||||
|
image_read_sub_help(m_file_name,extension,vararg)
|
||||||
|
fprintf('''DataType'',<Matlab class> default is ''double'', other possibilities are ''single'', ''uint16'', ''int16'', ''uint32'', etc.\n');
|
||||||
|
fprintf(' The conversion is done using ''cast'', i.e, out-of-range values are mapped to the minimum or maximum value\n');
|
||||||
|
fprintf('''ForceFileType'',<''extension''> force the file types to be recognized by the here specified extension,\n');
|
||||||
|
fprintf(' useful in case of no or other types of extensions, used by default as OrientExtension as well.\n');
|
||||||
|
fprintf(' The extension ''mar'' and ''mccd'' can be used to read MAR CCD TIFF data.\n');
|
||||||
|
fprintf('''RowFrom'',<0-max> region of interest definition, 0 or 1 for full frame\n');
|
||||||
|
fprintf('''RowTo'',<0-max> region of interest definition, 0 for full frame\n');
|
||||||
|
fprintf('''ColumnFrom'',<0-max> region of interest definition, 0 or 1 for full frame\n');
|
||||||
|
fprintf('''ColumnTo'',<0-max> region of interest definition, 0 for full frame\n');
|
||||||
|
image_orient_help(m_file_name,'ParametersOnly',1);
|
||||||
|
fprintf('''IsFmask'',<0-no,1-yes> interprete the filename(s) as search mask that may include wildcards, default true\n');
|
||||||
|
fprintf('''DisplayFilename'',<0-no,1-yes> display filename of a file before loading it, default yes\n');
|
||||||
|
fprintf('''UnhandledParError'',<0-no,1-yes> exit in case not all named parameters are used/known, default is yes\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('HDF5, H5 or NeXus specifics These files contain data and metadata hierarchically organized in groups and datasets,\n');
|
||||||
|
fprintf(' each group or dataset can also have attributes. Such files are thus here treated in a special way.\n');
|
||||||
|
fprintf(' If you provide only filename then the file contents, including links but excluding attributes,\n');
|
||||||
|
fprintf(' will be recursively read and returned as a Matlab structure. See also hdf5_load.m\n');
|
||||||
|
fprintf('''H5Location'',<location> If <location> is a group then it will be read recursively and returned as a Matlab structure.\n');
|
||||||
|
fprintf(' If <location> is a dataset, the dataset will be read and returned within the field ''data'',\n');
|
||||||
|
fprintf(' this is done in an effort to be compatible with the output of image_read for other file extensions. \n');
|
||||||
|
fprintf(' Only in this case the data region options will be used, e.g ''RowFrom'', ''RowTo'', etc. \n');
|
||||||
|
fprintf('''FrameRange'',<[first_fr last_fr]> Read only a subset of the frames available in the HDF5 file dataset specifed with ''H5Location''\n');
|
||||||
|
fprintf(' This will only have an effect if ''H5Location'' is a dataset and not a group \n');
|
||||||
|
fprintf('''ReadAttr'',<0-no,1-yes> Read the attributes of a dataset or group (default 0). The Name and Value of the attributes are \n');
|
||||||
|
fprintf(' returned in a structure. Note with this option only the attributes (and not the dataset) are read\n');
|
||||||
|
|
||||||
|
if (examples)
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('Examples:\n');
|
||||||
|
fprintf('[frame]=%s(''~/Data10/pilatus/image_1_ct.cbf'');\n',...
|
||||||
|
m_file_name);
|
||||||
|
fprintf('[frame]=%s({''~/Data10/pilatus/image_1_ct1.cbf'',''~/Data10/pilatus/image_1_ct2.cbf''});\n',...
|
||||||
|
m_file_name);
|
||||||
|
fprintf('[frame]=%s(''~/Data10/pilatus/S00010/*.cbf'',''IsFmask'',1);\n',...
|
||||||
|
m_file_name);
|
||||||
|
fprintf('[frame]=%s(''~/Data10/pilatus/image_1_ct.cbf'',''RowFrom'',500,''RowTo'',600);\n',...
|
||||||
|
m_file_name);
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('The returned structure has the fields data, header, filename and extension.\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('\n');
|
||||||
|
fprintf('Examples for HDF5:\n');
|
||||||
|
fprintf('[data] = image_read(''scan_00300.hdf5'') Read all data in the file.\n')
|
||||||
|
fprintf('[data] = image_read(''scan_00300.hdf5'',''H5Location'',''/entry/instrument'') Reads NeXus instrument group.\n')
|
||||||
|
fprintf('[data] = image_read(''scan_00300.hdf5'',''H5Location'',''/entry/collection/data/spec'') Reads spec data which includes counters and motors that change during a scan.\n')
|
||||||
|
fprintf('[data] = image_read(''scan_00300.hdf5'',''H5Location'',''/entry/collection/data/spec'',''ReadAttr'',1) Reads spec data that did not change during the scan, e.g. static motors.\n')
|
||||||
|
fprintf('[data] = image_read(''scan_00300.hdf5'',''H5Location'',''/entry/instrument/Pilatus_2M/data'') Reads all Pilatus frames from the scan.\n')
|
||||||
|
fprintf('[data] = image_read(''scan_00300.hdf5'',''H5Location'',''/entry/instrument/Pilatus_2M/data'',''FrameRange'',[5 10], ''RowFrom'',500,''RowTo'',Inf,''ColumnFrom'',200,''ColumnTo'',800 )\n')
|
||||||
|
fprintf(' Reads the specified frame range and region of interest of the pilatus frames.\n')
|
||||||
|
end
|
||||||
+159
@@ -0,0 +1,159 @@
|
|||||||
|
function M=json2mat(J)
|
||||||
|
import io.*
|
||||||
|
%JSON2MAT converts a javscript data object (JSON) into a Matlab structure
|
||||||
|
% using s recursive approach. J can also be a file name.
|
||||||
|
%
|
||||||
|
%Example: lala=json2mat('{lele:2,lili:4,lolo:[1,2,{lulu:5,bubu:[[1,2],[3,4],[5,6]]}]}')
|
||||||
|
% notice lala.lolo{3}.bubu is read as a 2D matrix.
|
||||||
|
%
|
||||||
|
% Jonas Almeida, March 2010
|
||||||
|
|
||||||
|
% Copyright (c) 2010, Jonas Almeida
|
||||||
|
% All rights reserved.
|
||||||
|
%
|
||||||
|
% Redistribution and use in source and binary forms, with or without
|
||||||
|
% modification, are permitted provided that the following conditions are
|
||||||
|
% met:
|
||||||
|
%
|
||||||
|
% * Redistributions of source code must retain the above copyright
|
||||||
|
% notice, this list of conditions and the following disclaimer.
|
||||||
|
% * Redistributions in binary form must reproduce the above copyright
|
||||||
|
% notice, this list of conditions and the following disclaimer in
|
||||||
|
% the documentation and/or other materials provided with the distribution
|
||||||
|
%
|
||||||
|
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
% POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
if exist(J)==2 % if J is a filename
|
||||||
|
fid=fopen(J,'r');
|
||||||
|
J='';
|
||||||
|
while ~feof(fid)
|
||||||
|
J=[J,fgetl(fid)];
|
||||||
|
end
|
||||||
|
fclose(fid);
|
||||||
|
M=json2mat(J);
|
||||||
|
else
|
||||||
|
J1=regexprep(J(1:min([5,length(J)])),'\s',''); %despaced start of J string
|
||||||
|
if J1(1)=='{' %extract structures
|
||||||
|
JJ=regexp(J,'\{(.*)\}','tokens');
|
||||||
|
M=extract_struct(JJ{1}{1});
|
||||||
|
elseif J1(1)=='[' %extract cells
|
||||||
|
JJ=regexp(J,'\[(.*)\]','tokens');
|
||||||
|
M=extract_cell(JJ{1}{1});
|
||||||
|
elseif J1(1)=='"' %literal string
|
||||||
|
JJ=regexp(J,'\"(.*)\"','tokens');
|
||||||
|
M=JJ{1}{1};
|
||||||
|
else %numeric value
|
||||||
|
M=str2num(J); % is number
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function y=extract_struct(x)
|
||||||
|
import io.*
|
||||||
|
|
||||||
|
%detag arrays first
|
||||||
|
indOC=extract_embed(x,'[',']');
|
||||||
|
n=size(indOC,1);
|
||||||
|
for i=n:-1:1
|
||||||
|
tag{i}=json2mat(x(indOC(i,1):indOC(i,2)));
|
||||||
|
x=[x(1:indOC(i,1)-1),'tag{',num2str(i),'}',x(indOC(i,2)+1:end)];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
a=regexp(x,'[^:,]+:[^,]+');
|
||||||
|
n=length(a);
|
||||||
|
a=[a,length(x)+2];
|
||||||
|
for i=1:n
|
||||||
|
s=x(a(i):a(i+1)-2);
|
||||||
|
t=regexp(s,'([^:]+):(.+)','tokens');
|
||||||
|
%t{1}{1}(t{1}{1}==32)=[]; % remove blanks, maybe later do something fancier like replace with underscores
|
||||||
|
t{1}{1}=strrep(t{1}{1},' ','_');
|
||||||
|
t{1}{1}=strrep(t{1}{1},'"','');
|
||||||
|
if t{1}{1}(1)=='_' %JSON allows for fieldnames starting with "_"
|
||||||
|
t{1}{1}(1)=''; % this line will cause hard to track problems if the same object has 2 attributes with the same name but one of them starting with "_"
|
||||||
|
end
|
||||||
|
if regexp(t{1}{2},'tag{\d+}')
|
||||||
|
y.(t{1}{1})=eval(t{1}{2});
|
||||||
|
else
|
||||||
|
y.(t{1}{1})=json2mat(t{1}{2});
|
||||||
|
end
|
||||||
|
%y.(t{1}{1})=json2mat(t{1}{2});
|
||||||
|
end
|
||||||
|
|
||||||
|
function y=extract_cell(x)
|
||||||
|
import io.*
|
||||||
|
|
||||||
|
indOC=extract_embed(x,'{','}');
|
||||||
|
n=size(indOC,1);
|
||||||
|
for i=n:-1:1
|
||||||
|
tag{i}=json2mat(x(indOC(i,1):indOC(i,2)));
|
||||||
|
x=[x(1:indOC(i,1)-1),'tag~<',num2str(i),'>~',x(indOC(i,2)+1:end)];
|
||||||
|
end
|
||||||
|
indOC=extract_embed(x,'[',']');
|
||||||
|
m=size(indOC,1);
|
||||||
|
for j=m:-1:1
|
||||||
|
i=n+j;
|
||||||
|
tag{i}=json2mat(x(indOC(i,1):indOC(i,2)));
|
||||||
|
try;tag{i}=cell2mat(tag{i});end
|
||||||
|
x=[x(1:indOC(i,1)-1),'tag{',num2str(i),'}',x(indOC(i,2)+1:end)];
|
||||||
|
end
|
||||||
|
x=strrep(x,'~<','{');
|
||||||
|
x=strrep(x,'>~','}');
|
||||||
|
if exist('tag') %catching numeric content
|
||||||
|
if isnumeric([tag{:}])
|
||||||
|
try
|
||||||
|
y=eval(['[',strrep(x,'},','};'),']']);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if exist('y')~=1
|
||||||
|
y=eval(['{',strrep(x,'"',''''),'}']);
|
||||||
|
end
|
||||||
|
|
||||||
|
%look for embeded objects and arrays
|
||||||
|
|
||||||
|
function y=extract_embed(x,tagOpen,tagClose)
|
||||||
|
import io.*
|
||||||
|
|
||||||
|
%EXTRACT_EMBED identifies embeded tagged segments
|
||||||
|
%Example y=extract_embed(str,'[',']')
|
||||||
|
|
||||||
|
indOpen=strfind(x,tagOpen)';
|
||||||
|
indOpen=[indOpen,ones(length(indOpen),1)];
|
||||||
|
indClose=strfind(x,tagClose)';
|
||||||
|
indClose=[indClose,-ones(length(indClose),1)];
|
||||||
|
indOpenClose=[indOpen;indClose];
|
||||||
|
[~,Ind]=sort(indOpenClose(:,1));
|
||||||
|
indOpenClose=indOpenClose(Ind,:);
|
||||||
|
n=size(indOpenClose,1);
|
||||||
|
for i=2:n % add one for open, take one for close
|
||||||
|
indOpenClose(i,2)=indOpenClose(i-1,2)+indOpenClose(i,2);
|
||||||
|
end
|
||||||
|
i=0;
|
||||||
|
op=0; %open
|
||||||
|
while i<n
|
||||||
|
i=i+1;
|
||||||
|
if (indOpenClose(i,2)==1)*(op==0)
|
||||||
|
op=1;
|
||||||
|
elseif indOpenClose(i,2)==0
|
||||||
|
op=0;
|
||||||
|
else
|
||||||
|
indOpenClose(i,2)=-1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if isempty(indOpenClose)
|
||||||
|
y=[];
|
||||||
|
else
|
||||||
|
indOpenClose(indOpenClose(:,2)<0,:)=[];
|
||||||
|
y=[indOpenClose(1:2:end,1),indOpenClose(2:2:end,1)];% Open/Close Indexes
|
||||||
|
end
|
||||||
@@ -0,0 +1,321 @@
|
|||||||
|
%LOAD_PREPARED_DATA Load prepared data file and convert it into the default Matlab
|
||||||
|
%structure
|
||||||
|
%
|
||||||
|
% filename path and filename of the h5 file
|
||||||
|
%
|
||||||
|
% *optional*
|
||||||
|
% return_intensity return intensity or magnitude; default false (= return magnitude)
|
||||||
|
% scan select scan, either integer or array
|
||||||
|
% enum return only selected frames
|
||||||
|
% return_fftshifted return results fftshifted, default == true
|
||||||
|
%
|
||||||
|
% *returns*:
|
||||||
|
% fmag fourier magnitudes of the measured data, ie fftshift(sqrt(data))
|
||||||
|
% fmask mask of the fourier magnitudes, 1 for bad pixels, 0 for other
|
||||||
|
% pos scanning positions (Npos x 2 array)
|
||||||
|
% max_power maximal intesity (max(sum(sum(fmag,1),2),[],3) / numel(fmag(:,:,1));)
|
||||||
|
% scanindexrange indices corresponding to each of the scans
|
||||||
|
% max_sum something stored in h5_data.measurement.(['n' num2str(ii-1)]).Attributes.max_sum;
|
||||||
|
%
|
||||||
|
% Examples:
|
||||||
|
% [fmag, fmask, ~] = load_prepared_data('~/Data10/analysis/S00668/S00668_S00669_data_400x400.h5');
|
||||||
|
% [fmag, fmask, pos] = load_prepared_data('~/Data10/analysis/S00668/S00668_S00669_data_400x400.h5');
|
||||||
|
%
|
||||||
|
% % load intensities
|
||||||
|
% [I, ~, ~] = load_prepared_data('~/Data10/analysis/S00668/S00668_S00669_data_400x400.h5', true);
|
||||||
|
%
|
||||||
|
% % load data from second scan
|
||||||
|
% [fmag, fmask, pos] = load_prepared_data('~/Data10/analysis/S00668/S00668_S00669_data_400x400.h5', false, 2);
|
||||||
|
%
|
||||||
|
% % load data from scan 1 and 3
|
||||||
|
% [fmag, fmask, pos] = load_prepared_data('~/Data10/analysis/S00668/S00668_S00669_data_400x400.h5', false, [1 3]);
|
||||||
|
|
||||||
|
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
%| |
|
||||||
|
%| Except where otherwise noted, this work is licensed under a |
|
||||||
|
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||||
|
%| International (CC BY-NC-SA 4.0) license. |
|
||||||
|
%| |
|
||||||
|
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
%| |
|
||||||
|
%| Author: CXS group, PSI |
|
||||||
|
%*-----------------------------------------------------------------------*
|
||||||
|
% You may use this code with the following provisions:
|
||||||
|
%
|
||||||
|
% If the code is fully or partially redistributed, or rewritten in another
|
||||||
|
% computing language this notice should be included in the redistribution.
|
||||||
|
%
|
||||||
|
% If this code, or subfunctions or parts of it, is used for research in a
|
||||||
|
% publication or if it is fully or partially rewritten for another
|
||||||
|
% computing language the authors and institution should be acknowledged
|
||||||
|
% in written form in the publication: “Data processing was carried out
|
||||||
|
% using the “cSAXS matlab package” developed by the CXS group,
|
||||||
|
% Paul Scherrer Institut, Switzerland.”
|
||||||
|
% Variations on the latter text can be incorporated upon discussion with
|
||||||
|
% the CXS group if needed to more specifically reflect the use of the package
|
||||||
|
% for the published work.
|
||||||
|
%
|
||||||
|
% A publication that focuses on describing features, or parameters, that
|
||||||
|
% are already existing in the code should be first discussed with the
|
||||||
|
% authors.
|
||||||
|
%
|
||||||
|
% This code and subroutines are part of a continuous development, they
|
||||||
|
% are provided “as they are” without guarantees or liability on part
|
||||||
|
% of PSI or the authors. It is the user responsibility to ensure its
|
||||||
|
% proper use and the correctness of the results.
|
||||||
|
|
||||||
|
function [ fmag, fmask, pos, max_power, scanindexrange, max_sum ] = load_prepared_data( filename, return_intensity, enum, return_fftshifted )
|
||||||
|
import io.HDF.hdf5_load
|
||||||
|
|
||||||
|
if nargin < 2
|
||||||
|
return_intensity = false; % return intensity as measured by detector
|
||||||
|
end
|
||||||
|
if nargin < 3
|
||||||
|
enum = []; % return only selected frames
|
||||||
|
end
|
||||||
|
if nargin < 4
|
||||||
|
return_fftshifted = true; % return data fftshifted, !! DEFAULT == true !!
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if ~exist(filename, 'file'); error('Cannot load %s', filename); end
|
||||||
|
|
||||||
|
%% compatility to load also old matlab datasets
|
||||||
|
[~,~,ext]=fileparts(filename);
|
||||||
|
if strcmpi(ext, '.mat')
|
||||||
|
d = load(filename);
|
||||||
|
fmag = d.data;
|
||||||
|
fmask = d.fmask;
|
||||||
|
if ~return_intensity
|
||||||
|
% normalize to provide similar data as in h5-mex
|
||||||
|
max_power = max(sum(sum(fmag,1),2),[],3) / numel(fmag(:,:,1));
|
||||||
|
renorm = sqrt(1/max_power);
|
||||||
|
fmag = sqrt(fmag)*renorm;
|
||||||
|
end
|
||||||
|
if return_fftshifted
|
||||||
|
fmag = math.fftshift_2D(fmag);
|
||||||
|
fmask = math.fftshift_2D(fmask);
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% load h5 file
|
||||||
|
recon = false;
|
||||||
|
inf = h5info(filename);
|
||||||
|
for ii=1:numel(inf.Groups)
|
||||||
|
if strcmpi(inf.Groups(ii).Name, '/reconstruction')
|
||||||
|
recon = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if recon
|
||||||
|
h5_data = hdf5_load(filename, '/measurement/data', '-a');
|
||||||
|
else
|
||||||
|
h5_data = hdf5_load(filename, '-a');
|
||||||
|
end
|
||||||
|
|
||||||
|
if isfield(h5_data, 'reconstruction')
|
||||||
|
h5_data = h5_data.measurement.data;
|
||||||
|
end
|
||||||
|
|
||||||
|
%% check hdf5 data verion (python or mex data prep?)
|
||||||
|
if isfield(h5_data, 'measurements')
|
||||||
|
h5_version = 'mex';
|
||||||
|
else
|
||||||
|
h5_version = 'LibDetXR';
|
||||||
|
end
|
||||||
|
|
||||||
|
switch h5_version
|
||||||
|
case 'mex'
|
||||||
|
warning('Outdated data format.')
|
||||||
|
asize = size(h5_data.measurements.measurement_0.diff_pat.Value);
|
||||||
|
fn = fieldnames(h5_data.measurements);
|
||||||
|
numpts = length(fn)-1;
|
||||||
|
fmag = zeros(asize(1), asize(2), numpts);
|
||||||
|
fmask = ones(asize(1), asize(2), numpts);
|
||||||
|
pos = zeros(numpts, 2);
|
||||||
|
|
||||||
|
if isempty(enum)
|
||||||
|
enum = 1:length(fieldnames(h5_data.detectors))-1;
|
||||||
|
end
|
||||||
|
|
||||||
|
for ii=enum
|
||||||
|
|
||||||
|
fmaskdet{ii} = zeros(asize(1),asize(2));
|
||||||
|
modules = transpose(h5_data.detectors.(['detector_' num2str(ii-1)]).modules.Value);
|
||||||
|
|
||||||
|
numrows = modules(:,1);
|
||||||
|
numcols = modules(:,2);
|
||||||
|
indbeginmody = modules(:,3)+1;
|
||||||
|
indbeginmodx = modules(:,4)+1;
|
||||||
|
indendmody = numrows + indbeginmody -1;
|
||||||
|
indendmodx = numcols + indbeginmodx -1;
|
||||||
|
nummody = length(indbeginmody);
|
||||||
|
nummodx = length(indbeginmodx);
|
||||||
|
|
||||||
|
for kk = 1:nummody
|
||||||
|
for jj = 1:nummodx
|
||||||
|
fmaskdet{ii}(indbeginmody(kk):indendmody(kk),indbeginmodx(jj):indendmodx(jj))=1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
scanindexrange = ones([2 length(enum)]);
|
||||||
|
cid=1;
|
||||||
|
for ii=1:numpts
|
||||||
|
cf =['measurement_' num2str(ii-1)];
|
||||||
|
det = h5_data.measurements.(cf).Attributes.detector;
|
||||||
|
if any(enum==det+1)
|
||||||
|
if ii>scanindexrange(2,det+1)
|
||||||
|
scanindexrange(2,det+1) = ii;
|
||||||
|
end
|
||||||
|
|
||||||
|
fmag(:,:,cid) = transpose(h5_data.measurements.(cf).diff_pat.Value);
|
||||||
|
if isfield(h5_data.measurements.(cf), 'bad_pixels')
|
||||||
|
bp_temp = h5_data.measurements.(cf).bad_pixels.Value;
|
||||||
|
else
|
||||||
|
bp_temp = [];
|
||||||
|
end
|
||||||
|
pos(cid, :) = h5_data.measurements.(cf).Attributes.position;
|
||||||
|
fmask(:,:,cid) = fmaskdet{det+1};
|
||||||
|
if ~isempty(bp_temp)
|
||||||
|
for kk=1:size(bp_temp,2)
|
||||||
|
fmask(bp_temp(1,kk)+1,bp_temp(2,kk)+1,cid) = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cid = cid + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
fmag = fmag(:,:,1:cid-1);
|
||||||
|
fmask = fmask(:,:,1:cid-1);
|
||||||
|
pos = pos(1:cid-1,:);
|
||||||
|
% attr = hdf5_load(filename, '/measurements/','-sa');
|
||||||
|
max_power = h5_data.measurements.Attributes.max_power;
|
||||||
|
fmask = logical(fmask);
|
||||||
|
if return_intensity
|
||||||
|
renorm = sqrt(1/max_power);
|
||||||
|
fmag = (fmag/renorm).^2;
|
||||||
|
end
|
||||||
|
|
||||||
|
scanindexrange = scanindexrange';
|
||||||
|
for ii=2:length(enum)
|
||||||
|
scanindexrange(ii,1) = scanindexrange(ii-1,2)+1;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case 'LibDetXR'
|
||||||
|
|
||||||
|
%% get data dims
|
||||||
|
fmag_dim(1) = 0;
|
||||||
|
fmag_dim(2) = 1;
|
||||||
|
if isempty(enum)
|
||||||
|
enum = 1:length(fieldnames(h5_data.measurement))-1;
|
||||||
|
end
|
||||||
|
|
||||||
|
for ii=enum
|
||||||
|
fmag_temp{ii} = h5_data.measurement.(['n' num2str(ii-1)]).data.Value;
|
||||||
|
fmag_dim(ii+2) = size(fmag_temp{ii},3);
|
||||||
|
end
|
||||||
|
|
||||||
|
asize = size(fmag_temp{enum(1)});
|
||||||
|
if asize(1) ~= asize(2)
|
||||||
|
error('Loading of asymmetric prepated datasets not supported, use p.force_preparation_data=true')
|
||||||
|
end
|
||||||
|
|
||||||
|
fmag = zeros(asize(1), asize(2), sum(fmag_dim)-1, 'single');
|
||||||
|
fmask = ones(asize(1), asize(2), sum(fmag_dim)-1, 'logical');
|
||||||
|
pos = zeros(sum(fmag_dim)-1, 2);
|
||||||
|
max_sum = zeros(length(enum), 1);
|
||||||
|
|
||||||
|
%% load modules to prepare fmask and load everything into containers
|
||||||
|
if isempty(enum)
|
||||||
|
enum = 1:length(fieldnames(h5_data.detector));
|
||||||
|
end
|
||||||
|
|
||||||
|
for ii=enum
|
||||||
|
% get modules for mask
|
||||||
|
fmaskdet{ii} = zeros(asize(1),asize(2), 'logical');
|
||||||
|
modules = transpose(h5_data.detector.(['n' num2str(ii-1)]).modules.Value);
|
||||||
|
|
||||||
|
numrows = modules(:,1);
|
||||||
|
numcols = modules(:,2);
|
||||||
|
indbeginmody = modules(:,3)+1;
|
||||||
|
indbeginmodx = modules(:,4)+1;
|
||||||
|
indendmody = numrows + indbeginmody -1;
|
||||||
|
indendmodx = numcols + indbeginmodx -1;
|
||||||
|
nummody = length(indbeginmody);
|
||||||
|
nummodx = length(indbeginmodx);
|
||||||
|
|
||||||
|
for kk = 1:nummody
|
||||||
|
for jj = 1:nummodx
|
||||||
|
fmaskdet{ii}(indbeginmody(kk):indendmody(kk),indbeginmodx(jj):indendmodx(jj))=1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
temp_range = sum(fmag_dim(1:ii+1)):sum(fmag_dim(1:ii+2))-1;
|
||||||
|
fmask(:,:,temp_range) = repmat(fmaskdet{ii},[1,1,fmag_dim(ii+2)]);
|
||||||
|
|
||||||
|
% get bad pixels
|
||||||
|
if isfield(h5_data.detector.(['n' num2str(ii-1)]), 'bad_pixels')
|
||||||
|
bp = h5_data.detector.(['n' num2str(ii-1)]).bad_pixels.Value;
|
||||||
|
for kk=1:size(bp,2)
|
||||||
|
fmask(bp(1,kk)+1,bp(2,kk)+1,temp_range) = 0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if isfield(h5_data.measurement.(['n' num2str(ii-1)]), 'bad_pixels')
|
||||||
|
bp = h5_data.measurement.(['n' num2str(ii-1)]).bad_pixels.Value;
|
||||||
|
bpi = h5_data.measurement.(['n' num2str(ii-1)]).bad_pixels_index.Value;
|
||||||
|
assert(length(bpi)==length(temp_range), 'Number of frames does not match the number of bad pixel datasets.')
|
||||||
|
offset = 1;
|
||||||
|
for kk=1:length(bpi)
|
||||||
|
for jj=offset:bpi(kk)
|
||||||
|
fmask(bp(1,jj)+1, bp(2,jj)+1, temp_range(kk)) = 0;
|
||||||
|
end
|
||||||
|
offset = bpi(kk);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
fmag(:,:,temp_range) = permute(fmag_temp{ii}, [2 1 3]);
|
||||||
|
pos_temp = h5_data.measurement.(['n' num2str(ii-1)]).positions.Value;
|
||||||
|
pos(temp_range,1) = pos_temp(1,:);
|
||||||
|
pos(temp_range,2) = pos_temp(2,:);
|
||||||
|
|
||||||
|
max_sum(enum) = h5_data.measurement.(['n' num2str(ii-1)]).Attributes.max_sum;
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% normalize to provide similar data as in h5-mex
|
||||||
|
max_power = max(sum(sum(fmag,1),2),[],3) / numel(fmag(:,:,1));
|
||||||
|
renorm = sqrt(1/max_power);
|
||||||
|
if ~return_intensity
|
||||||
|
fmag = sqrt(fmag)*renorm;
|
||||||
|
end
|
||||||
|
fmask = logical(fmask);
|
||||||
|
|
||||||
|
scanindexrange = zeros(numel(enum),2);
|
||||||
|
scanindexrange(1,:) = fmag_dim(2:3);
|
||||||
|
for ii=2:numel(enum)
|
||||||
|
scanindexrange(ii,1) = scanindexrange(ii-1,2)+1;
|
||||||
|
scanindexrange(ii,2) = scanindexrange(ii-1,2)+fmag_dim(ii+2);
|
||||||
|
end
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('Unknown HDF5 data structure!')
|
||||||
|
end
|
||||||
|
|
||||||
|
if ~return_fftshifted
|
||||||
|
% return data as seen by detector,
|
||||||
|
fmag = math.ifftshift_2D(fmag);
|
||||||
|
fmask = math.ifftshift_2D(fmask);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
Loaded 100 of 1012 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user