initial commit

This commit is contained in:
2026-08-07 15:56:42 +09:00
commit 91ad25aca9
1012 changed files with 159314 additions and 0 deletions
+48
View File
@@ -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
+318
View File
@@ -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
+212
View File
@@ -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;
+164
View File
@@ -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 */
+693
View File
@@ -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__ */
+68
View File
@@ -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
+19
View File
@@ -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;
}
+483
View File
@@ -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;
}
}
+47
View File
@@ -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
+929
View File
@@ -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;
}
}
+51
View File
@@ -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
+8
View File
@@ -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
+16
View 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
+8
View File
@@ -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>
+688
View File
@@ -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;
}
}
+121
View File
@@ -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
+103
View File
@@ -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
+299
View File
@@ -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
+339
View File
@@ -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
+385
View File
@@ -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
+90
View File
@@ -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.
+54
View File
@@ -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
+58
View File
@@ -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
+51
View File
@@ -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
+52
View File
@@ -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
+59
View File
@@ -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.
+229
View File
@@ -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');
+224
View File
@@ -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
+236
View File
@@ -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
% LICENSEEs 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, 379382 (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, 6871 (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, 2908929108 (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
+57
View File
@@ -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');
+84
View File
@@ -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
+69
View File
@@ -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
+100
View File
@@ -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
+77
View File
@@ -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;
+80
View File
@@ -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
% LICENSEEs 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, 379382 (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, 6871 (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, 2908929108 (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
+183
View File
@@ -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
+184
View File
@@ -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);
+51
View File
@@ -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
+56
View File
@@ -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
+60
View File
@@ -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.
+74
View File
@@ -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
% LICENSEEs 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, 379382 (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, 6871 (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, 2908929108 (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
+65
View File
@@ -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
+207
View File
@@ -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);
+456
View File
@@ -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
+345
View File
@@ -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
+179
View File
@@ -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;
}
}
}
}
+710
View File
@@ -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
+194
View File
@@ -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.
+130
View File
@@ -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
+52
View File
@@ -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
+72
View File
@@ -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
+803
View File
@@ -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.
+44
View File
@@ -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.
+414
View File
@@ -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');
+95
View File
@@ -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.
+161
View File
@@ -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;
}
+339
View File
@@ -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
+258
View File
@@ -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;
+82
View File
@@ -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
+65
View File
@@ -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
+84
View File
@@ -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
+69
View File
@@ -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
+65
View File
@@ -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
+132
View File
@@ -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
+99
View File
@@ -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
+642
View File
@@ -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);
+80
View File
@@ -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
+65
View File
@@ -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
+57
View File
@@ -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
+143
View File
@@ -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
+43
View File
@@ -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
+242
View File
@@ -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
+119
View File
@@ -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
+370
View File
@@ -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
+201
View File
@@ -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');
+86
View File
@@ -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
+32
View File
@@ -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
View File
@@ -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
View File
@@ -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
+298
View File
@@ -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.
+67
View File
@@ -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
+69
View File
@@ -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
View File
@@ -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 ];
+11
View File
@@ -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
+11
View File
@@ -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
+78
View File
@@ -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
+169
View File
@@ -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
+214
View File
@@ -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
+176
View File
@@ -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
+728
View File
@@ -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
+161
View File
@@ -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
View File
@@ -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
+321
View File
@@ -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