├── test_data ├── otf.dv ├── otf.tif ├── raw.dv ├── raw.tif ├── config ├── config-tiff └── run.sh ├── src ├── Buffers │ ├── Buffer.cpp │ ├── CMakeLists.txt │ ├── Makefile │ ├── bufferExample.cpp │ ├── PinnedCPUBuffer.h │ ├── test_GPUBuffer.cpp │ ├── test_CPUBuffer.cpp │ ├── PinnedCPUBuffer.cpp │ ├── CPUBuffer.cpp │ ├── CPUBuffer.h │ ├── GPUBuffer.h │ ├── GPUBuffer.cpp │ └── Buffer.h ├── cudaSirecon │ ├── cudaSirecon.h │ ├── cudaSireconDriver.cpp │ ├── CMakeLists.txt │ ├── interface.cpp │ ├── boostfs.cpp │ ├── mrc.h │ ├── gpuFunctions.h │ ├── SIM_reconstructor.hpp │ ├── gpuFunctionsImpl_hh.cu │ └── cudaSireconImpl.h ├── cudasireconConfig.h.in ├── otf │ ├── downloadFindFFTW.cmake.in │ ├── CMakeLists.txt │ └── otfviewer.cpp ├── cutilSafeCall.h └── CMakeLists.txt ├── environment-windows.yml ├── environment-linux.yml ├── .gitignore ├── bld.bat ├── VStutio_project ├── VStutio_project.vcxproj.filters ├── Buffers │ ├── Buffers.vcxproj.filters │ └── Buffers.vcxproj ├── VStutio_project.sln └── VStutio_project.vcxproj ├── recon.py ├── README.md └── LICENSE /test_data/otf.dv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scopetools/cudasirecon/HEAD/test_data/otf.dv -------------------------------------------------------------------------------- /test_data/otf.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scopetools/cudasirecon/HEAD/test_data/otf.tif -------------------------------------------------------------------------------- /test_data/raw.dv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scopetools/cudasirecon/HEAD/test_data/raw.dv -------------------------------------------------------------------------------- /test_data/raw.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scopetools/cudasirecon/HEAD/test_data/raw.tif -------------------------------------------------------------------------------- /test_data/config: -------------------------------------------------------------------------------- 1 | nimm=1.515 2 | background=0 3 | wiener=0.001 4 | k0angles=-0.804300,-1.8555,0.238800 5 | ls=0.2035 6 | ndirs=3 7 | nphases=5 8 | na=1.42 9 | otfRA=1 10 | dampenOrder0=1 -------------------------------------------------------------------------------- /src/Buffers/Buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "Buffer.h" 2 | 3 | Buffer::~Buffer() { 4 | } 5 | 6 | void Buffer::dump(std::ostream& s, int numCols) 7 | { 8 | dump(s, numCols, 0, getSize()); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /environment-windows.yml: -------------------------------------------------------------------------------- 1 | name: simbuild 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - cxx-compiler 6 | - ninja 7 | - cmake 8 | - fftw 9 | - boost-cpp 10 | - libtiff 11 | - liblapack=*=*netlib 12 | -------------------------------------------------------------------------------- /environment-linux.yml: -------------------------------------------------------------------------------- 1 | name: simbuild 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - cudatoolkit-dev 6 | - make 7 | - cxx-compiler 8 | - fftw 9 | - boost-cpp 10 | - cmake 11 | - libtiff 12 | - liblapack 13 | -------------------------------------------------------------------------------- /test_data/config-tiff: -------------------------------------------------------------------------------- 1 | nimm=1.515 2 | fastSI=0 3 | background=0 4 | wiener=0.001 5 | k0angles=0.804300,1.8555,-0.238800 6 | ls=0.2035 7 | ndirs=3 8 | nphases=5 9 | na=1.42 10 | otfRA=1 11 | dampenOrder0=1 12 | xyres=0.08 13 | zres=0.125 14 | zresPSF=0.125 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | build 3 | .vscode 4 | testData 5 | test_data/psf.dv 6 | test_data/GPUsirecon/* 7 | test_data/proc.dv 8 | IVE 9 | lapack 10 | *dist 11 | fftw2 12 | cmake_build 13 | 14 | src/IVE 15 | _test.sh 16 | src/cudaSirecon/cudasireconConfig.h 17 | src/cudasireconConfig.h 18 | -------------------------------------------------------------------------------- /src/cudaSirecon/cudaSirecon.h: -------------------------------------------------------------------------------- 1 | #ifndef CUDA_SIRECON_H 2 | #define CUDA_SIRECON_H 3 | 4 | 5 | #include "cudaSireconImpl.h" // Or only a subset of it is needed? 6 | /* 7 | The following definitions are needed from cudaSirecon.h: 8 | 9 | ReconParams, ImageParams, DriftParams, ReconData 10 | */ 11 | #endif 12 | -------------------------------------------------------------------------------- /src/cudasireconConfig.h.in: -------------------------------------------------------------------------------- 1 | // the configured options and settings for cudasirecon 2 | // This will be populated with variables from the project() setting 3 | // in CMakeLists.txt 4 | #define cudasirecon_VERSION_MAJOR @cudasirecon_VERSION_MAJOR@ 5 | #define cudasirecon_VERSION_MINOR @cudasirecon_VERSION_MINOR@ 6 | #define cudasirecon_VERSION_PATCH @cudasirecon_VERSION_PATCH@ -------------------------------------------------------------------------------- /test_data/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # makeotf psf.dv otf.otf -angle -0.804300 -ls 0.2035 -na 1.4 -nimm 1.515 -fixorigin 3 20 3 | 4 | parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) 5 | APP="$parent_path/../cmake_build/cudaSirecon/cudasirecon" 6 | 7 | # test TIFF 8 | $APP $parent_path raw $parent_path/otf.tif -c $parent_path/config-tiff 9 | 10 | # test MRC 11 | $APP $parent_path/raw.dv $parent_path/proc.dv $parent_path/otf.dv -c $parent_path/config 12 | -------------------------------------------------------------------------------- /src/otf/downloadFindFFTW.cmake.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(findFFTW-download NONE) 4 | 5 | include(ExternalProject) 6 | 7 | ExternalProject_Add(findFFTW_download 8 | GIT_REPOSITORY "https://github.com/egpbos/findfftw.git" 9 | CONFIGURE_COMMAND "" 10 | BUILD_COMMAND "" 11 | INSTALL_COMMAND "" 12 | TEST_COMMAND "" 13 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/findFFTW-src" 14 | BINARY_DIR "" 15 | INSTALL_DIR "" 16 | ) -------------------------------------------------------------------------------- /bld.bat: -------------------------------------------------------------------------------- 1 | del /Q cmake_build 2 | 3 | @REM if not exist src\IVE\ ( 4 | @REM powershell -Command "Invoke-WebRequest https://www.dropbox.com/s/2twvw0go3dr3aim/IVE.zip -OutFile IVE.zip" 5 | @REM powershell -Command "Expand-Archive IVE.zip -DestinationPath src\" 6 | @REM del IVE.zip ) 7 | 8 | mkdir cmake_build 9 | cd cmake_build 10 | 11 | cmake -G Ninja ^ 12 | -DBUILD_MRC=ON ^ 13 | -DBUILD_OTF_VIEWER=OFF ^ 14 | -DCMAKE_BUILD_TYPE=Release ^ 15 | -DCMAKE_INSTALL_PREFIX="%CONDA_PREFIX%/Library" ^ 16 | ../src 17 | 18 | ninja 19 | ninja install 20 | -------------------------------------------------------------------------------- /src/cudaSirecon/cudaSireconDriver.cpp: -------------------------------------------------------------------------------- 1 | #include "cudaSireconImpl.h" 2 | #include "SIM_reconstructor.hpp" 3 | 4 | 5 | int main(int argc, char **argv) 6 | { 7 | try { 8 | SIM_Reconstructor myreconstructor(argc, argv); 9 | 10 | for (int it = 0; it < myreconstructor.getNTimes(); ++it) { 11 | for (int iw = 0; iw < 1; ++iw) { 12 | myreconstructor.setFile(it, iw); 13 | myreconstructor.loadAndRescaleImage(it, iw); 14 | myreconstructor.setCurTimeIdx(it); 15 | if (myreconstructor.processOneVolume()) 16 | myreconstructor.writeResult(it, iw); 17 | } 18 | } 19 | 20 | myreconstructor.closeFiles(); 21 | } 22 | catch (std::exception &e) { 23 | std::cerr << "\n!!Error occurred: " << e.what() << std::endl; 24 | return 0; 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/Buffers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}" ${CUDA_INCLUDE_DIRS} 2 | "${CMAKE_SOURCE_DIR}/gtest/include") 3 | 4 | add_library(Buffer Buffer.cpp bufferExample.cpp CPUBuffer.cpp GPUBuffer.cpp 5 | PinnedCPUBuffer.cpp) 6 | 7 | set_property(TARGET Buffer PROPERTY MSVC_RUNTIME_LIBRARY "") 8 | 9 | set(HEADERS Buffer.h CPUBuffer.h GPUBuffer.h PinnedCPUBuffer.h) 10 | 11 | install( 12 | TARGETS Buffer 13 | RUNTIME DESTINATION bin 14 | LIBRARY DESTINATION lib 15 | ARCHIVE DESTINATION lib) 16 | 17 | set(TESTS test_CPUBuffer test_GPUBuffer) 18 | 19 | set(LIBRARIES Buffer gtest_main gtest) 20 | 21 | # foreach(t ${TESTS}) add_executable(${t} ${t}.cpp) add_dependencies(${t} 22 | # ${LIBRARIES}) target_link_libraries(${t} ${LIBRARIES}) add_test(${t} ${t}) 23 | # endforeach(t) 24 | 25 | install(FILES ${HEADERS} DESTINATION include) 26 | 27 | # add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS ${TESTS}) 28 | -------------------------------------------------------------------------------- /src/cutilSafeCall.h: -------------------------------------------------------------------------------- 1 | #ifndef CUTIL_SAVE_CALL_H 2 | #define CUTIL_SAVE_CALL_H 3 | 4 | #include 5 | 6 | // utilities for safe cuda api calls copied from cuda sdk. 7 | // (currently these aren't exported -- file local) 8 | #define cutilSafeCallNoSync(err) __cudaSafeCallNoSync(err, __FILE__, __LINE__) 9 | #define cutilSafeCall(err) __cudaSafeCall (err, __FILE__, __LINE__) 10 | inline static void __cudaSafeCall(cudaError_t err, const char *file, const int line) 11 | { 12 | if (cudaSuccess != err) { 13 | fprintf(stderr, "%s(%i) : cudaSafeCall() Runtime API error %d: %s.\n", 14 | file, line, (int)err, cudaGetErrorString(err)); 15 | exit(-1); 16 | } 17 | } 18 | inline static void __cudaSafeCallNoSync(cudaError_t err, const char *file, const int line) 19 | { 20 | if (cudaSuccess != err) { 21 | fprintf(stderr, "%s(%i) : cudaSafeCallNoSync() Runtime API error %d : %s.\n", 22 | file, line, (int)err, cudaGetErrorString(err)); 23 | exit(-1); 24 | } 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/Buffers/Makefile: -------------------------------------------------------------------------------- 1 | GTEST_DIR=~/gtest 2 | INC_PATH+=-I $(GTEST_DIR)/include -I/usr/local/cuda/include -I./ 3 | LIB_PATH+=-L $(GTEST_DIR)/lib -L/usr/local/cuda/lib64 4 | LIBS= 5 | LIBS+=-lgtest_main -lgtest -pthread -lcuda -lcudart 6 | 7 | #CXXFLAGS+=$(LIBS) $(INC_PATH) $(LIB_PATH) -std=c++0x -g -O0 8 | CXXFLAGS+=$(LIBS) $(INC_PATH) $(LIB_PATH) -std=c++0x -O3 9 | #CXX=/scr_3/gcc/gcc-4.6.3/bin/g++ 10 | 11 | BUFFER_OBJECT_FILES=Buffer.o CPUBuffer.o GPUBuffer.o PinnedCPUBuffer.o 12 | all: $(BUFFER_OBJECT_FILES) 13 | 14 | example: bufferExample 15 | 16 | bufferExample: bufferExample.cpp $(BUFFER_OBJECT_FILES) 17 | 18 | tests=test_CPUBuffer test_GPUBuffer 19 | 20 | CPUBuffer.o: Buffer.o CPUBuffer.h CPUBuffer.cpp 21 | GPUBuffer.o: Buffer.o GPUBuffer.h GPUBuffer.cpp 22 | PinnedCPUBuffer.o: Buffer.o PinnedCPUBuffer.h PinnedCPUBuffer.cpp 23 | 24 | test_CPUBuffer: test_CPUBuffer.cpp GPUBuffer.o CPUBuffer.o Buffer.o 25 | 26 | test_GPUBuffer: test_GPUBuffer.cpp GPUBuffer.o CPUBuffer.o Buffer.o 27 | 28 | .PHONY: check 29 | check: $(tests) 30 | for t in $(tests) ; do \ 31 | ./$$t ; \ 32 | done 33 | 34 | .PHONY: clean 35 | clean: 36 | rm -f $(tests) *.o 37 | 38 | -------------------------------------------------------------------------------- /src/Buffers/bufferExample.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int main(int argn, char** argv) 9 | { 10 | // Size of vector 11 | static const int N = 10; 12 | // 13 | // Input data 14 | float v[10] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}; 15 | 16 | // Create a Buffer on the host side 17 | CPUBuffer v_cpu(sizeof(v)); 18 | 19 | // Set the buffer from the input data 20 | v_cpu.setFrom(v, 0, sizeof(v), 0); 21 | 22 | // Print contents of v_cpu 23 | std::cout << "Data before transfer to GPU:\n"; 24 | v_cpu.dump(std::cout, N); 25 | 26 | // Create Buffer on the GPU (cuda device ID 0) 27 | GPUBuffer v_gpu(sizeof(v), 0); 28 | 29 | // Copy data from CPU to GPU 30 | v_cpu.set(&v_gpu, 0, v_cpu.getSize(), 0); 31 | 32 | // Create another Buffer on the CPU 33 | CPUBuffer v2_cpu(sizeof(v)); 34 | 35 | // Transfer data back from GPU to the CPU 36 | v_gpu.set(&v2_cpu, 0, v_gpu.getSize(), 0); 37 | 38 | // Print contents of output buffer 39 | std::cout << "Data after transfer to GPU:\n"; 40 | v2_cpu.dump(std::cout, N); 41 | 42 | // Upon exiting the scope of the program the memory associated with 43 | // the various Buffers (CPU and GPU) is automatically deallocated. 44 | return 0; 45 | } 46 | 47 | /** \example bufferExample.cpp 48 | * @brief This is an example of how to use the Buffer classes for memory 49 | * management and data transfers. 50 | */ 51 | 52 | -------------------------------------------------------------------------------- /VStutio_project/VStutio_project.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /VStutio_project/Buffers/Buffers.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/cudaSirecon/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories( 2 | ${CMAKE_CURRENT_SOURCE_DIR} 3 | "${CMAKE_CURRENT_SOURCE_DIR}/../Buffers") 4 | 5 | find_package(LAPACK REQUIRED) 6 | message(STATUS "IMLIB: " ${IMLIB}) 7 | message(STATUS "IVELIB: " ${IVELIB}) 8 | message(STATUS "LEG_STDIO: " ${LEG_STDIO}) 9 | message(STATUS "LAPACK_FOUND: " ${LAPACK_FOUND}) 10 | 11 | # libcudasirecon shared library 12 | add_library(cudasirecon SHARED cudaSirecon.cpp boostfs.cpp gpuFunctionsImpl.cu interface.cpp) 13 | cuda_add_cufft_to_target(cudasirecon) 14 | set_target_properties(cudasirecon 15 | PROPERTIES 16 | MSVC_RUNTIME_LIBRARY "" 17 | WINDOWS_EXPORT_ALL_SYMBOLS TRUE) 18 | target_link_libraries( 19 | cudasirecon 20 | Buffer 21 | ${TIFF_LIBRARIES} 22 | ${LAPACK_LIBRARIES} 23 | ${BOOST_LIBRARIES} 24 | ${Boost_PROGRAM_OPTIONS_LIBRARY} 25 | ${Boost_FILESYSTEM_LIBRARY} 26 | ${IMLIB} 27 | ${IVELIB}) 28 | 29 | 30 | # cudasirecon executable file 31 | add_executable(cudaSireconDriver cudaSireconDriver.cpp) 32 | cuda_add_cufft_to_target(cudaSireconDriver) 33 | target_link_libraries(cudaSireconDriver cudasirecon) 34 | target_include_directories(cudaSireconDriver PUBLIC "${PROJECT_BINARY_DIR}") 35 | set_target_properties(cudaSireconDriver 36 | PROPERTIES 37 | MSVC_RUNTIME_LIBRARY "" 38 | OUTPUT_NAME cudasirecon) 39 | 40 | 41 | if(WIN32) 42 | if(${MSVC_VERSION} GREATER 1800) 43 | target_link_libraries(cudasirecon ${LEG_STDIO}) 44 | target_link_libraries(cudaSireconDriver ${LEG_STDIO}) 45 | endif() 46 | else() 47 | target_link_libraries(cudasirecon rt) 48 | endif(WIN32) 49 | 50 | # added for make install to work in conda 51 | set(HEADERS cudaSirecon.h cudaSireconImpl.h gpuFunctions.h) 52 | 53 | install( 54 | TARGETS cudaSireconDriver cudasirecon 55 | RUNTIME DESTINATION bin 56 | LIBRARY DESTINATION lib 57 | ARCHIVE DESTINATION lib) 58 | 59 | install(FILES ${HEADERS} DESTINATION include) 60 | -------------------------------------------------------------------------------- /src/Buffers/PinnedCPUBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef PINNED_CPU_BUFFER_H 2 | #define PINNED_CPU_BUFFER_H 3 | 4 | #include "Buffer.h" 5 | #include "CPUBuffer.h" 6 | 7 | #include 8 | 9 | class GPUBuffer; 10 | 11 | /** 12 | * @brief Buffer class for managing pinned host memory. 13 | */ 14 | class PinnedCPUBuffer : public CPUBuffer { 15 | 16 | public: 17 | /** Constructor. */ 18 | PinnedCPUBuffer(); 19 | /** Constructor with a certain size. 20 | * @param size Size of buffer.*/ 21 | PinnedCPUBuffer(size_t size); 22 | /** Copy constructor.*/ 23 | PinnedCPUBuffer(const Buffer& toCopy); 24 | /** Assignment operator.*/ 25 | PinnedCPUBuffer& operator=(const Buffer& rhs); 26 | /** Destructor.*/ 27 | virtual ~PinnedCPUBuffer(); 28 | 29 | /** Get current size of buffer.*/ 30 | virtual size_t getSize() const { return size_; } ; 31 | /** Get pointer to the memory managed by the buffer. This is a host 32 | * pointer.*/ 33 | virtual void* getPtr() { return ptr_; } ; 34 | virtual const void* getPtr() const { return ptr_; } ; 35 | /** Resize the buffer. The old data becomes invalid after a call to 36 | * resize. 37 | * @param newsize New size of buffer. 38 | * */ 39 | virtual void resize(size_t newsize); 40 | 41 | virtual void set(Buffer* dest, size_t srcBegin, size_t srcEnd, 42 | size_t destBegin) const; 43 | 44 | virtual void setFrom(const CPUBuffer& src, size_t srcBegin, 45 | size_t srcEnd, size_t destBegin); 46 | virtual void setFrom(const PinnedCPUBuffer& src, size_t srcBegin, 47 | size_t srcEnd, size_t destBegin); 48 | virtual void setFrom(const GPUBuffer& src, size_t srcBegin, 49 | size_t srcEnd, size_t destBegin); 50 | virtual void setFrom(const void* src, size_t srcBegin, 51 | size_t srcEnd, size_t destBegin); 52 | 53 | virtual bool hasNaNs(bool verbose = false) const; 54 | 55 | private: 56 | size_t size_; 57 | char* ptr_; 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/cudaSirecon/interface.cpp: -------------------------------------------------------------------------------- 1 | #include "cudaSireconImpl.h" // must come first! 2 | #include "SIM_reconstructor.hpp" 3 | 4 | #ifdef _WIN32 5 | #define DllExport __declspec(dllexport) 6 | #else 7 | #define DllExport 8 | #endif 9 | 10 | extern "C" 11 | { 12 | 13 | DllExport SIM_Reconstructor *SR_new_from_shape(int nx, int ny, int nImages, 14 | const char *configFileName) 15 | { 16 | return new SIM_Reconstructor(nx, ny, nImages, configFileName); 17 | } 18 | 19 | DllExport void SR_setRaw(SIM_Reconstructor *sr, 20 | const float *const raw_data, 21 | int nx, int ny, int nz) 22 | { 23 | CImg raw_image(raw_data, nx, ny, nz); 24 | sr->setRaw(raw_image); 25 | } 26 | DllExport void SR_loadAndRescaleImage(SIM_Reconstructor *sr, int it, int iw) 27 | { 28 | sr->loadAndRescaleImage(it, iw); 29 | } 30 | DllExport void SR_setCurTimeIdx(SIM_Reconstructor *sr, int it) 31 | { 32 | sr->setCurTimeIdx(it); 33 | } 34 | DllExport void SR_processOneVolume(SIM_Reconstructor *sr) 35 | { 36 | sr->processOneVolume(); 37 | } 38 | DllExport void SR_getResult(SIM_Reconstructor *sr, float *result) 39 | { 40 | return sr->getResult(result); 41 | } 42 | DllExport ReconParams &SR_getReconParams(SIM_Reconstructor *sr) 43 | { 44 | return sr->getReconParams(); 45 | } 46 | 47 | DllExport ImageParams &SR_getImageParams(SIM_Reconstructor *sr) 48 | { 49 | return sr->getImageParams(); 50 | } 51 | 52 | // these functions only used to emulate cli 53 | 54 | DllExport SIM_Reconstructor *SR_new_from_argv(int argc, char **argv) 55 | { 56 | return new SIM_Reconstructor(argc, argv); 57 | } 58 | 59 | DllExport void SR_setFile(SIM_Reconstructor *sr, int it, int iw) 60 | { 61 | sr->setFile(it, iw); 62 | } 63 | DllExport void SR_writeResult(SIM_Reconstructor *sr, int it, int iw) 64 | { 65 | sr->writeResult(it, iw); 66 | } 67 | DllExport void SR_closeFiles(SIM_Reconstructor *sr) 68 | { 69 | sr->closeFiles(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/otf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories("${CMAKE_SOURCE_DIR}/cudaSirecon") # for CImg.h 2 | add_executable(makeotf radialft.cpp) 3 | 4 | if(BUILD_MRC OR BUILD_OTF_VIEWER) 5 | target_link_libraries(makeotf ${IMLIB} ${IVELIB}) 6 | endif() 7 | 8 | # ######## START findFFTW: https://github.com/egpbos/findFFTW ###### 9 | 10 | configure_file(downloadFindFFTW.cmake.in findFFTW-download/CMakeLists.txt) 11 | execute_process( 12 | COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 13 | RESULT_VARIABLE result 14 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/findFFTW-download) 15 | if(result) 16 | message(FATAL_ERROR "CMake step for findFFTW failed: ${result}") 17 | else() 18 | message("CMake step for findFFTW completed (${result}).") 19 | endif() 20 | execute_process( 21 | COMMAND ${CMAKE_COMMAND} --build . 22 | RESULT_VARIABLE result 23 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/findFFTW-download) 24 | if(result) 25 | message(FATAL_ERROR "Build step for findFFTW failed: ${result}") 26 | endif() 27 | 28 | set(findFFTW_DIR ${CMAKE_CURRENT_BINARY_DIR}/findFFTW-src) 29 | 30 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${findFFTW_DIR}") 31 | 32 | # ######## END findFFTW ########################################## 33 | 34 | if(WIN32) 35 | find_package(FFTW REQUIRED COMPONENTS FLOAT_LIB) 36 | # include_directories( ${FFTW_INCLUDE_DIRS} ) 37 | if(${MSVC_VERSION} GREATER 1800) 38 | target_link_libraries(makeotf ${LEG_STDIO}) 39 | endif() 40 | else() 41 | find_package(FFTW REQUIRED COMPONENTS FLOAT_THREADS_LIB) 42 | endif() 43 | 44 | message(STATUS "FFTW3 libraries: " ${FFTW_LIBRARIES}) 45 | target_link_libraries(makeotf ${FFTW_LIBRARIES} ${TIFF_LIBRARIES}) 46 | 47 | install(TARGETS makeotf RUNTIME DESTINATION bin) 48 | 49 | if(BUILD_OTF_VIEWER) 50 | message(STATUS "Build OTF Viewer: TRUE") 51 | 52 | include_directories(${PRIISM_INCLUDE_PATH}) 53 | link_directories(${PRIISM_LIB_PATH}) 54 | add_executable(otfviewer otfviewer.cpp) 55 | target_link_libraries(otfviewer ${IMLIB} ${IVELIB} ${TIFF_LIBRARIES}) 56 | 57 | if(WIN32) 58 | if(${MSVC_VERSION} GREATER 1800) 59 | target_link_libraries(otfviewer ${LEG_STDIO}) 60 | endif() 61 | else() 62 | find_package(X11 REQUIRED) 63 | target_link_libraries(otfviewer ${X11_LIBRARIES}) 64 | endif() 65 | 66 | install(TARGETS otfviewer RUNTIME DESTINATION bin) 67 | endif() 68 | -------------------------------------------------------------------------------- /src/cudaSirecon/boostfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // requires c++11 3 | #include 4 | #include 5 | #include // sort 6 | 7 | static boost::filesystem::path outputDir; 8 | 9 | std::vector gatherMatchingFiles(std::string target_path, std::string pattern) 10 | { 11 | // Check if the pattern is specified as a full file name (i.e.; if '.tif' is in the name) 12 | size_t p1 = pattern.rfind(".tif"); 13 | size_t p2 = pattern.rfind(".TIF"); 14 | if (p1 != std::string::npos || p2 != std::string::npos) { 15 | // if no matches were found, rfind() returns 'string::npos' 16 | // do not append ".*tif" at the end of pattern 17 | } 18 | else 19 | pattern.append(".*\\.[tT][iI][fF]"); 20 | pattern.insert(0, ".*"); // '.' is the wildcard in Perl regexp; '*' just means "repeat". 21 | 22 | const std::regex my_filter(pattern); 23 | 24 | std::vector< std::string > all_matching_files; 25 | 26 | boost::filesystem::directory_iterator end_itr; // Constructs the end iterator. 27 | for (boost::filesystem::directory_iterator i(target_path); i != end_itr; ++i) { 28 | 29 | // Skip if not a file 30 | if( !boost::filesystem::is_regular_file( i->status() ) ) continue; 31 | 32 | std::smatch what; 33 | 34 | auto fname = i->path().string(); //somehow this local variable is necessary with VS2017 35 | // With GCC 7.5 this variable is not needed; in-place "i->path().string()" is enough 36 | 37 | // Skip if no match 38 | if( !std::regex_match(fname/*i->path().string()*/, what, my_filter) ) continue; 39 | 40 | // File matches, store it 41 | all_matching_files.push_back(fname /*i->path().string()*/); 42 | } 43 | 44 | // sort file names so that earlier time points will be processed first: 45 | sort(all_matching_files.begin(), all_matching_files.end()); 46 | 47 | 48 | // Create output subfolder "decon/" just under the data folder: 49 | outputDir = target_path; 50 | outputDir /= "GPUsirecon"; 51 | 52 | if (! boost::filesystem::exists(outputDir) ) 53 | boost::filesystem::create_directory(outputDir); 54 | 55 | return all_matching_files; 56 | } 57 | 58 | 59 | std::string makeOutputFilePath(std::string inputFileName, std::string insert) 60 | { 61 | boost::filesystem::path inputpath(inputFileName); 62 | boost::filesystem::path outputpath(outputDir); 63 | 64 | std::string basename = inputpath.filename().string(); 65 | int pos = basename.find_last_of(".tif"); 66 | basename.insert(pos - 3, insert); 67 | 68 | outputpath /= basename; 69 | 70 | std::cout << "Output: " << outputpath.string() << '\n'; 71 | return outputpath.string(); 72 | } 73 | -------------------------------------------------------------------------------- /VStutio_project/VStutio_project.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Buffers", "Buffers\Buffers.vcxproj", "{AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cudaSirecon", "cudaSirecon\cudaSirecon.vcxproj", "{CFD235C6-F483-472C-B9AF-F26F8631C2CD}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF} = {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Mixed Platforms = Debug|Mixed Platforms 16 | Debug|Win32 = Debug|Win32 17 | Debug|x64 = Debug|x64 18 | Release|Mixed Platforms = Release|Mixed Platforms 19 | Release|Win32 = Release|Win32 20 | Release|x64 = Release|x64 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 24 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Debug|Mixed Platforms.Build.0 = Debug|Win32 25 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Debug|Win32.ActiveCfg = Debug|Win32 26 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Debug|Win32.Build.0 = Debug|Win32 27 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Debug|x64.ActiveCfg = Debug|Win32 28 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Release|Mixed Platforms.ActiveCfg = Release|x64 29 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Release|Mixed Platforms.Build.0 = Release|x64 30 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Release|Win32.ActiveCfg = Release|Win32 31 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Release|Win32.Build.0 = Release|Win32 32 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Release|x64.ActiveCfg = Release|x64 33 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF}.Release|x64.Build.0 = Release|x64 34 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 35 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Debug|Mixed Platforms.Build.0 = Debug|Win32 36 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Debug|Win32.ActiveCfg = Debug|Win32 37 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Debug|Win32.Build.0 = Debug|Win32 38 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Debug|x64.ActiveCfg = Debug|x64 39 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Debug|x64.Build.0 = Debug|x64 40 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Release|Mixed Platforms.ActiveCfg = Release|Win32 41 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Release|Mixed Platforms.Build.0 = Release|Win32 42 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Release|Win32.ActiveCfg = Release|Win32 43 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Release|Win32.Build.0 = Release|Win32 44 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Release|x64.ActiveCfg = Release|x64 45 | {CFD235C6-F483-472C-B9AF-F26F8631C2CD}.Release|x64.Build.0 = Release|x64 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /src/Buffers/test_GPUBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "Buffer.h" 3 | #include "GPUBuffer.h" 4 | #include "CPUBuffer.h" 5 | #include 6 | 7 | 8 | int compareArrays(char* arr1, char* arr2, int size); 9 | 10 | TEST(GPUBuffer, IncludeTest) { 11 | ASSERT_EQ(0, 0); 12 | } 13 | TEST(GPUBuffer, ConstructorTest) { 14 | GPUBuffer a; 15 | ASSERT_EQ(0, a.getSize()); 16 | ASSERT_EQ(0, a.getPtr()); 17 | GPUBuffer b(4 * sizeof(float), 0); 18 | ASSERT_EQ(4 * sizeof(float), b.getSize()); 19 | EXPECT_TRUE(0 != b.getPtr()); 20 | 21 | GPUBuffer c; 22 | GPUBuffer d(10, 0); 23 | c = d; 24 | } 25 | TEST(GPUBuffer, ResizeTest) { 26 | GPUBuffer a(0); 27 | a.resize(10); 28 | ASSERT_EQ(10, a.getSize()); 29 | EXPECT_TRUE(0 != a.getPtr()); 30 | } 31 | TEST(GPUBuffer, GPUSetTest) { 32 | CPUBuffer a; 33 | ASSERT_EQ(0, a.getSize()); 34 | ASSERT_EQ(0, a.getPtr()); 35 | a.resize(4 * sizeof(float)); 36 | float src[4] = {11.0, 22.0, 33.0, 44.0}; 37 | float result[4] = {11.0, 22.0, 33.0, 44.0}; 38 | float out[4]; 39 | a.setFrom(src, 0, sizeof(src), 0); 40 | a.setPlainArray(out, 0, a.getSize(), 0); 41 | ASSERT_EQ(0, 42 | compareArrays((char*)out, (char*)result, sizeof(result))); 43 | 44 | GPUBuffer b; 45 | b.resize(a.getSize()); 46 | a.set(&b, 0, 4 * sizeof(float), 0); 47 | 48 | GPUBuffer c; 49 | c.resize(b.getSize()); 50 | ASSERT_EQ(4 * sizeof(float), c.getSize()); 51 | b.set(&c, 0, 4 * sizeof(float), 0); 52 | 53 | CPUBuffer d; 54 | d.resize(c.getSize()); 55 | ASSERT_EQ(4 * sizeof(float), d.getSize()); 56 | c.set(&d, 0, c.getSize(), 0); 57 | d.setPlainArray(out, 0, d.getSize(), 0); 58 | ASSERT_EQ(0, 59 | compareArrays((char*)out, (char*)result, sizeof(result))); 60 | 61 | a.set(&c, 0, 2 * sizeof(float), 2 * sizeof(float)); 62 | c.dump(std::cout, 2); 63 | c.set(&d, 0, c.getSize(), 0); 64 | d.setPlainArray(out, 0, d.getSize(), 0); 65 | float result2[] = {11.0, 22.0, 11.0, 22.0}; 66 | ASSERT_EQ(0, 67 | compareArrays((char*)out, (char*)result2, sizeof(result2))); 68 | 69 | } 70 | TEST(GPUBuffer, DumpTest) { 71 | CPUBuffer a; 72 | ASSERT_EQ(0, a.getSize()); 73 | ASSERT_EQ(0, a.getPtr()); 74 | a.resize(4 * sizeof(float)); 75 | float src[4] = {11.0, 22.0, 33.0, 44.0}; 76 | float result[4] = {11.0, 22.0, 33.0, 44.0}; 77 | float out[4]; 78 | a.setFrom(src, 0, sizeof(src), 0); 79 | a.setPlainArray(out, 0, a.getSize(), 0); 80 | ASSERT_EQ(0, 81 | compareArrays((char*)out, (char*)result, sizeof(result))); 82 | 83 | GPUBuffer b; 84 | b.resize(a.getSize()); 85 | a.set(&b, 0, 4 * sizeof(float), 0); 86 | 87 | GPUBuffer c; 88 | c.resize(b.getSize()); 89 | ASSERT_EQ(4 * sizeof(float), c.getSize()); 90 | b.set(&c, 0, 4 * sizeof(float), 0); 91 | c.dump(std::cout, 2); 92 | } 93 | 94 | int compareArrays(char* arr1, char* arr2, int size) { 95 | int difference = 0; 96 | for (int i = 0; i < size; ++i) { 97 | difference += abs(arr1[i] - arr2[i]); 98 | } 99 | return difference; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/cudaSirecon/mrc.h: -------------------------------------------------------------------------------- 1 | // MRC-specific functionality 2 | #include "cudaSirecon.h" 3 | #include "IM.h" 4 | #include "IMInclude.h" 5 | #include "IWApiConstants.h" 6 | 7 | #if defined(_MSC_VER) && (_MSC_VER >= 1900) 8 | // for IMLIB with vs >2015 9 | // https://stackoverflow.com/questions/30412951/unresolved-external-symbol-imp-fprintf-and-imp-iob-func-sdl2 10 | FILE _iob[] = {*stdin, *stdout, *stderr}; 11 | extern "C" FILE *__cdecl __iob_func(void) 12 | { 13 | return _iob; 14 | } 15 | #endif 16 | 17 | // MRC header parser 18 | void loadHeader(const ReconParams& params, ImageParams* imgParams, 19 | IW_MRC_HEADER& header) { 20 | int ixyz[3]; 21 | int mxyz[3]; 22 | int pixeltype; 23 | float min; 24 | float max; 25 | float mean; 26 | IMRdHdr(istream_no, ixyz, mxyz, &pixeltype, &min, &max, &mean); 27 | IMGetHdr(istream_no, &header); 28 | imgParams->nx = 0; // deferred till deskewing situation is figured out 29 | imgParams->nx_raw = header.nx; 30 | imgParams->ny = header.ny; 31 | imgParams->nz = header.nz / (header.num_waves * header.num_times); 32 | /* header.nz is defined as the total number of sections = 33 | * nz*nwaves*ntimes (* ndirs*nphases in our case) */ 34 | imgParams->nz /= params.nphases * params.ndirs; 35 | imgParams->nwaves = header.num_waves; 36 | imgParams->ntimes = header.num_times; 37 | imgParams->wave[0] = header.iwav1; 38 | imgParams->wave[1] = header.iwav2; 39 | imgParams->wave[2] = header.iwav3; 40 | imgParams->wave[3] = header.iwav4; 41 | imgParams->wave[4] = header.iwav5; 42 | //! dxy: lateral pixel size; dz: axial pixel size; both in microns */ 43 | imgParams->dxy = header.ylen; 44 | imgParams->dz = header.zlen; 45 | } 46 | 47 | void setOutputHeader(const ReconParams& myParams, const ImageParams& imgParams, 48 | IW_MRC_HEADER& header) { 49 | header.mode = IW_FLOAT; 50 | header.nz = 51 | imgParams.nz * imgParams.nwaves * imgParams.ntimes * myParams.z_zoom; 52 | header.nx = imgParams.nx * myParams.zoomfact; 53 | header.ny *= myParams.zoomfact; 54 | header.xlen /= myParams.zoomfact; 55 | header.ylen /= myParams.zoomfact; 56 | header.zlen /= myParams.z_zoom; 57 | header.inbsym = 0; 58 | IMPutHdr(ostream_no, &header); 59 | IMAlCon(ostream_no, 0); 60 | } 61 | 62 | void saveCommandLineToHeader(int argc, char** argv, IW_MRC_HEADER& header, 63 | const ReconParams& myParams) { 64 | char titles[1000]; 65 | titles[0] = '\0'; 66 | for (int i = 3; i < argc; ++i) { 67 | strcat(titles, argv[i]); 68 | strcat(titles, " "); 69 | } 70 | if (myParams.bWriteTitle) { 71 | IMAlLab(ostream_no, titles, strlen(titles) / 80 + 1); 72 | } 73 | IMWrHdr(ostream_no, header.label, 1, header.amin, header.amax, header.amean); 74 | } 75 | 76 | int saveIntermediateDataForDebugging(const ReconParams& params) { 77 | if (params.bSaveSeparated) { 78 | IMWrHdr(separated_stream_no, "separated bands of all directions", 1, 0, 1, 0); 79 | IMClose(separated_stream_no); 80 | } 81 | if (params.bSaveAlignedRaw) { 82 | IMWrHdr(aligned_stream_no, "drift-corrected raw images", 1, 83 | aligned_header.amin, aligned_header.amax, aligned_header.amean); 84 | IMClose(aligned_stream_no); 85 | } 86 | if (params.bSaveOverlaps) { 87 | IMWrHdr(overlaps_stream_no, "overlaps in real space", 1, 0, 1, 0); 88 | IMClose(overlaps_stream_no); 89 | } 90 | if (params.bSaveSeparated || params.bSaveAlignedRaw || params.bSaveOverlaps) { 91 | printf( 92 | "\nQuit processing because either bSaveSeparated, " 93 | "bSaveAlignedRaw, or bSaveOverlaps is TRUE\n"); 94 | return 1; 95 | } 96 | return 0; 97 | } -------------------------------------------------------------------------------- /src/cudaSirecon/gpuFunctions.h: -------------------------------------------------------------------------------- 1 | #ifndef GPU_FUNCTIONS_H 2 | #define GPU_FUNCTIONS_H 3 | 4 | #include "GPUBuffer.h" 5 | #include "cudaSireconImpl.h" 6 | 7 | #include 8 | 9 | struct vector; 10 | struct vector3d; 11 | struct ReconParams; 12 | 13 | /* 14 | returns alpha*a + beta*b in a 15 | offset is an offset into a 16 | len is the number of elements in the vectors a and b 17 | imSrc can be a NULL pointer, in which case only fDest*imDest will be returned 18 | */ 19 | void image_arithmetic(GPUBuffer* a, const GPUBuffer& b, int offset, 20 | int len, float alpha, float beta); 21 | void image_arithmetic(GPUBuffer* a, const GPUBuffer& b, 22 | int offsetA, int offsetB, 23 | int len, float alpha, float beta); 24 | 25 | void apodize(int napodize, int nx,int ny, GPUBuffer* image, int offset); 26 | void cosapodize(int nx,int ny, GPUBuffer* image, int offset); 27 | void rescale(int nx, int ny, int nz, int z, int zoffset, int direction, 28 | int wave, int t, int phases, std::vector* images, int equalizez, 29 | int equalizet, double* sum_dir0_phase0); 30 | 31 | int calcRefImage(const std::vector& rawImages, 32 | GPUBuffer* refImage, const std::vector& offImages, 33 | int nOffImages, int nx, int ny, int nphases, int type_of_refImage); 34 | 35 | void fixdrift_2D(std::vector* CrawImages, 36 | vector3d *driftlist, int nphases, int nx, int ny, int nz, int dir, 37 | int z); 38 | 39 | void separate(int nx, int ny, int z, int direction, int nphases, int 40 | norders, std::vector*rawImages, float *sepMatrix); 41 | 42 | void makemodeldata(int nx, int ny, int nz, std::vector* bands, 43 | int norders, vector k0, float dy, float dz, 44 | std::vector* OTF, short wave, ReconParams *pParams); 45 | 46 | void fixdrift_bt_dirs(std::vector* bands, int norders, 47 | vector3d drift, int nx,int ny, int nz); 48 | 49 | void findk0(std::vector* bands, GPUBuffer* overlap0, 50 | GPUBuffer* overlap1, int nx, int ny, int nz, int norders, vector *k0, 51 | float dy, float dz, std::vector* OTF, short wave, 52 | ReconParams * pParams); 53 | 54 | void fitk0andmodamps(std::vector* bands, GPUBuffer* overlap0, 55 | GPUBuffer* overlap1, int nx, int ny, int nz, int norders, 56 | vector *k0, float dxy, float dz, std::vector* otf, short wave, 57 | cuFloatComplex* amps, ReconParams * pParams); 58 | 59 | float findrealspacemodamp(std::vector* bands, 60 | GPUBuffer* overlap0, GPUBuffer* overlap1, int nx, int ny, int nz, 61 | int order1, int order2, vector k0, float dy, float dz, 62 | std::vector* OTF, short wave, cuFloatComplex* modamp1, 63 | cuFloatComplex* modamp2, cuFloatComplex* modamp3, int redoarrays, 64 | ReconParams *pParams); 65 | 66 | void filterbands(int dir, std::vector* bands, 67 | const std::vector& k0, int ndirs, int norders, 68 | std::vector& otf, float dy, float dz, 69 | const std::vector >& amp, 70 | const std::vector& noiseVarFactors, int nx, int ny, int nz, 71 | short wave, ReconParams* params); 72 | 73 | void assemblerealspacebands(int dir, GPUBuffer* outbuffer, GPUBuffer* bigbuffer, 74 | std::vector* bands, int ndirs, int norders, 75 | const std::vector& k0, int nx, int ny, int nz, 76 | float dxy, float zoomfact, 77 | int z_zoom, float expfact); 78 | 79 | void computeAminAmax(const GPUBuffer* data, int nx, int ny, int nz, 80 | float* min, float* max); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/Buffers/test_CPUBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "Buffer.h" 2 | #include "CPUBuffer.h" 3 | #include "GPUBuffer.h" 4 | #include "gtest/gtest.h" 5 | #include 6 | 7 | 8 | int compareArrays(char* arr1, char* arr2, int size); 9 | TEST(CPUBuffer, IncludeTest) { 10 | ASSERT_EQ(0, 0); 11 | } 12 | TEST(CPUBuffer, ConstructorTest) { 13 | CPUBuffer a; 14 | ASSERT_EQ(0, a.getSize()); 15 | ASSERT_EQ(0, a.getPtr()); 16 | CPUBuffer b(4 * sizeof(float)); 17 | ASSERT_EQ(4 * sizeof(float), b.getSize()); 18 | EXPECT_TRUE(0 != b.getPtr()); 19 | } 20 | TEST(CPUBuffer, ResizeTest) { 21 | CPUBuffer a; 22 | a.resize(10); 23 | ASSERT_EQ(10, a.getSize()); 24 | EXPECT_TRUE(0 != a.getPtr()); 25 | } 26 | TEST(CPUBuffer, SetFromPlainArrayTest) { 27 | CPUBuffer a; 28 | ASSERT_EQ(0, a.getSize()); 29 | ASSERT_EQ(0, a.getPtr()); 30 | a.resize(4 * sizeof(float)); 31 | float src[4] = {11.0, 22.0, 33.0, 44.0}; 32 | float result[4] = {11.0, 22.0, 33.0, 44.0}; 33 | float out[4]; 34 | a.setFrom(src, 0, sizeof(src), 0); 35 | a.setPlainArray(out, 0, a.getSize(), 0); 36 | ASSERT_EQ(0, 37 | compareArrays((char*)out, (char*)result, sizeof(result))); 38 | } 39 | TEST(CPUBuffer, SetTest) { 40 | CPUBuffer a; 41 | ASSERT_EQ(0, a.getSize()); 42 | ASSERT_EQ(0, a.getPtr()); 43 | a.resize(4 * sizeof(float)); 44 | float src[4] = {11.0, 22.0, 33.0, 44.0}; 45 | float result[4] = {11.0, 22.0, 33.0, 44.0}; 46 | float out[4]; 47 | a.setFrom(src, 0, sizeof(src), 0); 48 | a.setPlainArray(out, 0, a.getSize(), 0); 49 | ASSERT_EQ(0, 50 | compareArrays((char*)out, (char*)result, sizeof(result))); 51 | 52 | CPUBuffer b; 53 | b.resize(a.getSize()); 54 | a.set(&b, 0, 4 * sizeof(float), 0); 55 | b.setPlainArray(out, 0, b.getSize(), 0); 56 | ASSERT_EQ(0, 57 | compareArrays((char*)out, (char*)result, sizeof(result))); 58 | } 59 | TEST(CPUBuffer, TakeOwnershipTest) { 60 | CPUBuffer a; 61 | float* src = new float[4]; 62 | src[0] = 11.0; 63 | src[1] = 22.0; 64 | src[2] = 33.0; 65 | src[3] = 44.0; 66 | float result[4] = {11.0, 22.0, 33.0, 44.0}; 67 | a.takeOwnership(src, 4 * sizeof(float)); 68 | ASSERT_EQ(0, 69 | compareArrays((char*)a.getPtr(), (char*)result, sizeof(result))); 70 | } 71 | TEST(CPUBuffer, Dump) { 72 | CPUBuffer a; 73 | float* src = new float[4]; 74 | src[0] = 11.0; 75 | src[1] = 22.0; 76 | src[2] = 33.0; 77 | src[3] = 44.0; 78 | a.takeOwnership(src, 4 * sizeof(float)); 79 | a.dump(std::cout, 2); 80 | ASSERT_EQ(0, 0); 81 | } 82 | TEST(CPUBuffer, GPUSetTest) { 83 | CPUBuffer a; 84 | ASSERT_EQ(0, a.getSize()); 85 | ASSERT_EQ(0, a.getPtr()); 86 | a.resize(4 * sizeof(float)); 87 | float src[4] = {11.0, 22.0, 33.0, 44.0}; 88 | float result[4] = {11.0, 22.0, 33.0, 44.0}; 89 | float out[4]; 90 | a.setFrom(src, 0, sizeof(src), 0); 91 | a.setPlainArray(out, 0, a.getSize(), 0); 92 | ASSERT_EQ(0, 93 | compareArrays((char*)out, (char*)result, sizeof(result))); 94 | 95 | GPUBuffer b; 96 | b.resize(a.getSize()); 97 | a.set(&b, 0, 4 * sizeof(float), 0); 98 | 99 | CPUBuffer c; 100 | c.resize(b.getSize()); 101 | ASSERT_EQ(4 * sizeof(float), c.getSize()); 102 | b.set(&c, 0, 4 * sizeof(float), 0); 103 | c.setPlainArray(out, 0, c.getSize(), 0); 104 | ASSERT_EQ(0, 105 | compareArrays((char*)out, (char*)result, sizeof(result))); 106 | } 107 | 108 | int compareArrays(char* arr1, char* arr2, int size) { 109 | int difference = 0; 110 | for (int i = 0; i < size; ++i) { 111 | difference += abs(arr1[i] - arr2[i]); 112 | } 113 | return difference; 114 | } 115 | 116 | -------------------------------------------------------------------------------- /src/otf/otfviewer.cpp: -------------------------------------------------------------------------------- 1 | //! Requires C++11 2 | 3 | #define cimg_use_tiff 4 | #define cimg_use_cpp11 1 5 | #include "CImg.h" 6 | using namespace cimg_library; 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #if defined(_MSC_VER) && (_MSC_VER >= 1900) 13 | // for IMLIB with vs >2015 14 | // https://stackoverflow.com/questions/30412951/unresolved-external-symbol-imp-fprintf-and-imp-iob-func-sdl2 15 | FILE _iob[] = {*stdin, *stdout, *stderr}; 16 | 17 | extern "C" FILE * __iob_func(void) 18 | { 19 | return _iob; 20 | } 21 | 22 | #endif 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | 27 | bool bRotatedFull = false; 28 | float gamma = 0.4; 29 | 30 | if (argc < 2) { 31 | std::cerr << "Need at least one argument" << 32 | "Usage: otfviewer [-g gamma_value] [-a] OTF_file_name\n" << 33 | " -g: gamma_value (default is 0.4)\n" << 34 | " -a: to display OTF in full F space with vertical axis being kz\n"; 35 | return 0; 36 | } 37 | 38 | int flags, opt; 39 | while ((opt = getopt(argc, argv, "ag:")) != -1) { 40 | switch (opt) { 41 | case 'a': 42 | bRotatedFull = true; 43 | break; 44 | case 'g': 45 | gamma = std::stod(optarg); 46 | break; 47 | default: 48 | std::cerr << "\nUsage: otfviewer [-g gamma_value] [-a] OTF_file_name \n" << 49 | " -g: gamma_value (default is 0.4)\n" << 50 | " -a: to display OTF in full F space with vertical axis being kz\n"; 51 | return 0; 52 | } 53 | } 54 | TIFFSetWarningHandler(NULL); 55 | TIFFSetErrorHandler(NULL); 56 | TIFF *tf = TIFFOpen(argv[optind], "r"); 57 | CImg<> atiff; 58 | if (tf) { 59 | TIFFClose(tf); 60 | atiff.assign(argv[optind]); 61 | } 62 | else { 63 | std::cout << "Not a TIFF file; now try MRC\n"; 64 | int istream_no = 1; 65 | // Suppress IM header printout; somehow only in this mode would the rest of 66 | // IM calls go well on Windows. 67 | IMAlPrt(0); 68 | 69 | if (IMOpen(istream_no, argv[optind], "ro")) { 70 | std::cerr << "File " << argv[optind] << " cannot be opened.\n"; 71 | return -1; 72 | } 73 | int ixyz[3], mxyz[3], nxyzst[3], pixeltype; 74 | float mmm[3]; 75 | IW_MRC_HEADER header; 76 | 77 | IMRdHdr(istream_no, ixyz, mxyz, &pixeltype, mmm, mmm+1, mmm+2); 78 | IMGetHdr(istream_no, &header); 79 | 80 | atiff.assign(header.nx * 2, header.ny, header.nz); 81 | for (int z=0; z amplitudes(atiff.width()/2, atiff.height(), atiff.depth()); 87 | cimg_forXYZ(amplitudes, x, y, z) { 88 | float r = atiff(2*x, y, z); 89 | float i = atiff(2*x+1, y, z); 90 | amplitudes(x, y, z) = pow(std::sqrt(r*r + i*i), gamma); 91 | } 92 | 93 | if (bRotatedFull) { 94 | CImg<> ampAlt(amplitudes.height()*2-1, amplitudes.width(), amplitudes.depth()); 95 | cimg_forXYZ(amplitudes, x, y, z) { 96 | int kz = x; 97 | if (x > amplitudes.width()/2) kz -= amplitudes.width(); // origin at corners 98 | ampAlt(y+amplitudes.height(), kz+amplitudes.width()/2, z) = amplitudes(x, y, z); 99 | ampAlt(amplitudes.height()-y, kz+amplitudes.width()/2, z) = amplitudes(x, y, z); 100 | } 101 | 102 | amplitudes = ampAlt; 103 | } 104 | 105 | amplitudes.display(argv[optind], false); 106 | 107 | // Somehow doubled XY image looks the same: 108 | // CImg<> large = amplitudes.resize_doubleXY(); 109 | // std::cout << amplitudes.width() << " " << large.width() << std::endl; 110 | // large.display(argv[1], false); 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ############################################################################## 2 | # Build instruction for CUDA SIMrecon project 3 | # 4 | # 1. Use conda to set up dependencies: conda env create -f environment.yml # for 5 | # linux conda env create -f environment_win.yml # for windows conda activate 6 | # simbuild 7 | # 8 | # 1. CUDA: The linux environment comes with the cudatoolkit-dev package that 9 | # includes the nvcc compiler For windows, you will need to install the CUDA 10 | # toolkit manually 11 | # 12 | # 1. MRC/DV support (optional) If you want to build with MRC support add the IVE 13 | # libraries to the src directory with the following paths: For Linux: 14 | # src/IVE/linux64/INCLUDE src/IVE/linux64/LIB For Windows: 15 | # src/IVE/win64/INCLUDE src/IVE/win64/LIB 16 | # 17 | # If you DON'T want to build with MRC or do not have access to the IVE libraries 18 | # please run cmake with the `-DBUILD_MRC=OFF` option 19 | # 20 | # To build the otfviewer, use `-DBUILD_OTF_VIEWER=ON` 21 | # 22 | # 1. run build.sh (linux) or bld.bat (windows) inspect those scripts for more 23 | # details 24 | # 25 | # 1. If building is successful, an executable cudaSireconDriver is generated in 26 | # cmake_build/cudaSirecon. Run the test to make sure it works: $ 27 | # test_data/run.sh 28 | # 29 | # ############################################################################## 30 | 31 | option(BUILD_MRC "Build cudasirecon with MRC support" ON) 32 | option(BUILD_OTF_VIEWER "Build OTF viewer (requires X11)" OFF) 33 | 34 | cmake_minimum_required(VERSION 3.14) 35 | 36 | # This is the one place where version is set 37 | project(cudasirecon VERSION 1.2.0) 38 | configure_file("${PROJECT_SOURCE_DIR}/cudasireconConfig.h.in" "${PROJECT_SOURCE_DIR}/cudasireconConfig.h") 39 | include_directories("${PROJECT_SOURCE_DIR}") 40 | 41 | enable_language(CUDA) 42 | enable_testing() 43 | 44 | 45 | if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) 46 | set(CMAKE_CUDA_ARCHITECTURES "52;60;61;70;72;75") 47 | endif() 48 | find_package(CUDA REQUIRED) 49 | find_package(CUDAToolkit REQUIRED) 50 | message(STATUS "FOUND CUDA: " ${CUDAToolkit_BIN_DIR}) 51 | include_directories(${CUDAToolkit_INCLUDE_DIRS}) 52 | 53 | add_definitions(-Dcimg_display=0) 54 | 55 | find_package(OpenMP) 56 | message(STATUS "OpenMP FOUND: " ${OPENMP_FOUND}) 57 | if(OPENMP_FOUND) 58 | # nvcc and openmp with CImg aren't working at the moment 59 | # https://github.com/dtschump/CImg/issues/286 60 | add_definitions(-Dcimg_use_openmp=0) 61 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 62 | set(CMAKE_EXE_LINKER_FLAGS 63 | "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 64 | endif() 65 | 66 | find_package(TIFF) 67 | find_package( 68 | Boost 69 | COMPONENTS program_options filesystem system 70 | REQUIRED) 71 | link_directories(${Boost_LIBRARY_DIRS}) 72 | include_directories(${Boost_INCLUDE_DIRS}) 73 | 74 | if(WIN32) 75 | if(${MSVC_VERSION} GREATER 1800) 76 | find_library(LEG_STDIO legacy_stdio_definitions) 77 | message(STATUS "adding legacy stdio definitions for >VS14.0 " ${LEG_STDIO}) 78 | endif() 79 | endif(WIN32) 80 | 81 | message(STATUS "CUDA_NVCC_FLAGS: " ${CUDA_NVCC_FLAGS}) 82 | 83 | 84 | if(BUILD_MRC OR BUILD_OTF_VIEWER) 85 | message(STATUS "** Building WITH mrc support **") 86 | 87 | if(WIN32) 88 | set(PLATFORM win64) 89 | else() 90 | set(PLATFORM linux64) 91 | endif(WIN32) 92 | 93 | set(PRIISM_LIB_PATH "${CMAKE_SOURCE_DIR}/IVE/${PLATFORM}/LIB") 94 | set(PRIISM_INCLUDE_PATH "${CMAKE_SOURCE_DIR}/IVE/${PLATFORM}/INCLUDE") 95 | include_directories(${PRIISM_INCLUDE_PATH}) 96 | link_directories(${PRIISM_LIB_PATH}) 97 | 98 | find_library( 99 | IMLIB 100 | NAMES imlib libimlib 101 | PATHS ${PRIISM_LIB_PATH} REQUIRED) 102 | find_library( 103 | IVELIB 104 | NAMES ive libive 105 | PATHS ${PRIISM_LIB_PATH} REQUIRED) 106 | add_definitions(-DMRC) 107 | else() 108 | message(STATUS "** Building WITHOUT mrc support **") 109 | endif() 110 | 111 | add_subdirectory(Buffers) 112 | add_subdirectory(cudaSirecon) 113 | add_subdirectory(otf) 114 | -------------------------------------------------------------------------------- /src/Buffers/PinnedCPUBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "PinnedCPUBuffer.h" 2 | #include "CPUBuffer.h" 3 | #include "GPUBuffer.h" 4 | 5 | PinnedCPUBuffer::PinnedCPUBuffer() : 6 | size_(0), ptr_(0) 7 | { 8 | } 9 | 10 | PinnedCPUBuffer::PinnedCPUBuffer(size_t size) : 11 | size_(size), ptr_(0) 12 | { 13 | cudaError_t err = cudaHostAlloc((void**)&ptr_, size_, cudaHostAllocDefault); 14 | if (err != cudaSuccess) { 15 | throw std::runtime_error("cudaHostAlloc() failed."); 16 | } 17 | } 18 | 19 | PinnedCPUBuffer::PinnedCPUBuffer(const Buffer& toCopy) : 20 | size_(toCopy.getSize()), ptr_(0) 21 | { 22 | cudaError_t err = cudaHostAlloc((void**)&ptr_, size_, cudaHostAllocDefault); 23 | if (err != cudaSuccess) { 24 | throw std::runtime_error("cudaHostAlloc() failed."); 25 | } 26 | toCopy.set(this, 0, size_, 0); 27 | } 28 | 29 | PinnedCPUBuffer& PinnedCPUBuffer::operator=(const Buffer& rhs) { 30 | cudaError_t err; 31 | if (this != &rhs) { 32 | size_ = rhs. getSize(); 33 | if (ptr_ != 0) { 34 | err = cudaFreeHost(ptr_); 35 | if (err != cudaSuccess) { 36 | throw std::runtime_error("cudaFreeHost() failed."); 37 | } 38 | } 39 | err = cudaHostAlloc((void**)&ptr_, size_, cudaHostAllocDefault); 40 | if (err != cudaSuccess) { 41 | throw std::runtime_error("cudaHostAlloc failed."); 42 | } 43 | rhs.set(this, 0, size_, 0); 44 | } 45 | return *this; 46 | } 47 | 48 | PinnedCPUBuffer::~PinnedCPUBuffer() { 49 | if (ptr_) { 50 | cudaError_t err = cudaFreeHost(ptr_); 51 | if (err != cudaSuccess) { 52 | // in C++11 destructors default to noexcept 53 | // throw std::runtime_error("cudaFreeHost() failed."); 54 | std::cout << "cudaFreeHost() failed: " << err << std::endl; 55 | std::cout << cudaGetErrorString(err) << std::endl; 56 | } 57 | } 58 | } 59 | 60 | void PinnedCPUBuffer::resize(size_t newsize) { 61 | cudaError_t err; 62 | if (ptr_) { 63 | err = cudaFreeHost(ptr_); 64 | if (err != cudaSuccess) { 65 | throw std::runtime_error("cudaFreeHost() failed."); 66 | } 67 | ptr_ = 0; 68 | } 69 | size_ = newsize; 70 | if (newsize > 0) { 71 | err = cudaHostAlloc((void**)&ptr_, size_, cudaHostAllocDefault); 72 | if (err != cudaSuccess) { 73 | throw std::runtime_error("cudaHostAlloc() failed."); 74 | } 75 | } 76 | } 77 | 78 | void PinnedCPUBuffer::set(Buffer* dest, size_t srcBegin, size_t srcEnd, 79 | size_t destBegin) const { 80 | dest->setFrom(*this, srcBegin, srcEnd, destBegin); 81 | } 82 | 83 | void PinnedCPUBuffer::setFrom(const CPUBuffer& src, size_t srcBegin, 84 | size_t srcEnd, size_t destBegin) { 85 | if (srcEnd - srcBegin > size_ - destBegin) { 86 | throw std::runtime_error("Buffer overflow."); 87 | } 88 | memcpy(ptr_ + destBegin, (char*)src.getPtr() + srcBegin, 89 | srcEnd - srcBegin); 90 | } 91 | 92 | void PinnedCPUBuffer::setFrom(const PinnedCPUBuffer& src, size_t srcBegin, 93 | size_t srcEnd, size_t destBegin) { 94 | setFrom((const CPUBuffer&)src, srcBegin, srcEnd, destBegin); 95 | } 96 | 97 | 98 | void PinnedCPUBuffer::setFrom(const GPUBuffer& src, size_t srcBegin, 99 | size_t srcEnd, size_t destBegin) { 100 | if (srcEnd - srcBegin > size_ - destBegin) { 101 | throw std::runtime_error("Buffer overflow."); 102 | } 103 | cudaError_t err = cudaMemcpyAsync(ptr_ + destBegin, 104 | (char*)src.getPtr() + srcBegin, srcEnd - srcBegin, 105 | cudaMemcpyDeviceToHost, 0); 106 | if (err != cudaSuccess) { 107 | std::cout << "Error code: " << err << std::endl; 108 | std::cout << cudaGetErrorString(err) << std::endl; 109 | throw std::runtime_error("cudaMemcpy failed."); 110 | } 111 | } 112 | 113 | void PinnedCPUBuffer::setFrom(const void* src, size_t srcBegin, 114 | size_t srcEnd, size_t destBegin) 115 | { 116 | CPUBuffer::setFrom(src, srcBegin, srcEnd, destBegin); 117 | } 118 | 119 | bool PinnedCPUBuffer::hasNaNs(bool verbose) const 120 | { 121 | int numEntries = size_ / sizeof(float); 122 | float* arr = (float*)ptr_; 123 | int i = 0; 124 | bool haveNaNs = false; 125 | if (verbose) { 126 | for (i = 0; i < numEntries; ++i) { 127 | #ifndef _WIN32 128 | bool in = std::isnan(arr[i]); 129 | #else 130 | bool in = _isnan(arr[i]); 131 | #endif 132 | if (in) { 133 | std::cout << "NaN entry in array at: " << i << std::endl; 134 | } 135 | haveNaNs |= in; 136 | } 137 | } else { 138 | while ((!haveNaNs) && i < numEntries) { 139 | #ifndef _WIN32 140 | haveNaNs |= std::isnan(arr[i]); 141 | #else 142 | haveNaNs |= _isnan(arr[i]); 143 | #endif 144 | ++i; 145 | } 146 | } 147 | return haveNaNs; 148 | } 149 | -------------------------------------------------------------------------------- /src/Buffers/CPUBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "CPUBuffer.h" 2 | 3 | #include "PinnedCPUBuffer.h" 4 | #include "GPUBuffer.h" 5 | 6 | CPUBuffer::CPUBuffer() : 7 | size_(0), ptr_(0) 8 | { 9 | } 10 | 11 | CPUBuffer::CPUBuffer(size_t size) : 12 | size_(size), ptr_(0) 13 | { 14 | ptr_ = new char[size_]; 15 | } 16 | 17 | CPUBuffer::CPUBuffer(const Buffer& toCopy) : 18 | size_(toCopy.getSize()), ptr_(0) 19 | { 20 | ptr_ = new char[size_]; 21 | toCopy.set(this, 0, size_, 0); 22 | } 23 | 24 | CPUBuffer& CPUBuffer::operator=(const Buffer& rhs) { 25 | if (this != &rhs) { 26 | size_ = rhs. getSize(); 27 | if (ptr_ != 0) { 28 | delete [] ptr_; 29 | } 30 | ptr_ = new char[size_]; 31 | rhs.set(this, 0, size_, 0); 32 | } 33 | return *this; 34 | } 35 | 36 | CPUBuffer::~CPUBuffer() { 37 | if (ptr_) { 38 | delete [] ptr_; 39 | } 40 | } 41 | 42 | void CPUBuffer::resize(size_t newsize) { 43 | if (ptr_) { 44 | delete [] ptr_; 45 | ptr_ = 0; 46 | } 47 | size_ = newsize; 48 | if (newsize > 0) { 49 | ptr_ = new char[size_]; 50 | } 51 | } 52 | 53 | void CPUBuffer::set(Buffer* dest, size_t srcBegin, size_t srcEnd, 54 | size_t destBegin) const { 55 | dest->setFrom(*this, srcBegin, srcEnd, destBegin); 56 | } 57 | 58 | void CPUBuffer::setFrom(const CPUBuffer& src, size_t srcBegin, 59 | size_t srcEnd, size_t destBegin) { 60 | if (srcEnd - srcBegin > size_ - destBegin) { 61 | throw std::runtime_error("Buffer overflow."); 62 | } 63 | memcpy(ptr_ + destBegin, (char*)src.getPtr() + srcBegin, 64 | srcEnd - srcBegin); 65 | } 66 | 67 | void CPUBuffer::setFrom(const PinnedCPUBuffer& src, size_t srcBegin, 68 | size_t srcEnd, size_t destBegin) { 69 | setFrom((const CPUBuffer&)src, srcBegin, srcEnd, destBegin); 70 | } 71 | 72 | 73 | void CPUBuffer::setFrom(const GPUBuffer& src, size_t srcBegin, 74 | size_t srcEnd, size_t destBegin) { 75 | if (srcEnd - srcBegin > size_ - destBegin) { 76 | throw std::runtime_error("Buffer overflow."); 77 | } 78 | cudaError_t err = cudaMemcpy(ptr_ + destBegin, 79 | (char*)src.getPtr() + srcBegin, srcEnd - srcBegin, 80 | cudaMemcpyDeviceToHost); 81 | if (err != cudaSuccess) { 82 | std::cout << "Error code: " << err << std::endl; 83 | std::cout << cudaGetErrorString(err) << std::endl; 84 | throw std::runtime_error("cudaMemcpy failed."); 85 | } 86 | } 87 | 88 | void CPUBuffer::setFrom(const void* src, size_t srcBegin, 89 | size_t srcEnd, size_t destBegin) { 90 | if (srcEnd - srcBegin > size_ - destBegin) { 91 | throw std::runtime_error("Buffer overflow."); 92 | } 93 | memcpy(ptr_ + destBegin, (char*)src + srcBegin, srcEnd - srcBegin); 94 | } 95 | 96 | void CPUBuffer::takeOwnership(const void* src, size_t num) { 97 | size_ = num; 98 | if (ptr_) { 99 | delete [] ptr_; 100 | } 101 | ptr_ = (char*) src; 102 | } 103 | 104 | void CPUBuffer::setPlainArray(void* dest, size_t srcBegin, 105 | size_t srcEnd, size_t destBegin) const { 106 | memcpy(dest, ptr_ + srcBegin, srcEnd - srcBegin); 107 | } 108 | 109 | void CPUBuffer::setToZero() 110 | { 111 | memset((void*)ptr_, 0, size_); 112 | } 113 | 114 | void CPUBuffer::dump(std::ostream& stream, int numCols) 115 | { 116 | Buffer::dump(stream, numCols); 117 | } 118 | 119 | void CPUBuffer::dump(std::ostream& stream, int numCols, 120 | size_t begin, size_t end) 121 | { 122 | float* arr = (float*)ptr_; 123 | arr += begin / sizeof(float); 124 | size_t numEntries = (end - begin) / sizeof(float); 125 | int i = 0; 126 | int row = 0; 127 | while (i < numEntries - numCols) { 128 | for (int j = 0; j < numCols; ++j) { 129 | stream << arr[i] << " "; 130 | ++i; 131 | } 132 | stream << std::endl; 133 | ++row; 134 | } 135 | for(; i < numEntries; ++i) { 136 | stream << arr[i] << " "; 137 | } 138 | stream << std::endl; 139 | } 140 | 141 | bool CPUBuffer::hasNaNs(bool verbose) const 142 | { 143 | int numEntries = size_ / sizeof(float); 144 | float* arr = (float*)ptr_; 145 | int i = 0; 146 | bool haveNaNs = false; 147 | if (verbose) { 148 | for (i = 0; i < numEntries; ++i) { 149 | #ifndef _WIN32 150 | bool in = std::isnan(arr[i]); 151 | #else 152 | bool in = _isnan(arr[i]); 153 | #endif 154 | if (in) { 155 | std::cout << "NaN entry in array at: " << i << std::endl; 156 | } 157 | haveNaNs |= in; 158 | } 159 | } else { 160 | while ((!haveNaNs) && i < numEntries) { 161 | #ifndef _WIN32 162 | haveNaNs |= std::isnan(arr[i]); 163 | #else 164 | haveNaNs |= _isnan(arr[i]); 165 | #endif 166 | ++i; 167 | } 168 | } 169 | return haveNaNs; 170 | } 171 | 172 | -------------------------------------------------------------------------------- /src/Buffers/CPUBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef CPU_BUFFER_H 2 | #define CPU_BUFFER_H 3 | 4 | #include "Buffer.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class PinnedCPUBuffer; 13 | class GPUBuffer; 14 | 15 | /** 16 | * @brief Buffer class for managing memory on CPU side. 17 | */ 18 | class CPUBuffer : public Buffer { 19 | 20 | public: 21 | /** Constructor. */ 22 | CPUBuffer(); 23 | /** Constructor with a certain size. 24 | * @param size Size of buffer.*/ 25 | CPUBuffer(size_t size); 26 | /** Copy constructor.*/ 27 | CPUBuffer(const Buffer& toCopy); 28 | /** Assignment operator.*/ 29 | CPUBuffer& operator=(const Buffer& rhs); 30 | /** Destructor.*/ 31 | virtual ~CPUBuffer(); 32 | 33 | /** Get current size of buffer.*/ 34 | virtual size_t getSize() const { return size_; } ; 35 | /** Get pointer to the memory managed by the buffer. This is a host 36 | * pointer.*/ 37 | virtual void* getPtr() { return ptr_; } ; 38 | virtual const void* getPtr() const { return ptr_; } ; 39 | /** Resize the buffer. The old data becomes invalid after a call to 40 | * resize. 41 | * @param newsize New size of buffer. 42 | * */ 43 | virtual void resize(size_t newsize); 44 | 45 | /** Copy a slice of this buffer into dest. The slice in this starts 46 | * at srcBegin and ends at srcEnd. The slice is copied into dest 47 | * starting at destBegin. The parameters srcBegin, srcEnd, and 48 | * destBegin are in bytes. 49 | * @param dest Buffer that is to be set. 50 | * @param srcBegin Beginning of slice that is copied into Buffer. 51 | * @param srcEnd End of slice that is copied into Buffer. 52 | * @param destBegin Offset into dest. 53 | * */ 54 | virtual void set(Buffer* dest, size_t srcBegin, size_t srcEnd, 55 | size_t destBegin) const; 56 | /** Set this buffer from a src CPUBuffer. 57 | * @param src Source buffer. 58 | * @param srcBegin Beginning of slice that is copied into this. 59 | * @param srcEnd End of slice that is copied into this. 60 | * @param destBegin Offset in dest. 61 | * */ 62 | virtual void setFrom(const CPUBuffer& src, size_t srcBegin, 63 | size_t srcEnd, size_t destBegin); 64 | /** Set this buffer from a src PinnedCPUBuffer. Data transfers 65 | * between GPUBuffer and PinnedCPUBuffer objects are done 66 | * asynchronously. 67 | * @param src Source buffer. 68 | * @param srcBegin Beginning of slice that is copied into this. 69 | * @param srcEnd End of slice that is copied into this. 70 | * @param destBegin Offset in dest. 71 | * */ 72 | virtual void setFrom(const PinnedCPUBuffer& src, size_t srcBegin, 73 | size_t srcEnd, size_t destBegin); 74 | /** Set this buffer from a src GPUBuffer. Currently only setting 75 | * from a buffer on the same device is supported. 76 | * @param src Source buffer. 77 | * @param srcBegin Beginning of slice that is copied into this. 78 | * @param srcEnd End of slice that is copied into this. 79 | * @param destBegin Offset in dest. 80 | * */ 81 | virtual void setFrom(const GPUBuffer& src, size_t srcBegin, 82 | size_t srcEnd, size_t destBegin); 83 | /** Set this buffer from a plain array. 84 | * @param src Source buffer. 85 | * @param srcBegin Beginning of slice that is copied into this. 86 | * @param srcEnd End of slice that is copied into this. 87 | * @param destBegin Offset in dest. 88 | * */ 89 | virtual void setFrom(const void* src, size_t srcBegin, 90 | size_t srcEnd, size_t destBegin); 91 | 92 | /** Use a host pointer for the buffer. Note that CPUBuffer calls 93 | * delete [] on this pointer when it is destroyed. src must not be 94 | * deleted by the client code. 95 | * @param src Pointer to valid host memory. Has to be at least of 96 | * size num. 97 | * @param num Size in bytes of src.*/ 98 | void takeOwnership(const void* src, size_t num); 99 | /** Copy the contents of the buffer to a plain array. Semantics is 100 | * identical to the set method. 101 | * @param dest Plain array that is to be set. 102 | * @param srcBegin Beginning of slice that is copied into dest. 103 | * @param srcEnd End of slice that is copied into dest. 104 | * @param destBegin Offset into dest. 105 | * */ 106 | virtual void setPlainArray(void* dest, size_t srcBegin, 107 | size_t srcEnd, size_t destBegin) const; 108 | 109 | virtual void setToZero(); 110 | 111 | void dump(std::ostream& stream, int numCols); 112 | virtual void dump(std::ostream& stream, int numCols, 113 | size_t begin, size_t end); 114 | 115 | virtual bool hasNaNs(bool verbose = false) const; 116 | 117 | private: 118 | size_t size_; 119 | char* ptr_; 120 | }; 121 | 122 | #endif 123 | 124 | -------------------------------------------------------------------------------- /src/Buffers/GPUBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef GPU_BUFFER_H 2 | #define GPU_BUFFER_H 3 | 4 | #include "Buffer.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "../cutilSafeCall.h" 12 | 13 | class CPUBuffer; 14 | class PinnedCPUBuffer; 15 | 16 | /** A class for managing flat GPU memory. The GPU memory managed by a 17 | * GPUBuffer is freed when the buffer is destroyed (e.g. when it goes 18 | * out of scope). 19 | * @brief Class for managing GPU memory. 20 | * */ 21 | class GPUBuffer : public Buffer { 22 | 23 | public: 24 | /** Constructor. Creates a buffer on default cuda device 0.*/ 25 | GPUBuffer(); 26 | /** Create a buffer on a specific cuda device. 27 | * @param device Cuda device on which to create the Buffer. 28 | * */ 29 | GPUBuffer(int device); 30 | /** Create a buffer of a certain size on a specific cuda device. 31 | * @param size Size of buffer in bytes. 32 | * @param device Cuda device on which to create the Buffer. 33 | * */ 34 | GPUBuffer(size_t size, int device); 35 | /** Copy constructor.*/ 36 | GPUBuffer(const GPUBuffer& toCopy); 37 | /** Copy a GPU Buffer to a different device. 38 | * @param toCopy GPUBuffer that is to be copied. 39 | * @param device Cuda device on which to create the new GPUBuffer.*/ 40 | GPUBuffer(const Buffer& toCopy, int device); 41 | /** Set a GPUBuffer from a different GPUBuffer. 42 | * @param rhs GPUBuffer from which to set this GPUBuffer.*/ 43 | GPUBuffer& operator=(const GPUBuffer& rhs); 44 | /** Set a GPUBuffer from a CPUBuffer. 45 | * @param rhs CPUBuffer from which to set this GPUBuffer.*/ 46 | GPUBuffer& operator=(const CPUBuffer& rhs); 47 | /** Destructor. Frees the GPU memory managed by this GPUBuffer.*/ 48 | virtual ~GPUBuffer(); 49 | 50 | virtual size_t getSize() const { return size_; } ; 51 | virtual void* getPtr() { return ptr_; } ; 52 | virtual const void* getPtr() const { return ptr_; } ; 53 | /** Set the pointer managed by this GPUBuffer to ptr. The memory 54 | * managed previously by this Buffer is released. 55 | * @param ptr Device pointer to GPU memory. 56 | * @param size Size of memory pointed to by ptr. 57 | * @param device Cuda device on which the memory pointed to by ptr 58 | * is located.*/ 59 | virtual void setPtr(char* ptr, size_t size, int device); 60 | /** Change the size of the GPUBuffer. The data held by the buffer 61 | * becomes invalid, even when the size of the buffer is increased. 62 | * Setting the size of the buffer to zero frees all GPU memory. 63 | * @param newsize New size of GPU buffer.*/ 64 | virtual void resize(size_t newsize); 65 | 66 | /** Copy a slice of this buffer into dest. The slice in this starts 67 | * at srcBegin and ends at srcEnd. The slice is copied into dest 68 | * starting at destBegin. The parameters srcBegin, srcEnd, and 69 | * destBegin are in bytes. 70 | * @param dest Buffer that is to be set. 71 | * @param srcBegin Beginning of slice that is copied into Buffer. 72 | * @param srcEnd End of slice that is copied into Buffer. 73 | * @param destBegin Offset into dest. 74 | * */ 75 | virtual void set(Buffer* dest, size_t srcBegin, size_t srcEnd, 76 | size_t destBegin) const; 77 | 78 | /** Set this buffer from a src CPUBuffer. 79 | * @param src Source buffer. 80 | * @param srcBegin Beginning of slice that is copied into this. 81 | * @param srcEnd End of slice that is copied into this. 82 | * @param destBegin Offset in dest. 83 | * */ 84 | virtual void setFrom(const CPUBuffer& src, size_t srcBegin, 85 | size_t srcEnd, size_t destBegin); 86 | /** Set this buffer from a src PinnedCPUBuffer. Data transfers 87 | * between GPUBuffer and PinnedCPUBuffer objects are done 88 | * asynchronously. 89 | * @param src Source buffer. 90 | * @param srcBegin Beginning of slice that is copied into this. 91 | * @param srcEnd End of slice that is copied into this. 92 | * @param destBegin Offset in dest. 93 | * */ 94 | virtual void setFrom(const PinnedCPUBuffer& src, size_t srcBegin, 95 | size_t srcEnd, size_t destBegin); 96 | /** Set this buffer from a src GPUBuffer. Currently only setting 97 | * from a buffer on the same device is supported. 98 | * @param src Source buffer. 99 | * @param srcBegin Beginning of slice that is copied into this. 100 | * @param srcEnd End of slice that is copied into this. 101 | * @param destBegin Offset in dest. 102 | * */ 103 | virtual void setFrom(const GPUBuffer& src, size_t srcBegin, 104 | size_t srcEnd, size_t destBegin); 105 | 106 | virtual void setToZero(); 107 | 108 | void dump(std::ostream& stream, int numCols); 109 | virtual void dump(std::ostream& stream, int numCols, 110 | size_t begin, size_t end); 111 | 112 | virtual bool hasNaNs(bool verbose = false) const; 113 | 114 | private: 115 | int device_; 116 | size_t size_; 117 | char* ptr_; 118 | }; 119 | 120 | #endif 121 | 122 | -------------------------------------------------------------------------------- /recon.py: -------------------------------------------------------------------------------- 1 | import os 2 | from contextlib import contextmanager 3 | from subprocess import run 4 | 5 | import mrc 6 | import numpy as np 7 | 8 | # NOTE: this assumes that you have config files and otf files with the emission wavelength 9 | # names in them... such as `config528.txt` and `otf528.otf`. You may place those files 10 | # anywhere, but you should update the _DIR variables below 11 | 12 | # path to your otf directory. Defaults to the same as the recon.py file 13 | OTF_DIR = os.path.abspath(os.path.dirname(__file__)) 14 | # path to your config directory. Defaults to the same as the recon.py file 15 | CONFIG_DIR = os.path.abspath(os.path.dirname(__file__)) 16 | # name of the reconstruction app 17 | APP = "cudasirecon" 18 | 19 | 20 | # you could of course do something more complicated with the config/otf finding 21 | def get_otf_and_config(wave, otf_dir=OTF_DIR, config_dir=CONFIG_DIR): 22 | otf = os.path.join(otf_dir, f"otf{wave}.otf") 23 | config = os.path.join(config_dir, f"config{wave}.txt") 24 | if not os.path.exists(otf): 25 | print(f"Could not find otf file: {otf}") 26 | return None 27 | if not os.path.exists(config): 28 | print(f"Could not find config file: {config}") 29 | return None 30 | return otf, config 31 | 32 | 33 | def merge_files(file_list, outfile, delete=False): 34 | data = [mrc.imread(fname) for fname in file_list] 35 | waves = [0, 0, 0, 0, 0] 36 | for i, item in enumerate(data): 37 | waves[i] = item.Mrc.hdr.wave[0] 38 | hdr = data[0].Mrc.hdr 39 | m = mrc.Mrc2(outfile, mode="w") 40 | array = np.stack(data, -3) 41 | m.initHdrForArr(array) 42 | mrc.copyHdrInfo(m.hdr, hdr) 43 | m.hdr.NumWaves = len(file_list) 44 | m.hdr.wave = waves 45 | m.writeHeader() 46 | m.writeStack(array) 47 | m.close() 48 | if delete: 49 | try: 50 | [os.remove(f) for f in file_list] 51 | except Exception: 52 | pass 53 | return outfile 54 | 55 | 56 | def write_single_channel(array, outpath, hdr, wave): 57 | """writes a new single-channel file from array data, copying information from hdr""" 58 | print(f"Extracting channel {wave}...") 59 | m = mrc.Mrc2(outpath, mode="w") 60 | m.initHdrForArr(array) 61 | mrc.copyHdrInfo(m.hdr, hdr) 62 | m.hdr.NumWaves = 1 63 | m.hdr.wave = [wave, 0, 0, 0, 0] 64 | m.writeHeader() 65 | m.writeStack(array) 66 | m.close() 67 | 68 | 69 | @contextmanager 70 | def file_splitter(fname): 71 | """Context manager that takes care of splitting the file and making sure that 72 | duplicated data gets cleaned up when done. 73 | """ 74 | im = mrc.imread(fname) 75 | header = im.Mrc.header 76 | namesplit = os.path.splitext(fname) 77 | try: 78 | splitfiles = [] 79 | if header.NumWaves == 1: 80 | # if it's a single channel file, we don't need to split 81 | wave = header.wave[0] 82 | otf_config = get_otf_and_config(wave) 83 | if otf_config is not None: 84 | splitfiles = [(fname, wave, *otf_config)] 85 | else: 86 | # otherwise break out individual wavelenghts 87 | for c in range(header.NumWaves): 88 | wave = header.wave[c] 89 | out = f"{namesplit[0]}-{wave}{namesplit[1]}" 90 | # assumes channel is the 3rd to last dimension 91 | data = np.take(im, c, -3) 92 | otf_config = get_otf_and_config(wave) 93 | if otf_config is not None: 94 | write_single_channel(data, out, header, wave) 95 | splitfiles.append((out, wave, *otf_config)) 96 | yield splitfiles 97 | finally: 98 | # clean up the split files 99 | if header.NumWaves > 1: 100 | print("\nCleaning up extracted channels...") 101 | for file, b, c, d in splitfiles: 102 | os.remove(file) 103 | 104 | 105 | def reconstruct_single(file, otf, config=None, outfile=None, **kwargs): 106 | """perform the reconstruction""" 107 | if outfile is None: 108 | namesplit = os.path.splitext(file) 109 | outfile = f"{namesplit[0]}_PROC{namesplit[1]}" 110 | cmd = [APP, file, outfile, otf] 111 | if config: 112 | cmd.extend(["-c", config]) 113 | if kwargs: 114 | for key, value in kwargs.items(): 115 | cmd.extend([f"--{key}", str(value)]) 116 | print(f"Running command: {' '.join(cmd)}") 117 | run(cmd) 118 | return outfile 119 | 120 | 121 | def reconstruct(inFile, outfile=None, **kwargs): 122 | """Splits multi-channel file into individual channels 123 | then reconstructs each channel and merges the results 124 | """ 125 | if outfile is None: 126 | namesplit = os.path.splitext(inFile) 127 | outfile = f"{namesplit[0]}_PROC{namesplit[1]}" 128 | 129 | with file_splitter(inFile) as splitfiles: 130 | processed = [] 131 | for file, wave, otf, config in splitfiles: 132 | try: 133 | processed.append(reconstruct_single(file, otf, config, **kwargs)) 134 | except Exception as e: 135 | print(f"Cannot reconstruct file {file} due to error {e}") 136 | if len(processed) > 1: 137 | print("\nMerging multi-channel reconstructions...") 138 | final_file = merge_files(processed, outfile, delete=True) 139 | else: 140 | final_file = processed[0] 141 | if final_file != outfile: 142 | os.rename(final_file, outfile) 143 | return final_file 144 | 145 | 146 | if __name__ == "__main__": 147 | import argparse 148 | 149 | parser = argparse.ArgumentParser() 150 | parser.add_argument("infile", type=argparse.FileType("r")) 151 | args, extras = parser.parse_known_args() 152 | extras = {k: v for k, v in zip(extras[::2], extras[1::2])} 153 | reconstruct(os.path.abspath(args.infile.name), **extras) 154 | -------------------------------------------------------------------------------- /src/Buffers/GPUBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "GPUBuffer.h" 2 | 3 | #include "CPUBuffer.h" 4 | #include "PinnedCPUBuffer.h" 5 | 6 | GPUBuffer::GPUBuffer() : 7 | device_(0), size_(0), ptr_(0) 8 | { 9 | } 10 | 11 | GPUBuffer::GPUBuffer(int device) : 12 | device_(device), size_(0), ptr_(0) 13 | { 14 | } 15 | 16 | GPUBuffer::GPUBuffer(size_t size, int device) : 17 | device_(device), size_(size), ptr_(0) 18 | { 19 | cudaError_t err = cudaSetDevice(device_); 20 | if (err != cudaSuccess) { 21 | throw std::runtime_error("cudaSetDevice failed."); 22 | } 23 | err = cudaMalloc((void**)&ptr_, size_); 24 | if (err != cudaSuccess) { 25 | throw std::runtime_error("cudaMalloc failed."); 26 | } 27 | } 28 | 29 | GPUBuffer::GPUBuffer(const GPUBuffer& toCopy) : 30 | device_(toCopy.device_), size_(toCopy.size_), ptr_(0) 31 | { 32 | this->resize(size_); 33 | toCopy.set(this, 0, size_, 0); 34 | } 35 | 36 | GPUBuffer::GPUBuffer(const Buffer& toCopy, int device) : 37 | device_(device), size_(toCopy.getSize()), ptr_(0) 38 | { 39 | this->resize(size_); 40 | toCopy.set(this, 0, size_, 0); 41 | } 42 | 43 | GPUBuffer& GPUBuffer::operator=(const GPUBuffer& rhs) { 44 | if (this->device_ != rhs.device_) { 45 | throw std::runtime_error( 46 | "Different devices in GPUBuffer::operator=."); 47 | } 48 | if (this != &rhs) { 49 | size_ = rhs.getSize(); 50 | this->resize(size_); 51 | rhs.set(this, 0, size_, 0); 52 | } 53 | return *this; 54 | } 55 | 56 | GPUBuffer& GPUBuffer::operator=(const CPUBuffer& rhs) { 57 | size_ = rhs.getSize(); 58 | this->resize(size_); 59 | rhs.set(this, 0, size_, 0); 60 | return *this; 61 | } 62 | 63 | GPUBuffer::~GPUBuffer() { 64 | if (ptr_) { 65 | cudaError_t err = cudaFree(ptr_); 66 | if (err != cudaSuccess) { 67 | std::cout << "Error code: " << err << std::endl; 68 | std::cout << "ptr_: " << (long long int)ptr_ << std::endl; 69 | // in C++11 destructors default to noexcept 70 | // throw std::runtime_error("cudaFree failed."); 71 | } 72 | ptr_ = 0; 73 | } 74 | } 75 | 76 | void GPUBuffer::resize(size_t newsize) { 77 | if (ptr_) { 78 | cudaError_t err = cudaFree(ptr_); 79 | if (err != cudaSuccess) { 80 | throw std::runtime_error("cudaFree failed."); 81 | } 82 | ptr_ = 0; 83 | } 84 | cudaError_t err = cudaSetDevice(device_); 85 | if (err != cudaSuccess) { 86 | throw std::runtime_error("cudaSetDevice failed."); 87 | } 88 | size_ = newsize; 89 | if (newsize > 0) { 90 | err = cudaMalloc((void**)&ptr_, size_); 91 | if (err != cudaSuccess) { 92 | throw std::runtime_error("cudaMalloc failed."); 93 | } 94 | } 95 | } 96 | 97 | void GPUBuffer::setPtr(char* ptr, size_t size, int device) 98 | { 99 | if (ptr_) { 100 | cutilSafeCall(cudaFree(ptr_)); 101 | } 102 | ptr_ = ptr; 103 | size_ = size; 104 | device_ = device; 105 | } 106 | 107 | void GPUBuffer::set(Buffer* dest, size_t srcBegin, size_t srcEnd, 108 | size_t destBegin) const { 109 | dest->setFrom(*this, srcBegin, srcEnd, destBegin); 110 | } 111 | 112 | void GPUBuffer::setFrom(const CPUBuffer& src, size_t srcBegin, 113 | size_t srcEnd, size_t destBegin) { 114 | if (srcEnd - srcBegin > size_ - destBegin) { 115 | std::cout << "Trying to write " << srcEnd - srcBegin << " bytes\n"; 116 | std::cout << "To buffer of size " << size_ << " bytes\n"; 117 | std::cout << "With offset " << destBegin << " bytes\n"; 118 | std::cout << "Overflow by " << (int)size_ - destBegin - (srcEnd - srcBegin) << "\n"; 119 | std::cout << std::endl; 120 | throw std::runtime_error("Buffer overflow."); 121 | } 122 | cudaError_t err = cudaMemcpy(ptr_ + destBegin, 123 | (char*)src.getPtr() + srcBegin, srcEnd - srcBegin, 124 | cudaMemcpyHostToDevice); 125 | if (err != cudaSuccess) { 126 | throw std::runtime_error("cudaMemcpy failed."); 127 | } 128 | } 129 | 130 | void GPUBuffer::setFrom(const PinnedCPUBuffer& src, size_t srcBegin, 131 | size_t srcEnd, size_t destBegin) { 132 | if (srcEnd - srcBegin > size_ - destBegin) { 133 | std::cout << "Trying to write " << srcEnd - srcBegin << " bytes\n"; 134 | std::cout << "To buffer of size " << size_ << " bytes\n"; 135 | std::cout << "With offset " << destBegin << " bytes\n"; 136 | std::cout << "Overflow by " << (int)size_ - destBegin - (srcEnd - srcBegin) << "\n"; 137 | std::cout << std::endl; 138 | throw std::runtime_error("Buffer overflow."); 139 | } 140 | cudaError_t err = cudaMemcpyAsync(ptr_ + destBegin, 141 | (char*)src.getPtr() + srcBegin, srcEnd - srcBegin, 142 | cudaMemcpyHostToDevice, 0); 143 | if (err != cudaSuccess) { 144 | throw std::runtime_error("cudaMemcpy failed."); 145 | } 146 | } 147 | 148 | void GPUBuffer::setFrom(const GPUBuffer& src, size_t srcBegin, 149 | size_t srcEnd, size_t destBegin) { 150 | if (this->device_ != src.device_) { 151 | throw std::runtime_error( 152 | "Currently setFrom only supports transferring data within the " 153 | "same device or between host and device."); 154 | } 155 | if (srcEnd - srcBegin > size_ - destBegin) { 156 | throw std::runtime_error("Buffer overflow."); 157 | } 158 | cudaError_t err = cudaMemcpy(ptr_ + destBegin, 159 | (char*)src.getPtr() + srcBegin, srcEnd - srcBegin, 160 | cudaMemcpyDeviceToDevice); 161 | if (err != cudaSuccess) { 162 | throw std::runtime_error("cudaMemcpy failed."); 163 | } 164 | } 165 | 166 | void GPUBuffer::dump(std::ostream& stream, int numCols) 167 | { 168 | Buffer::dump(stream,numCols); 169 | } 170 | 171 | void GPUBuffer::setToZero() 172 | { 173 | cudaMemset(ptr_, 0, size_); 174 | } 175 | 176 | void GPUBuffer::dump(std::ostream& stream, int numCols, 177 | size_t begin, size_t end) 178 | { 179 | CPUBuffer cpuBuff(*this); 180 | cpuBuff.dump(stream, numCols, begin, end); 181 | } 182 | 183 | bool GPUBuffer::hasNaNs(bool verbose) const 184 | { 185 | CPUBuffer tmp(size_); 186 | this->set(&tmp, 0, size_, 0); 187 | return tmp.hasNaNs(verbose); 188 | } 189 | -------------------------------------------------------------------------------- /src/Buffers/Buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef BUFFER_H 2 | #define BUFFER_H 3 | 4 | #include 5 | #include 6 | 7 | class CPUBuffer; 8 | class PinnedCPUBuffer; 9 | class GPUBuffer; 10 | 11 | /** Buffer class for managing flat memory. 12 | * 13 | * This class serves two main purposes: 14 | * 1) Manage memory resources 15 | * 2) Transfer data between different buffers that could reside on 16 | * different devices (e.g. host vs gpu or in a multi-gpu environment) 17 | * 18 | * @brief Interface for Buffer classes used for managing memory on CPUs, 19 | * GPUs, and data transfers. 20 | * */ 21 | class Buffer { 22 | 23 | public: 24 | /** Destructor*/ 25 | virtual ~Buffer(); 26 | 27 | /** Get current size of buffer.*/ 28 | virtual size_t getSize() const = 0; 29 | /** Get pointer to the memory managed by the buffer.*/ 30 | virtual void* getPtr() = 0; 31 | /** Get a const pointer to the memory managed by the buffer.*/ 32 | virtual const void* getPtr() const = 0; 33 | /** Resize the buffer. The old data becomes invalid after a call to 34 | * resize. 35 | * @param newsize New size of buffer. 36 | * */ 37 | virtual void resize(size_t newsize) = 0; 38 | 39 | /** Copy a slice of this buffer into dest. The slice in this starts 40 | * at srcBegin and ends at srcEnd. The slice is copied into dest 41 | * starting at destBegin. The parameters srcBegin, srcEnd, and 42 | * destBegin are in bytes. 43 | * @param dest Buffer that is to be set. 44 | * @param srcBegin Beginning of slice that is copied into Buffer. 45 | * @param srcEnd End of slice that is copied into Buffer. 46 | * @param destBegin Offset into dest. 47 | * */ 48 | virtual void set(Buffer* dest, size_t srcBegin, size_t srcEnd, 49 | size_t destBegin) const = 0; 50 | 51 | /** Set this buffer from a src CPUBuffer. 52 | * @param src Source buffer. 53 | * @param srcBegin Beginning of slice that is copied into this. 54 | * @param srcEnd End of slice that is copied into this. 55 | * @param destBegin Offset in dest. 56 | * */ 57 | virtual void setFrom(const CPUBuffer& src, size_t srcBegin, 58 | size_t srcEnd, size_t destBegin) = 0; 59 | /** Set this buffer from a src PinnedCPUBuffer. Data transfers 60 | * between GPUBuffer and PinnedCPUBuffer objects are done 61 | * asynchronously. 62 | * @param src Source buffer. 63 | * @param srcBegin Beginning of slice that is copied into this. 64 | * @param srcEnd End of slice that is copied into this. 65 | * @param destBegin Offset in dest. 66 | * */ 67 | virtual void setFrom(const PinnedCPUBuffer& src, size_t srcBegin, 68 | size_t srcEnd, size_t destBegin) = 0; 69 | /** Set this buffer from a src GPUBuffer. Currently only setting 70 | * from a buffer on the same device is supported. 71 | * @param src Source buffer. 72 | * @param srcBegin Beginning of slice that is copied into this. 73 | * @param srcEnd End of slice that is copied into this. 74 | * @param destBegin Offset in dest. 75 | * */ 76 | virtual void setFrom(const GPUBuffer& src, size_t srcBegin, 77 | size_t srcEnd, size_t destBegin) = 0; 78 | 79 | /** Set contents of Buffer to zero. */ 80 | virtual void setToZero() = 0; 81 | 82 | /** Dump contents of buffer to a stream 83 | * @param stream Stream to which to write. 84 | * @param numCols Number of entries per line 85 | */ 86 | void dump(std::ostream& stream, int numCols); 87 | /** Dump part of a Buffer to a stream 88 | * @param stream Stream to which to write. 89 | * @param numCols Number of entries per line 90 | * @param begin Start of part of buffer to be dumped (in bytes) 91 | * @param end End of part of the buffer to be dumped (in bytes) 92 | * */ 93 | virtual void dump(std::ostream& stream, int numCols, 94 | size_t begin, size_t end) = 0; 95 | 96 | /** Check if there are any nans in the buffer. This is an expensive 97 | * operation that is carried out on the CPU. The entire buffer is 98 | * traversed as if it were an array of floats and each entry is 99 | * checked to see whether it is nan. To avoid excessive slow down 100 | * in the application this function should typically be wrapped in a 101 | * conditional compilation section (e.g. using #ifndef NDEBUG). 102 | * @param verbose If this flag is set to true all nan entries are 103 | * printed to the std::cout. If the flag is false the function 104 | * returns when the first nan value is encountered. 105 | * */ 106 | virtual bool hasNaNs(bool verbose = false) const = 0; 107 | }; 108 | 109 | /** 110 | * \mainpage Buffer classes for managing memory allocation and data transfers 111 | * 112 | * 113 | * \section intro_sec Introduction 114 | * 115 | * The purpose of the various Buffer classes is to automate memory 116 | * allocation and deallocation and to make data transfers between 117 | * different memory spaces (e.g. CPU and GPU) easier. 118 | * 119 | * 120 | * \section allocation Memory allocation and deallocation 121 | * 122 | * In general, memory resources are allocated by creating Buffer 123 | * objects. Buffers can be resized if the memory requirements change of 124 | * if the memory is no longer needed. In case of the latter one should 125 | * resize to 0. Memory is released automatically when the Buffer object 126 | * goes out of scope. 127 | * 128 | * 129 | * \section transfers Data transfers 130 | * 131 | * Data transfers are typically done using the set method on the source 132 | * buffer with a pointer to the target buffer as an argument. The 133 | * various setFrom() methods are a lower level mechanism that allows set 134 | * to work polymorphically for any buffer as the destination. In 135 | * general the set method should be preferred over the setFrom() methods 136 | * in application code. The purpose of the other arguments of the set 137 | * method is to enable copying a slice of the source buffer to a 138 | * specific offset in the target buffer (e.g. a two dimensional slice in 139 | * the x-y plane). 140 | * 141 | * Asynchronous data transfers can be achieved by using PinnedCPUBuffer 142 | * objects on the host side. 143 | * 144 | * It is possible to sidestep the data transfer mechanisms provided by 145 | * the Buffer classes. To this end one can get the raw pointers to the 146 | * underlying memory using the getPtr() methods. 147 | * 148 | * 149 | * \section example Example 150 | * 151 | * An example of how this may be used is shown by the following program. 152 | * 153 | * \include bufferExample.cpp 154 | * 155 | * 156 | */ 157 | 158 | /** \def NDEBUG 159 | * This macro controlls whether assert statements are evaluated or not. 160 | * If NDEBUG is defined assert statements are not compiled. 161 | */ 162 | #endif 163 | 164 | -------------------------------------------------------------------------------- /src/cudaSirecon/SIM_reconstructor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIM_RECONSTRUCTOR_HPP 2 | #define SIM_RECONSTRUCTOR_HPP 3 | 4 | #include 5 | namespace po = boost::program_options; 6 | #include 7 | 8 | 9 | //! All calculation starts with a SIM_Reconstructor object 10 | /*! 11 | As seen in cudaSireconDriver.cpp, SIM reconstruction is done in the following steps: 12 | 1. Instantiate a SIM_Reconstructor object by passing along the command line; 13 | 2. For all the time points, do: 14 | 2a. Load raw data and preprocess 15 | 2b. call member processOneVolume() to reconstruct the current time point 16 | 2c. write reconstruction result of current time point 17 | 3. Close file(s) and exit 18 | */ 19 | class SIM_Reconstructor { 20 | 21 | public: 22 | /*! This constructor does the following: 23 | * - Command line is parsed by this ctor using Boost program_options library; 24 | * - Set all parameters' values; 25 | * - Decide if we're in TIFF mode or MRC mode (potentially using Bio-Formats in the future??) 26 | * - Call openFiles(), which would 27 | * -# in MRC mode open raw data and OTF files for reading and output file for writing; 28 | * -# in TIFF mode, just open the OTF TIFF file 29 | * - Call setup() to allocate all memory buffers based on header dimension info and deskew request 30 | */ 31 | SIM_Reconstructor(int argc, char **argv); 32 | /*! This constructor does the following: 33 | * Set up options format using Boost program_options library; 34 | * Parse the config file for user parameter settings 35 | * Set all parameters' values; 36 | * Allocate memory buffers 37 | */ 38 | SIM_Reconstructor(int nx, int ny, 39 | int nimages, // number of raw images per volume 40 | std::string configFileName 41 | ); 42 | // SIM_Reconstructor(int nx, int ny, 43 | // int nimages, // number of raw images per volume 44 | // int ndirs, // number of SIM angles 45 | // int nphases, // number of SIM phases 46 | // float SIMangle, // SIM pattern angle in radians 47 | // float line_spacing, // line spacing 48 | // float wiener, // Wiener constant 49 | // float deskewAngle, // sample-scan lattice SIM 50 | // int bDeskewOnly, // deskew only? 51 | // int wavelength, // emission wavelength 52 | // float xy_cel, // x-y pixel size 53 | // float zcel, // sample piezo or objective piezo step 54 | // float besselNA, // Bessel average excitation NA 55 | // float background, // background to subtract pre processing 56 | // float xy_zoom, // factor by which to reduce x-y pixel size 57 | // float z_zoom, // default should be 1.; factor by which to reduce z pixel size 58 | // float gammaApo, // default should be 1. 59 | // int suppressR, // number of pixels around band center to suppress during assembly; default 10 60 | // unsigned deviceId); // CUDA device ID 61 | ~SIM_Reconstructor(); 62 | 63 | //! Load raw data from a file and do bleach correction (what "rescale" refers to) 64 | /*! 65 | * Calls private method loadImageData() 66 | * As is in other occasions, 'waveIdx' is to indicate color channel but mostly unused. 67 | * In the future, may add multi-color capability 68 | */ 69 | void loadAndRescaleImage(int timeIdx, int waveIdx); 70 | void setFile(int timeIdx, int waveIdx); 71 | void setRaw(CImg<> &input, int timeIdx=0, int waveIdx=0); 72 | 73 | //! The main processing occurs inside this function: 74 | /*! 75 | 1. Re-initialize all key device buffers under m_reconData; 76 | 2. Fine-tune k0 vectors, modulation amplitudes and phases for all directions and orders 77 | 3. For all directions, pre-filter separated bands, inverse FFT, and assemble the bands 78 | */ 79 | int processOneVolume(); 80 | 81 | //! Off-load processed result to host and save it to disk 82 | void writeResult(int timeIdx, int waveIdx); 83 | void getResult(float *result); 84 | 85 | int getNTimes() { return m_imgParams.ntimes; }; 86 | void setCurTimeIdx(int it) { m_imgParams.curTimeIdx = it; }; 87 | 88 | ReconParams & getReconParams() {return m_myParams;}; 89 | ImageParams & getImageParams() {return m_imgParams;}; 90 | 91 | void closeFiles(); //! only needed for closing MRC output file 92 | 93 | //! Names of input TIFF files (usually a time series whose file names all match a pattern) 94 | std::vector< std::string > m_all_matching_files; 95 | CImg<> m_otf_tiff; 96 | 97 | 98 | private: 99 | CImg<> rawImage; 100 | std::string m_config_file; 101 | ReconParams m_myParams; 102 | ImageParams m_imgParams; 103 | ReconData m_reconData; 104 | DriftParams m_driftParams; 105 | int m_zoffset; 106 | po::options_description m_progopts; 107 | po::variables_map m_varsmap; 108 | #ifdef MRC 109 | IW_MRC_HEADER m_in_out_header; 110 | #endif 111 | bool m_OTFfile_valid; 112 | 113 | int m_argc; 114 | char ** m_argv; 115 | 116 | int setupProgramOptions(); //! setup command line options using Boost library 117 | int setParams(); //! assign parameters after parsing command line 118 | void setup(unsigned width, unsigned height, unsigned nImages, unsigned nChannels); 119 | //! Read header, set up OTF and separation matrix, allocate device buffers, initialize parameters like k0guess etc. 120 | /*! 121 | Calls setup_part2() to: 122 | 1. OTF is loaded and transferred to CUDA device by calling getOTFs(); 123 | 2. Separation (or un-mixing) matrix is allocated on CUDA device and populated; 124 | 3. Raw image and other buffers, including overlap0/1, bigbuffer, outbuffer, are allocated on CUDA device 125 | by calling allocateImageBuffers(); 126 | 4. Allocate/initialize a bunch of reconstruction related parameters , including: 127 | a. inscale 128 | b. k0 129 | c. k0_time0 130 | d. k0guess 131 | e. sum_dir0_phase0 132 | f. amp 133 | */ 134 | void setup(); 135 | void setup_common(); 136 | /*! 137 | Calculate m_myParams.norders, then 138 | Call determine_otf_dimensions(), allocateOTFs(), then loadOTFs() 139 | */ 140 | void setupOTFsFromFile(); 141 | int loadOTFs(); // read OTF from file 142 | /*! 143 | In MRC mode: 144 | 1. Open input file; 2. Create output file; 3. Open OTF file 145 | In TIFF mode: 146 | 1. Make sure a series of TIFF files exist; 2. Open OTF file 147 | */ 148 | void openFiles(); 149 | 150 | //! Load raw data from disk, do flat-fielding, and transfer data to GPU 151 | /*! 152 | This is called by loadAndRescaleImage(); 153 | 'zoffset' is used if z-padding is used (almost never) 154 | 'iw' is color channel indicator; rarely used 155 | */ 156 | void loadImageData(int it, int iw); 157 | void determine_otf_dimensions(); 158 | }; 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /VStutio_project/Buffers/Buffers.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {AAE0AF2B-D932-44C7-8ADE-A249535D0DFF} 23 | Win32Proj 24 | Buffers 25 | 26 | 27 | 28 | StaticLibrary 29 | true 30 | v120 31 | Unicode 32 | 33 | 34 | StaticLibrary 35 | true 36 | v120 37 | Unicode 38 | 39 | 40 | StaticLibrary 41 | false 42 | v120 43 | true 44 | Unicode 45 | 46 | 47 | StaticLibrary 48 | false 49 | v120 50 | true 51 | Unicode 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | $(SolutionDir) 71 | 72 | 73 | $(SolutionDir) 74 | 75 | 76 | 77 | Use 78 | Level3 79 | Disabled 80 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 81 | 82 | 83 | Windows 84 | true 85 | 86 | 87 | 88 | 89 | Use 90 | Level3 91 | Disabled 92 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 93 | 94 | 95 | Windows 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | Use 103 | MaxSpeed 104 | true 105 | true 106 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 107 | $(CUDA_PATH)/include 108 | None 109 | 110 | 111 | Windows 112 | true 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | Level3 120 | NotUsing 121 | MaxSpeed 122 | true 123 | true 124 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 125 | $(CUDA_PATH)/include 126 | None 127 | 128 | 129 | Windows 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /src/cudaSirecon/gpuFunctionsImpl_hh.cu: -------------------------------------------------------------------------------- 1 | #ifndef GPU_FUNCTIONS_IMPL_H 2 | #define GPU_FUNCTIONS_IMPL_H 3 | 4 | #include "gpuFunctions.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../cutilSafeCall.h" 10 | 11 | #ifndef RED_BLOCK_SIZE_X 12 | #define RED_BLOCK_SIZE_X 32 13 | #endif 14 | #ifndef RED_BLOCK_SIZE_Y 15 | #define RED_BLOCK_SIZE_Y 32 16 | #endif 17 | 18 | 19 | /** Data from pParams going into constant memory */ 20 | __constant__ int const_pParams_bSuppress_singularities; 21 | __constant__ int const_pParams_suppression_radius; 22 | __constant__ int const_pParams_bDampenOrder0; 23 | __constant__ int const_pParams_bNoKz0; 24 | __constant__ int const_pParams_bFilteroverlaps; 25 | __constant__ int const_pParams_apodizeoutput; 26 | __constant__ float const_pParams_apoGamma; 27 | __constant__ bool const_pParams_bBessel; 28 | __constant__ int const_pParams_bRadAvgOTF; 29 | __constant__ int const_pParams_nzotf; 30 | __constant__ float const_pParams_dkrotf; 31 | __constant__ float const_wiener; 32 | 33 | /** These data are not modified in the kernels and can go in constant memory */ 34 | __constant__ int const_zdistcutoff[3]; 35 | __constant__ float const_ampmag2[3]; 36 | __constant__ float const_ampmag2_alldirs[9]; 37 | __constant__ cuFloatComplex const_conjamp[3]; 38 | __constant__ float const_noiseVarFactors[9]; 39 | __constant__ float2 const_k0[3]; 40 | __constant__ cuFloatComplex * const_otfPtrs[3]; 41 | 42 | #define MAX_ORDERS 32 43 | #define MAX_PHASES 32 44 | __constant__ float* const_outputPtrs[MAX_ORDERS * 2 -1]; 45 | __constant__ float* const_imgPtrs[MAX_PHASES]; 46 | __constant__ float const_sepMatrix[(MAX_ORDERS * 2 - 1) * MAX_PHASES]; 47 | 48 | __global__ void image_arithmetic_kernel(float* a, const float* b, 49 | int len, float alpha, float beta); 50 | __global__ void apodize_x_kernel(int napodize, int nx, int ny, 51 | float* image); 52 | __global__ void apodize_y_kernel(int napodize, int nx, int ny, 53 | float* image); 54 | __global__ void cosapodize_kernel(int nx, int ny, float* image); 55 | __global__ void rescale_kernel(float* img, int nx, int ny, 56 | float scaleFactor); 57 | __global__ void sum_reduction_kernel(float* img, int nx, int ny, 58 | float* partialReduction); 59 | 60 | __host__ void makeoverlaps(std::vector* bands, 61 | GPUBuffer* overlap0, GPUBuffer* overlap1, int nx, int ny, int nz, 62 | int order1, int order2, 63 | float k0x, float k0y, float dy, float dz, 64 | std::vector* OTF, short wave, ReconParams* pParams); 65 | 66 | __global__ void makeOverlaps0Kernel(int nx, int ny, int nz, 67 | int order1, int order2, float kx, float ky, 68 | float rdistcutoff, float otfcutoff, float zdistcutoff, 69 | float order0_2_factor, float dkx, float dky, float kzscale, 70 | cuFloatComplex *band1im, cuFloatComplex *band1re, 71 | cuFloatComplex *overlap0); 72 | __global__ void makeOverlaps1Kernel(int nx, int ny, int nz, 73 | int order1, int order2, float kx, float ky, 74 | float rdistcutoff, float otfcutoff, float zdistcutoff, 75 | float order0_2_factor, float dkx, float dky, float kzscale, 76 | cuFloatComplex *band2im, cuFloatComplex *band2re, 77 | cuFloatComplex *overlap1); 78 | 79 | __host__ void aTimesConjB(GPUBuffer* overlap0, GPUBuffer* overlap1, 80 | int nx, int ny, int nz, GPUBuffer* crosscorr_c); 81 | __global__ void aTimesConjBKernel(cuFloatComplex* overlap0, 82 | cuFloatComplex* overlap1, int nx, int ny, int nz, 83 | cuFloatComplex* crosscorr_c); 84 | 85 | __host__ void computeIntensities(GPUBuffer* amplitudes, int nx, int ny, 86 | GPUBuffer* intensities); 87 | __global__ void computeIntensitiesKernel(cuFloatComplex* amplitudes, 88 | int nx, int ny, float* intensities); 89 | 90 | __host__ void findpeak(float array[], int sizex, int sizey, vector *peak); 91 | __host__ float fitparabola( float a1, float a2, float a3); 92 | 93 | __host__ void computeIntensities(GPUBuffer* amplitudes, int nx, int ny, 94 | GPUBuffer* intensities); 95 | 96 | __host__ float getmodamp(float kangle, float klength, 97 | std::vector* bands, GPUBuffer* overlap0, GPUBuffer* overlap1, 98 | int nx, int ny,int nz, int order1, int order2, float dy, float dz, 99 | std::vector* otf, short wave, cuFloatComplex* modamp, 100 | int redoarrays, ReconParams *pParams, int bShowDetail); 101 | 102 | __host__ float findrealspacemodamp(std::vector* bands, 103 | GPUBuffer* overlap0, GPUBuffer* overlap1, int nx, int ny, int nz, 104 | int order1, int order2, vector k0, float dy, float dz, 105 | std::vector* OTF, short wave, cuFloatComplex* modamp1, 106 | cuFloatComplex* modamp2, cuFloatComplex* modamp3, int redoarrays, 107 | ReconParams *pParams); 108 | 109 | __global__ void reductionKernel( 110 | int nx, int ny, int nz, 111 | float kx, float ky, float dxy, 112 | const cuFloatComplex *overlap0, const cuFloatComplex *overlap1, 113 | cuFloatComplex *XStarY, float *sumXMag, float *sumYMag); 114 | 115 | __host__ float fitxyparabola( float x1, float y1, float x2, float y2, 116 | float x3, float y3); 117 | 118 | __device__ cuFloatComplex dev_otfinterpolate(cuFloatComplex * otf, float 119 | kx, float ky, int kz, float kzscale); 120 | 121 | __device__ float dev_suppress(float x); 122 | __device__ float dev_mag2(cuFloatComplex x); 123 | __device__ float dev_order0damping(float radius, float zindex, float rlimit, int zlimit); 124 | __global__ void move_kernel(cuFloatComplex *inarray1, cuFloatComplex *inarray2, int order, 125 | cuFloatComplex *outarray, int nx, int ny, int nz, float 126 | zoomfact, int z_zoom); 127 | __global__ void write_outbuffer_kernel1(cuFloatComplex * bigbuffer, 128 | float * outbuffer, int); 129 | __global__ void write_outbuffer_kernel2(float * coslookup, float * sinlookup, 130 | cuFloatComplex * bigbuffer, float * outbuffer, int); 131 | 132 | __global__ void cos_sin_kernel(float k0x, float k0y, float dxy, float fact, 133 | float * coslookup, float * sinlookup, int); 134 | 135 | __global__ void filterbands_kernel1(int dir, int ndirs, int order, int norders, int nx, 136 | int ny, int nz, float rdistcutoff, float zapocutoff, float apocutoff, 137 | float krscale, float kzscale, 138 | cuFloatComplex * dev_bandptr, cuFloatComplex * dev_bandptr2, bool bSecondEntry); 139 | 140 | // __global__ void filterbands_kernel2(int dir, int ndirs, int order, int norders, int nx, 141 | // int ny, int nz, float rdistcutoff, float zapocutoff, float apocutoff, 142 | // float krscale, float kzscale, /*cuFloatComplex *dev_scale,*/ cuFloatComplex * dev_tempbandplus, 143 | // cuFloatComplex * dev_bandptr, cuFloatComplex * dev_bandptr2); 144 | 145 | __global__ void filterbands_kernel3(int order, int nx, int ny, int nz, 146 | cuFloatComplex * dev_bandptr, cuFloatComplex * 147 | dev_bandptr2); 148 | 149 | __global__ void filterbands_kernel4(int order, int nx, int ny, int nz, 150 | cuFloatComplex * dev_tempbandplus, cuFloatComplex * dev_bandptr, 151 | cuFloatComplex * dev_bandptr2); 152 | 153 | __global__ void separate_kernel(int norders, int nphases, int nx, int ny, int nz); 154 | __global__ void computeAminAmax_kernel(const float* data, int numElems, 155 | float* maxPartialResult, float* minPartialResult); 156 | 157 | __global__ void summation_kernel(float * img, double * intRes, int n); 158 | __global__ void sumAboveThresh_kernel(float * img, double * intRes, unsigned * counter, float thresh, int n); 159 | __global__ void scale_kernel(float * img, double factor, int n); 160 | 161 | 162 | template 163 | T cpuReduce(const T* vec, int n) { 164 | T red = 0; 165 | for (int i = 0; i < n; ++i) { 166 | red += vec[i]; 167 | } 168 | return red; 169 | } 170 | 171 | cuFloatComplex cpuReduce(const cuFloatComplex* vec, int n) { 172 | cuFloatComplex red; 173 | red.x = 0; 174 | red.y = 0; 175 | for (int i = 0; i < n; ++i) { 176 | red.x += vec[i].x; 177 | red.y += vec[i].y; 178 | } 179 | return red; 180 | } 181 | #endif 182 | -------------------------------------------------------------------------------- /VStutio_project/VStutio_project.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | {363C1217-D4E3-4ABE-BAE9-567D3B9A730C} 32 | Win32Proj 33 | VStutio_project 34 | $(CUDA_PATH) 35 | cudaRecon 36 | 37 | 38 | 39 | Application 40 | true 41 | v120 42 | Unicode 43 | 44 | 45 | Application 46 | true 47 | v120 48 | Unicode 49 | 50 | 51 | Application 52 | false 53 | v120 54 | true 55 | Unicode 56 | 57 | 58 | Application 59 | false 60 | v120 61 | true 62 | Unicode 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | true 83 | 84 | 85 | true 86 | 87 | 88 | false 89 | 90 | 91 | false 92 | $(SolutionDir) 93 | cudaSireconDriver 94 | 95 | 96 | 97 | 98 | 99 | Level3 100 | Disabled 101 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 102 | 103 | 104 | Console 105 | true 106 | 107 | 108 | 109 | 110 | 111 | 112 | Level3 113 | Disabled 114 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 115 | 116 | 117 | Console 118 | true 119 | 120 | 121 | 122 | 123 | Level3 124 | 125 | 126 | MaxSpeed 127 | true 128 | true 129 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 130 | 131 | 132 | Console 133 | true 134 | true 135 | true 136 | 137 | 138 | 139 | 140 | Level3 141 | 142 | 143 | MaxSpeed 144 | true 145 | true 146 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 147 | $(CUDA_PATH)/include;../Buffers;C:/libtiff;../IVE/win64/INCLUDE;C:/Boost/boost_1_55_0 148 | None 149 | 150 | 151 | Console 152 | true 153 | true 154 | true 155 | C:\Boost\boost_1_55_0\lib;$(CUDA_PATH)\lib\x64;C:\libtiff;..\lapack\win64;..\IVE\win64\lib;$(SolutionDir) 156 | cuda.lib;cudart.lib;cufft.lib;libtiff.lib;liblapack.lib;libblas.lib;libimlib.lib;libive.lib;Buffers.lib;%(AdditionalDependencies) 157 | 158 | 159 | 64 160 | compute_20,sm_20;compute_30,sm_30 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /src/cudaSirecon/cudaSireconImpl.h: -------------------------------------------------------------------------------- 1 | #ifndef __CUDA_SIRECON_H 2 | #define __CUDA_SIRECON_H 3 | 4 | #ifdef _WIN32 5 | #define _USE_MATH_DEFINES 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifndef __clang__ 20 | #include 21 | #endif 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include "Buffer.h" 30 | #include "GPUBuffer.h" 31 | #include "CPUBuffer.h" 32 | #include "PinnedCPUBuffer.h" 33 | #include "gpuFunctions.h" 34 | 35 | #define cimg_use_tiff 36 | #include 37 | using namespace cimg_library; 38 | 39 | #ifdef MRC 40 | #include // MRC file I/O routines 41 | #endif 42 | 43 | 44 | // Block sizes for reduction kernels 45 | #define RED_BLOCK_SIZE_X 64 46 | #define RED_BLOCK_SIZE_Y 4 47 | 48 | // Some simulation parameters 49 | /**ratio of beam size in pupil to pupil size */ 50 | #define SPOTRATIO 0.1 51 | #define MAXPHASES 25 52 | 53 | /** If k0 initial estimate is off from the guess by over this percentage, a warning will be displayed */ 54 | #define K0_WARNING_THRESH 0.05 55 | 56 | 57 | #define CHECKED_DELETE(PTR) \ 58 | if (PTR) {\ 59 | delete PTR;\ 60 | PTR = 0;\ 61 | } 62 | #define CHECKED_DELETE_ARR(PTR) \ 63 | if (PTR) {\ 64 | delete [] PTR;\ 65 | PTR = 0;\ 66 | } 67 | 68 | //static TIFF *otf_tiff; // TODO: get rid of this; use "CImg<> m_otf_tiff" member in SIM_reconstructor instead. 69 | 70 | static const int istream_no = 1; 71 | static const int ostream_no = 2; 72 | static const int otfstream_no = 3; 73 | static const int aligned_stream_no = 10; 74 | static const int separated_stream_no = 11; 75 | static const int overlaps_stream_no = 12; 76 | 77 | #ifdef MRC 78 | // static IW_MRC_HEADER header; 79 | static IW_MRC_HEADER aligned_header; 80 | static IW_MRC_HEADER sep_header; 81 | static IW_MRC_HEADER overlaps_header; 82 | #endif 83 | 84 | struct myExtHeader { 85 | float timestamp; 86 | float phaseAbsDeg; 87 | float expDose; 88 | float xdrift; 89 | float ydrift; 90 | }; 91 | 92 | 93 | struct vector { 94 | float x; 95 | float y; 96 | }; 97 | struct vector3d { 98 | float x; 99 | float y; 100 | float z; 101 | }; 102 | 103 | /** Overall image reconstruction parameters. */ 104 | struct ReconParams { 105 | float k0startangle, linespacing; 106 | float na, nimm; 107 | int ndirs, nphases, norders_output; 108 | int norders; 109 | float *phaseSteps; /** user-specified non-ideal phase steps, one for each orientation */ 110 | bool bTwolens; /** whether to process I{^5}S dataset */ 111 | bool bFastSIM; /** fast SIM data is organized differently */ 112 | bool bBessel; /** whether to process Bessel-Sheet SIM dataset */ 113 | float BesselNA; /* excitation NA of the Bessel beam */ 114 | float BesselLambdaEx; /* excitation wavelength of the Bessel beam */ 115 | float deskewAngle; /* Beseel-sheet sample scan angle */ 116 | int extraShift; // If deskewed, the output image's extra shift in X 117 | bool bNoRecon; // whether not to reconstruct; used usually when deskewing 118 | unsigned cropXYto; // crop the X-Y dimension to this size; 0 means no cropping 119 | bool bWriteTitle; /** whether to write command line args to title field in mrc header */ 120 | 121 | /* algorithm related parameters */ 122 | float otfcutoff; /** below which OTF value will be deemed as noise and not used in makeoverlaps*/ 123 | float zoomfact; 124 | int z_zoom; 125 | int nzPadTo; /** pad zero sections to this number of z sections */ 126 | float explodefact; 127 | bool bFilteroverlaps; 128 | int recalcarrays; /** whether to calculate the overlaping regions between bands just once or always; used in fitk0andmodamps() */ 129 | int napodize; 130 | int bSearchforvector; 131 | int bUseTime0k0; /** whether to use time 0's k0 fit for the rest of a time series */ 132 | int apodizeoutput; /** 0-no apodize; 1-cosine apodize; 2-triangle apodize; used in filterbands() */ 133 | float apoGamma; 134 | int bSuppress_singularities; /** whether to dampen the OTF values near band centers; used in filterbands() */ 135 | int suppression_radius; /** if suppress_singularities is 1, the range within which suppresion is applied; used in filterbands() */ 136 | bool bDampenOrder0; /** whether to dampen the OTF values near band centers; used in filterbands() */ 137 | int bFitallphases; /** In NL SIM, whether to use fitted phase for all orders or to infer higher order phase from order 1 phase fil */ 138 | int do_rescale; /** fading correction method: 0-no correction; 1-with correction */ 139 | bool equalizez; 140 | bool equalizet; 141 | bool bNoKz0; /** if true, no kz=0 plane is used in modamp fit and assemblerealspace() */ 142 | float wiener, wienerInr; 143 | // // int bUseEstimatedWiener; 144 | std::vector forceamp; 145 | // float *k0angles; 146 | std::vector k0angles; 147 | 148 | /** OTF specific parameters */ 149 | int nxotf, nyotf, nzotf; 150 | float dzPSF; /** PSF's z step size (for non-MRC formats) */ 151 | float dkzotf, dkrotf; /** OTF's pixel size in inverse mirons */ 152 | bool bRadAvgOTF; /** is radially-averaged OTF used? */ 153 | bool bOneOTFperAngle; /** one OTF per SIM angle (instead of common OTF for all angles)?*/ 154 | 155 | /* drift correction and phase step correction related flags */ 156 | int bFixdrift; /** whether nor not to correct drift between pattern directions */ 157 | float drift_filter_fact; /** fraction of the NA; used as the cutoff frequency in high-pass filtering in drift estimation */ 158 | 159 | /* Camera related parameters */ 160 | float constbkgd; 161 | int bBgInExtHdr; /** In Andor EMCCD, background varies with each exposure, esp. in EM mode. Hidden-behind-aluminum-foil pixels can be used to estimate background of each exposure and stored in the extended header. When this option is true, the 3rd float of the extended header stores such estimated background values. */ 162 | int bUsecorr; /** whether to use a camera flat-fielding (or correction) file */ 163 | std::string corrfiles; /** name of the camera correction file if bUsecorr is 1 */ 164 | float readoutNoiseVar; 165 | float electrons_per_bit; 166 | 167 | /* Debugging flags */ 168 | int bMakemodel; /** whether to fake an ideal point source and obtain a recontruction of it (i.e., an effective PSF in some sense) */ 169 | int bSaveSeparated; /** whether to save separated bands and then quit before filterbands */ 170 | std::string fileSeparated; 171 | int bSaveAlignedRaw; /** whether to save dirft-corrected raw images (within each direction) and then quit before filterbands */ 172 | std::string fileRawAligned; 173 | int bSaveOverlaps; /** whether to save makeoverlaps() output into a file */ 174 | std::string fileOverlaps; 175 | 176 | bool bTIFF; 177 | std::string ifiles; 178 | std::string ofiles; 179 | std::string otffiles; 180 | }; 181 | struct ImageParams { 182 | int nx; //! image's width after deskewing or same as "nx_raw" 183 | int nx_raw; //! raw image's width before deskewing 184 | int ny; 185 | int nz; 186 | int nz0; 187 | short nwaves; 188 | short wave[5]; 189 | short ntimes; 190 | unsigned short curTimeIdx; 191 | float dxy; 192 | float dz; 193 | float dz_raw; //! used when deskew is performed on raw data; to remember the original dz before de-skewing 194 | float inscale; 195 | }; 196 | struct DriftParams { 197 | vector3d* driftlist; 198 | float* phaseList; 199 | vector* driftAcq; 200 | vector3d* drifts; 201 | float* phaseAbs; 202 | float* timestamps; 203 | float* timestamps_for_fitting; 204 | float* expDose; 205 | vector3d* drift_bt_dirs; 206 | DriftParams() : driftlist(0), phaseList(0), driftAcq(0), drifts(0), 207 | phaseAbs(0), timestamps(0), timestamps_for_fitting(0), expDose(0) { 208 | }; 209 | ~DriftParams() { 210 | CHECKED_DELETE_ARR(driftlist); 211 | CHECKED_DELETE_ARR(phaseList); 212 | CHECKED_DELETE_ARR(driftAcq); 213 | CHECKED_DELETE_ARR(drifts); 214 | CHECKED_DELETE_ARR(phaseAbs); 215 | CHECKED_DELETE_ARR(timestamps); 216 | CHECKED_DELETE_ARR(timestamps_for_fitting); 217 | CHECKED_DELETE_ARR(expDose); 218 | }; 219 | }; 220 | struct ReconData { 221 | size_t sizeOTF; 222 | std::vector > otf; 223 | CPUBuffer background; 224 | CPUBuffer slope; 225 | float backgroundExtra; 226 | std::vector > savedBands; 227 | std::vector sepMatrix; 228 | std::vector noiseVarFactors; 229 | GPUBuffer overlap0; 230 | GPUBuffer overlap1; 231 | std::vector k0; 232 | std::vector k0_time0; 233 | std::vector k0guess; 234 | std::vector > amp; 235 | std::vector sum_dir0_phase0; 236 | GPUBuffer bigbuffer; 237 | GPUBuffer outbuffer; 238 | }; 239 | 240 | 241 | void SetDefaultParams(ReconParams *pParams); 242 | 243 | 244 | // Functions for dealing with input images 245 | 246 | /** General setup applicable to all times and waves 247 | * Sets up image parameters and sets up OTFs. 248 | * Allocates memory for images on GPU, and for sepmatrix and noisevars on CPU. 249 | * */ 250 | // void setup(ReconParams* params, ImageParams* 251 | // imgParams, DriftParams* driftParams, ReconData* data); 252 | #ifdef MRC 253 | void loadHeader(const ReconParams& params, ImageParams* imgParams, IW_MRC_HEADER &header); 254 | #endif 255 | 256 | void allocateOTFs(ReconParams *pParams, int sizeOTF, std::vector > & otfs); 257 | void allocateImageBuffers(const ReconParams& params, 258 | const ImageParams& imgParams, ReconData* reconData); 259 | 260 | #ifdef MRC 261 | void setOutputHeader(const ReconParams& myParams, const ImageParams& imgParams, 262 | IW_MRC_HEADER &header); 263 | #endif 264 | 265 | void bgAndSlope(const ReconParams& myParams, 266 | const ImageParams& imgParams, ReconData* reconData); 267 | 268 | void getbg_and_slope(const char *corrfiles, float *background, 269 | float *slope, int nx, int ny); 270 | 271 | void makematrix(int nphases, int norders, int dir, float *arrPhases, 272 | float *sepMatrix, float * noiseVarFactors); 273 | 274 | void allocSepMatrixAndNoiseVarFactors(const ReconParams& params, 275 | ReconData* reconData); 276 | 277 | void load_and_flatfield(CImg<> &cimg, int section_no, float *bufDestiny, 278 | float *background, float backgroundExtra, 279 | float *slope, float inscale); 280 | void deskewOneSection(CImg<> &rawSection, float* nxp2OutBuff, int z, int nz, 281 | int nx_out, float deskewFactor, int extraShift); 282 | // For TIFF inputs 283 | // void load_and_flatfield(CImg<> &cimg, int section_no, float *bufDestiny, 284 | // float background, float inscale); 285 | 286 | // // For MRC inputs 287 | // void load_and_flatfield(int section_no, int wave_no, 288 | // int time_no, float *bufDestiny, float *buffer, int nx, int ny, 289 | // float *background, float backgroundExtra, float *slope, float inscale, 290 | // int bUsecorr); 291 | 292 | #ifdef MRC 293 | int saveIntermediateDataForDebugging(const ReconParams& params); 294 | #endif 295 | 296 | void matrix_transpose(float* mat, int nRows, int nCols); 297 | 298 | void findModulationVectorsAndPhasesForAllDirections( 299 | int zoffset, ReconParams* params, const ImageParams& imgParams, 300 | DriftParams* driftParams, ReconData* data); 301 | 302 | void apodizationDriver(int zoffset, ReconParams* params, 303 | const ImageParams& imgParams, DriftParams* driftParams, ReconData* data); 304 | void rescaleDriver(int it, int iw, int zoffset, ReconParams* params, 305 | const ImageParams& imgParams, DriftParams* driftParams, ReconData* data); 306 | void transformXYSlice(int zoffset, ReconParams* params, 307 | const ImageParams& imgParams, DriftParams* driftParams, ReconData* data); 308 | 309 | // // int fitXYdrift(vector3d *drifts, float * timestamps, int nPoints, 310 | // // vector3d *fitted_drift, float *eval_timestamps, int nEvalPoints); 311 | // // void calcPhaseList(float * phaseList, vector3d *driftlist, 312 | // // float *phaseAbs, float k0angle, float linespacing, 313 | // // float dr, int nphases, int nz, int direction, int z); 314 | 315 | void writeResult(int it, int iw, const ReconParams& params, 316 | const ImageParams& imgParams, const ReconData& reconData); 317 | 318 | // This only works for MRC/DV files for now: 319 | #ifdef MRC 320 | void saveCommandLineToHeader(int argc, char **argv, IW_MRC_HEADER &header); 321 | #endif 322 | 323 | void dumpBands(std::vector* bands, int nx, int ny, int nz0); 324 | 325 | void deviceMemoryUsage(); 326 | 327 | double meanAboveBackground_GPU(GPUBuffer &img, int nx, int ny, int nz); 328 | void rescale_GPU(GPUBuffer &img, int nx, int ny, int nz, float scale); 329 | // void deskew_GPU(std::vector * pImgs, int nx, int ny, int nz, float deskewAngle, float dz_prior_to, float dr, int extraShift, float fillVal); 330 | 331 | // Compute rdistcutoff 332 | // int rdistcutoff(int iw, const ReconParams& params, const ImageParams& imgParams); 333 | float get_phase(cuFloatComplex b); 334 | float cmag(cuFloatComplex a); 335 | cuFloatComplex cmul(cuFloatComplex a, cuFloatComplex b); 336 | 337 | // Extern Blas and Lapack declarations 338 | extern "C" void sgemm_(const char*, const char*, int*, int*, int*, 339 | float*, float*, int*, float*, int*, float*, float*, int*); 340 | extern "C" void sgetrf_(int*, int*, float*, int*, int*, int*); 341 | extern "C" void sgetri_(int*, float*, int*, int*, float*, int*, int*); 342 | extern "C" void sgels_(const char*, int*, int*, int*, float*, int*, float*, 343 | int*, float*, int*, int*); 344 | 345 | extern "C" int load_tiff(TIFF *const tif, const unsigned int directory, const unsigned colind, float *const buffer); 346 | extern "C" int save_tiff(TIFF *tif, const unsigned int directory, int colind, const int nwaves, int width, int height, float * buffer , int bIsComplex); 347 | std::vector gatherMatchingFiles(std::string target_path, std::string pattern); 348 | std::string makeOutputFilePath(std::string inputFileName, std::string insert); 349 | 350 | #endif 351 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cudasirecon 2 | 3 | Mats Gustafsson & Lin Shao's 3-beam SIM reconstruction software, with CUDA acceleration. 4 | 5 | Algorithm as described in [Gustafsson et al (2008) *Biophys. J.* **94(12)**: 4957–4970. doi: 10.1529/biophysj.107.120345](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2397368/) 6 | 7 | 8 | ## Installation 9 | 10 | Packages for Linux and Windows on conda-forge: 11 | 12 | ```bash 13 | $ conda install -c conda-forge cudasirecon 14 | 15 | # you may wish to put it in a new environment ("sim" here): 16 | $ conda create -n sim -y -c conda-forge cudasirecon 17 | $ conda activate sim 18 | ``` 19 | 20 | In the examples shown above and below, *Shell* command line is used. The same works mostly in a Anaconda Prompt window on Windows, except for using`\`in place of`/`as the folder name dividers 21 | 22 | ## Usage 23 | ### For`cudasirecon` 24 | 25 | ```bash 26 | # the binary will be available as 27 | $ cudasirecon 28 | 29 | # for command line help 30 | $ cudasirecon --help 31 | # or: 32 | $ cudasirecon -h 33 | 34 | # a typical call for tiff files 35 | $ cudasirecon some/folder file_pattern otf.tif -c config_file 36 | 37 | # a typical call for dv/mrc files 38 | $ cudasirecon data.dv data-proc.dv otf.dv -c config_file 39 | 40 | ``` 41 | 42 | #### Notes 43 | - `cudasirecon`should be supplied (unless to just display help message) with at least three arguments, which are interpreted differently depending on whether the input files are in TIFF or MRC/DV format: 44 | - For MRC/DV format, the three arguments represent`input_file_name`,`output_file_name`, and `otf_file_name`in that order 45 | - For TIFF format, the three arguments represent `input_files_folder`,`pattern_shared_among_the_input_files`, and`otf_file_name`in that order; the output files are saved in a subfolder named `GPUsirecon` (subject to change) under `input_files_folder` 46 | - The order of these three arguments, to be called *positional arguments* hereafter, is essential because their position determines how the program interprets them (unless a specific option names preceeds them; more on that below). 47 | - The reason for such difference is that MRC/DV format usually stores a full time-series of 3D or 2D images in a single file, while in TIFF format typically each time point is saved in a separate TIFF file with a slightly different names from other files in the same series. 48 | - Besides these three arguments, `cudasirecon` is typically supplied with options or flags (a detailed list is below). For example `--ndirs 3` informs the program the number of SIM pattern angles; or `--bessel` to inform that the data was acquired in lattice-light-sheet mode. All options that require an argument have a default setting if that option is not specified (for example one can skip the `--ndirs 3` option because that's the default). There is no rules on ordering of the options/flags and they can appear either before or after or even in-between the three positional arguments. 49 | - The `-c` or `--config` option allows using a config file (as demo'ed in the above Shell scipt) to specify multiple options, with one`option_name=option_value`pair per each line and the choices for`option_name`are the same as the command-line option names (the long form preceded with`--`). An example 3D SIM config file may look like this: 50 | 51 | ```bash 52 | nimm=1.515 53 | background=90 54 | wiener=0.001 55 | # angles of illumination in radians 56 | k0angles=-0.804300,-1.8555,0.238800 57 | ls=0.2035 58 | ndirs=3 59 | nphases=5 60 | na=1.42 61 | otfRA=1 62 | dampenOrder0=1 63 | ``` 64 | 65 | - OTF files are converted from PSF files using`makeotf`program also included in this package; more on its usage below. 66 | 67 | 68 | ### Full list of options/flags for`cudasirecon` 69 | 70 | ```txt 71 | $ cudasirecon --help 72 | Usage: 73 | cudasirecon [--options] [option-arguments] input_file(or folder) output_file(or file name pattern) otf_file 74 | 75 | List of options: 76 | --input-file arg input file name (or data folder in TIFF mode) 77 | --output-file arg output file name (or filename pattern in TIFF mode) 78 | --otf-file arg OTF file name 79 | -c [ --config ] arg name of a config file with parameters in place of command-line options 80 | --ndirs arg (=3) number of SIM directions 81 | --nphases arg (=5) number of pattern phases per SIM direction 82 | --nordersout arg (=0) number of output SIM orders (must be <= nphases//2; safe to ignore usually) 83 | --angle0 arg (=1.648) angle of the first SIM angle in radians 84 | --ls arg (=0.172) line spacing of SIM pattern in microns 85 | --na arg (=1.2) detection objective's numerical aperture 86 | --nimm arg (=1.33) refractive index of immersion medium 87 | --wiener arg (=0.01) Wiener constant; lower value leads to higher resolution and noise; 88 | playing with it extensively is strongly encouraged 89 | --zoomfact arg (=2) lateral zoom factor in the output over the input images; 90 | leaving it at 2 should be fine in most cases 91 | --zzoom arg (=1) axial zoom factor; almost never needed 92 | --background arg (=0) camera readout background 93 | --usecorr arg use a flat-field correction file if provided 94 | --forcemodamp arg modamps to be forced to these values; useful when 95 | image quality is low and auto-estimated modamps 96 | are below, say, 0.1 97 | --k0angles arg user these pattern vector k0 angles for all 98 | directions (instead of inferring the rest agnles 99 | from angle0) 100 | --otfRA using rotationally averaged OTF; otherwise using 101 | 3/2D OTF for 3/2D raw data 102 | --otfPerAngle using one OTF per SIM angle; otherwise one OTF is 103 | used for all angles, which is how it's been done 104 | traditionally 105 | --fastSI SIM image is organized in Z->Angle->Phase order; 106 | otherwise assuming Angle->Z->Phase image order 107 | --k0searchAll [=arg(=0)] search for k0 at all time points 108 | --norescale [=arg(=0)] no bleach correction 109 | --equalizez bleach correction for z 110 | --equalizet bleach correction for time 111 | --dampenOrder0 dampen order-0 in final assembly; do not use for 2D SIM; good choice for high-background images 112 | --nosuppress [=arg(=0)] do not suppress DC singularity in the result (good choice for 2D/TIRF data) 113 | --nokz0 not using kz=0 plane of the 0th order in the final assembly (mostly for debug) 114 | --gammaApo arg (=1) output apodization gamma; 1.0 means triangular 115 | apo; lower value means less dampening of 116 | high-resolution info at the tradeoff of higher 117 | noise 118 | --explodefact arg (=1) artificially exploding the reciprocal-space 119 | distance between orders by this factor (for debug) 120 | --nofilterovlps [=arg(=0)] not filtering the overlaping region between bands (for debug) 121 | --saveprefiltered arg save separated bands (half Fourier space) into a file and exit (for debug) 122 | --savealignedraw arg save drift-fixed raw data (half Fourier space) into a file and exit (for debug) 123 | --saveoverlaps arg save overlap0 and overlap1 (real-space complex data) into a file and exit (for debug) 124 | --2lenses I5S data 125 | --bessel bessel-SIM data 126 | --besselExWave arg (=0.488) Bessel SIM excitation wavelength in microns 127 | --besselNA arg (=0.144) Bessel SIM excitation NA) 128 | --deskew arg (=0) Deskew angle; if not 0.0 then perform deskewing before processing 129 | --deskewshift arg (=0) If deskewed, the output image's extra shift in X (positive->left) 130 | --noRecon No reconstruction will be performed; useful when combined with --deskew 131 | --cropXY arg (=0) Crop the X-Y dimension to this number; 0 means no cropping 132 | --xyres arg (=0.1) x-y pixel size (only used for TIFF files) 133 | --zres arg (=0.2) z pixel size (only used for TIFF files) 134 | --zresPSF arg (=0.15) z pixel size used in PSF TIFF files) 135 | --wavelength arg (=530) emission wavelength in nanometers (only used for TIFF files) 136 | --writeTitle Write command line to MRC/DV header (may cause issues with bioformats) 137 | -h [ --help ] produce help message 138 | --version show version 139 | 140 | ``` 141 | 142 | #### Notes on the essential flags 143 | - `--ndirs`and `--nphases` informs the program of the number of SIM angles and phases within each angle, respectively. 144 | - `--ls`, `--angle0` (or `--k0angles`) inform the program of a good estimation on the SIM pattern's line spacing (in µm) and angles (in radians). If using `--angle0`, then the rest of the angles are successively incremented by π/`ndirs`; if using `--k0angles` then list all angles in order and separated by commas without any space. 145 | - `--wiener`specifies the Wiener constant that balances between resolution and amplified noise artifact. The lower it is, the higher the resolution but also more amplified-noise-related artifacts and vice versa. 146 | - `--background`informs the estimated background level of the input images. The camera's dark image's mean intensity would be a good guess to start with. Too high of a background value supplied can be fatal to the reconstruction result. 147 | - `--otfRA` is needed if rotationally averaged OTF is used 148 | - `--fastSI`is needed if Z->Angle->Phase acquisition order is used 149 | - For lattice-light-sheet SIM, one would need the `--bessel` flag and might want to specify the following flags: `--besselNA`, `--besselNA`, `--deskew`, `--deskewshift` 150 | 151 | ### For`makeotf` 152 | The utility of `makeotf` is to generate rotationally averaged OTFs for all SIM orders. The input to it is a single-direction SIM data set acquire with one point-like object as the sample. In general this OTF can be used for reconstructing multi-angle SIM data. 153 | 154 | ``` 155 | # And example of how to call makeotf: 156 | 157 | $ makeotf /path/to/psf.dv otf.dv -angle -1.855500 -ls 0.2075 -na 1.4 -nimm 1.515 -fixorigin 3 20 -leavekz 7 11 3 158 | 159 | # The example above shows practically all flags that are needed for generating a 3D SIM OTF; if 2D SIM or LLSM-SIM you should skip the last two flags. 160 | ``` 161 | #### Essential flags 162 | 163 | - `-fixorigin`takes two integers (>0) as arguments. Purpose of this flag is to suppress the singularity of order-0 (i.e., wide-field) 3D OTF at the origin by extrapolating the OTF's amplitudes between those pixels along the kr axis toward the origin and use that value in the end result. 3 and 20 are in general good for PSFs obtained with at least 256x256 pixels 164 | - **Do not** supply this option to process LLSM-SIM PSFs, as the issue with origin singularity is much less severe. 165 | - `-leavekz`takes three integers as arguments. Purpose of this flag is to zero out the region outside of the OTF support. The first two numbers correspond to the two pixels on the positive kz axis of the order-1 OTF, between which the order-1 OTF support intersects the kz axis. The third number corresponds to a pixel on the positive kz axis, between which and the origin the order-2 OTF support intersects the kz axis. With these other related numbers such as NA and wavelengths, the program could calculate what's inside and what's outside the OTF supports and then zero out the outside parts. 166 | - To get these numbers right, it usually requires trial and error approach and examining the OTF output to see if the carving-out makes sense. 167 | - In TIFF mode, along with the OTF file the program also outputs a companion TIFF file, whose name contains `OnlyForViewing`, that can be easily opened to examine the OTF. 168 | - **Do not** supply this option to process LLSM-SIM PSFs, as the OTF supports are not well defined geometrically. 169 | 170 | 171 | 172 | ## GPU requirements 173 | 174 | This software requires a CUDA-compatible NVIDIA GPU. 175 | 176 | The libraries available on conda-forge have been compiled against different 177 | versions of the CUDA toolkit. The required CUDA libraries are bundled in the 178 | conda distributions so you don't need to install the CUDA toolkit separately. 179 | If desired, you can pick which version of CUDA you'd like based on your needs, 180 | but please note that different versions of the CUDA toolkit have different GPU 181 | driver requirements: 182 | 183 | To specify a specific cudatoolkit version, install as follows (for instance, to use 184 | `cudatoolkit=10.2`): 185 | 186 | ```sh 187 | # NOTE: conda-forge coming soon... not available yet. 188 | conda install -c conda-forge cudasirecon cudatoolkit=10.2 189 | ``` 190 | 191 | | CUDA | Linux driver | Win driver | 192 | | ----- | ------------ | ---------- | 193 | | 10.2 | ≥ 440.33 | ≥ 441.22 | 194 | | 11.0 | ≥ 450.36.06 | ≥ 451.22 | 195 | | 11.1 | ≥ 455.23 | ≥ 456.38 | 196 | | 11.2 | ≥ 460.27.03 | ≥ 460.82 | 197 | 198 | 199 | If your CUDA Driver version is too low for the version of cudasirecon that you have installed, you may get an error that looks like: `!!Error occurred: cudaSetDevice failed` 200 | 201 | If you run into trouble, feel free to [open an issue](https://github.com/scopetools/cudasirecon/issues) and describe your setup. 202 | 203 | 204 | ## Multichannel reconstruction 205 | 206 | `cudasirecon` does not currently accept multi-channel files. So it is necessary 207 | to temporarily pull out each channel into a new file prior to reconstruction. 208 | The provided `recon.py` script is an example of how to use the 209 | [`mrc`](https://github.com/tlambert03/mrc) package to extract individual 210 | channels from a .dv file, reconstruct them, and merge them back (and clean up 211 | the intermediate file). It is used as follows (note, `mrc`, `numpy`, and 212 | `cudasirecon` must be in your path): 213 | 214 | ``` 215 | python recon.py /path/to/raw_data.dv 216 | ``` 217 | 218 | `recon.py` will also accept any key value pairs that `cudasirecon` also accepts 219 | (to see that full list, type `cudasirecon -h` at the command prompt). For 220 | instance, to override just a couple of the reconstruction parameters, you could 221 | do something like this: 222 | 223 | ``` 224 | python recon.py /path/to/raw_data.dv wiener 0.001 background 150 225 | ``` 226 | 227 | There are a couple of hard-coded filepaths in `recon.py`. Specifically, it 228 | currently expects to find the OTFs and config files in the same directory as the 229 | recon.py script. You can change that by putting in an absolute directory to 230 | some other folder for the variables at the top of the file: 231 | 232 | ```python 233 | # path to your otf directory. Defaults to the same as the recon.py file 234 | OTF_DIR = os.path.abspath(os.path.dirname(__file__)) 235 | # path to your config directory. Defaults to the same as the recon.py file 236 | CONFIG_DIR = os.path.abspath(os.path.dirname(__file__)) 237 | ``` 238 | 239 | Note also, that the config and OTF files must be named with the emission 240 | wavelength in the filenames. For example: `config528.txt` and `otf528.otf` 241 | 242 | 243 | ## Compiling locally from source 244 | 245 | #### on linux: 246 | ```sh 247 | conda env create -f environment-linux.yml 248 | conda activate simbuild 249 | ./build.sh # see build.sh for cmake details 250 | 251 | # test it: 252 | ./test_data/run.sh 253 | ``` 254 | 255 | #### on windows: 256 | ```sh 257 | conda env create -f environment-windows.yml 258 | conda activate simbuild 259 | bld.bat # see bld.bat for cmake details 260 | ``` 261 | 262 | ### Building with MRC support 263 | 264 | The IVE/Priism libraries (for MRC/DV support), are not distributed with this 265 | source code and must be acquired seperately from UCSF. Place them in a folder 266 | called `IVE` at the top level of the source folder (same folder as the 267 | cudaSirecon folder). It should minimally have the following files and folders 268 | (example shown for linux, use `.a` or `.lib` as necessary for osx or windows) 269 | 270 | then build with `cmake -DBUILD_MRC=ON ....` 271 | 272 |
273 | 274 | required IVE folder structure 275 | 276 | ``` 277 | cudasirecon 278 | ├── ... 279 | └── IVE/ 280 | ├── darwin64/ 281 | │ ├── INCLUDE/ 282 | │ └── LIB/ 283 | ├── linux64/ 284 | │ ├── INCLUDE/ 285 | │ │ ├── IM.h 286 | │ │ ├── IMInclude.h 287 | │ │ └── IWApiConstants.h 288 | │ └── LIB/ 289 | │ ├── libimlib.a 290 | │ └── libive.a 291 | └── win64/ 292 | ├── INCLUDE/ 293 | └── LIB/ 294 | ``` 295 | 296 |
297 | 298 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------