Files
fold_slice/+astra/ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu
T
2026-08-07 15:56:42 +09:00

354 lines
12 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
*-----------------------------------------------------------------------*
|                                                                       |
|  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);
}
}
}