mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 20:39:08 +09:00
initial commit
This commit is contained in:
@@ -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
|
||||
File diff suppressed because one or more lines are too long
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user