Commit 25d8d20b5117b6f35d62ce2cdbf4381253d86a45

Authored by David Mayerich
1 parent 193bb525

added FFT support for HSIproc in Agilent imaging systems

Showing 2 changed files with 477 additions and 261 deletions   Show diff stats
stim/envi/agilent_binary.h 0 → 100644
  1 +//make sure that this header file is only loaded once
  2 +#ifndef STIM_AGILENT_BINARY_H
  3 +#define STIM_AGILENT_BINARY_H
  4 +
  5 +#include <string>
  6 +#include <fstream>
  7 +
  8 +//CUDA
  9 +#ifdef CUDA_FOUND
  10 + #include <cuda_runtime.h>
  11 + #include "cufft.h"
  12 + #include <stim/cuda/cudatools/error.h>
  13 +#endif
  14 +
  15 +namespace stim{
  16 +
  17 +template<typename T>
  18 +class agilent_binary{
  19 +
  20 +protected:
  21 + std::string fname;
  22 + T* ptr;
  23 + size_t R[3];
  24 + static const size_t header = 1020;
  25 + double Z[2];
  26 +
  27 +public:
  28 + size_t size(){
  29 + return (size_t)R[0] * (size_t)R[1] * (size_t)R[2];
  30 + }
  31 +
  32 + size_t bytes(){
  33 + return size() * sizeof(T);
  34 + }
  35 + void alloc(){
  36 + ptr = (T*) malloc(bytes());
  37 + }
  38 + void alloc(short x, short y, short z){
  39 + R[0] = x;
  40 + R[1] = y;
  41 + R[2] = z;
  42 + alloc();
  43 + }
  44 +
  45 + void deep_copy(agilent_binary<T>* dst, const agilent_binary<T>* src){
  46 + dst->alloc(src->R[0], src->R[1], src->R[2]); //allocate memory
  47 + memcpy(dst->ptr, src->ptr, bytes()); //copy the data
  48 + memcpy(dst->Z, src->Z, sizeof(double) * 2); //copy the data z range
  49 + }
  50 +
  51 + agilent_binary(){
  52 + memset(R, 0, sizeof(short) * 3); //set the resolution to zero
  53 + ptr = NULL;
  54 + }
  55 +
  56 + /// Constructor with resolution
  57 + agilent_binary(short x, short y, short z){
  58 + alloc(x, y, z);
  59 + }
  60 +
  61 + /// Constructor with filename
  62 + agilent_binary(std::string filename){
  63 + ptr = NULL;
  64 + load(filename);
  65 + }
  66 +
  67 + /// Copy constructor
  68 + agilent_binary(const agilent_binary<T> &obj){
  69 + deep_copy(this, &obj);
  70 + }
  71 +
  72 + agilent_binary<T>& operator=(const agilent_binary<T> rhs){
  73 + if(this != &rhs){ //check for self-assignment
  74 + deep_copy(this, &rhs); //make a deep copy
  75 + }
  76 + return *this; //return the result
  77 + }
  78 +
  79 + ~agilent_binary(){
  80 + free(ptr);
  81 + }
  82 +
  83 + void load(std::string filename){
  84 + if(ptr != NULL) free(ptr); //if memory has been allocated, free it
  85 +
  86 + fname = filename; //save the filename
  87 +
  88 + short x, y, z;
  89 +
  90 + std::ifstream infile(fname, std::ios::binary); //open the input file
  91 + infile.seekg(9, std::ios::beg); //seek past 9 bytes from the beginning of the file
  92 +
  93 + infile.read((char*)(&z), 2); //read two bytes of data (the number of samples is stored as a 16-bit integer)
  94 +
  95 + infile.seekg(13, std::ios::cur); //skip another 13 bytes
  96 + infile.read((char*)(&x), 2); //read the X and Y dimensions
  97 + infile.read((char*)(&y), 2);
  98 +
  99 + infile.seekg(header, std::ios::beg); //seek to the start of the data
  100 +
  101 + alloc(x, y, z);
  102 + ptr = (T*) malloc(bytes()); //allocate space for the data
  103 + infile.read((char*)ptr, bytes()); //read the data
  104 + infile.close();
  105 + }
  106 +
  107 + void save(std::string filename){
  108 + std::ofstream outfile(filename, std::ios::binary); //create an output file
  109 +
  110 + char zero = 0;
  111 + for(size_t i = 0; i < 9; i++) outfile.write(&zero, 1); //write 9 zeros
  112 + outfile.write((char*)&R[0], 2);
  113 + for(size_t i = 0; i < 13; i++) outfile.write(&zero, 1); //write 13 zeros
  114 + outfile.write((char*)&R[1], 2);
  115 + outfile.write((char*)&R[2], 2);
  116 + for(size_t i = 0; i < 992; i++) outfile.write(&zero, 1); //write 992 zeros
  117 + //char zerovec[1020];
  118 + //outfile.write((char*)zerovec, 1020);
  119 +
  120 + size_t b = bytes();
  121 + outfile.write((char*)ptr, b); //write the data to the output file
  122 + outfile.close();
  123 + }
  124 +
  125 + stim::envi_header create_header(){
  126 + stim::envi_header header;
  127 + header.samples = R[0];
  128 + header.lines = R[1];
  129 + header.bands = R[2];
  130 +
  131 + double z_delta = (double)(Z[1] - Z[0]) / (double)(R[2] - 1);
  132 + header.wavelength.resize(R[2]);
  133 + for(size_t i = 0; i < R[2]; i++)
  134 + header.wavelength[i] = i * z_delta + Z[0];
  135 +
  136 + return header;
  137 + }
  138 +
  139 + /// Calculate the absorbance spectrum from the transmission spectrum given a background
  140 + void absorbance(stim::agilent_binary<T>* background){
  141 + size_t N = size(); //calculate the number of values to be ratioed
  142 + if(N != background->size()){
  143 + std::cerr<<"ERROR in stim::agilent_binary::absorbance() - transmission image size doesn't match background"<<std::endl;
  144 + exit(1);
  145 + }
  146 + for(size_t i = 0; i < N; i++)
  147 + ptr[i] = -log10(ptr[i] / background->ptr[i]);
  148 + }
  149 +
  150 +#ifdef CUDA_FOUND
  151 + /// Perform an FFT and return a binary file with bands in the specified range
  152 + agilent_binary<T> fft(float band_min, float band_max){
  153 + auto total_start = std::chrono::high_resolution_clock::now();
  154 +
  155 + auto start = std::chrono::high_resolution_clock::now();
  156 + T* cpu_data = (T*) malloc( bytes() ); //allocate space for the transposed data
  157 + for(size_t b = 0; b < R[2]; b++){
  158 + for(size_t x = 0; x < R[0] * R[1]; x++){
  159 + cpu_data[x * R[2] + b] = ptr[b * R[0] * R[1] + x];
  160 + }
  161 + }
  162 + auto end = std::chrono::high_resolution_clock::now();
  163 + std::chrono::duration<double> diff = end-start;
  164 + // std::cout << "Transpose data: " << diff.count() << " s\n";
  165 +
  166 + start = std::chrono::high_resolution_clock::now();
  167 + cufftHandle plan; //allocate space for a cufft plan
  168 + cufftReal* gpu_data; //create a pointer to the data
  169 + size_t batch = R[0] * R[1]; //calculate the batch size (X * Y)
  170 + HANDLE_ERROR(cudaMalloc((void**)&gpu_data, bytes())); //allocate space on the GPU
  171 + HANDLE_ERROR(cudaMemcpy(gpu_data, cpu_data, bytes(), cudaMemcpyHostToDevice)); //copy the data to the GPU
  172 + cufftComplex* gpu_fft;
  173 + HANDLE_ERROR(cudaMalloc((void**)&gpu_fft, R[0] * R[1] * (R[2]/2 + 1) * sizeof(cufftComplex)));
  174 + end = std::chrono::high_resolution_clock::now();
  175 + diff = end-start;
  176 + //std::cout << "Allocate/copy: " << diff.count() << " s\n";
  177 +
  178 + start = std::chrono::high_resolution_clock::now();
  179 + int N[1]; //create an array with the interferogram size (required for cuFFT input)
  180 + N[0] = R[2]; //set the only array value to the interferogram size
  181 + if(cufftPlanMany(&plan, 1, N, NULL, 1, R[2], NULL, 1, R[2], CUFFT_R2C, batch) != CUFFT_SUCCESS){
  182 + std::cout<<"cuFFT Error: unable to create 1D plan."<<std::endl;
  183 + exit(1);
  184 + }
  185 + end = std::chrono::high_resolution_clock::now();
  186 + diff = end-start;
  187 + //std::cout << "Create a plan: " << diff.count() << " s\n";
  188 +
  189 + start = std::chrono::high_resolution_clock::now();
  190 + if (cufftExecR2C(plan, gpu_data, gpu_fft) != CUFFT_SUCCESS){ //execute the (implicitly forward) transform
  191 + std::cout<<"CUFFT error: ExecR2C Forward failed";
  192 + exit(1);
  193 + }
  194 + end = std::chrono::high_resolution_clock::now();
  195 + diff = end-start;
  196 + //std::cout << "Perform FFT: " << diff.count() << " s\n";
  197 +
  198 + start = std::chrono::high_resolution_clock::now();
  199 + std::complex<T>* cpu_fft = (std::complex<T>*) malloc( R[0] * R[1] * (R[2]/2+1) * sizeof(std::complex<T>) );
  200 + HANDLE_ERROR(cudaMemcpy(cpu_fft, gpu_fft, R[0] * R[1] * (R[2]/2+1) * sizeof(cufftComplex), cudaMemcpyDeviceToHost)); //copy data from the host to the device
  201 +
  202 + double int_delta = 0.00012656; //interferogram sample spacing in centimeters
  203 + double int_length = int_delta * R[2]; //interferogram length in centimeters
  204 + double fft_delta = 1/int_length; //spectrum spacing (in inverse centimeters, wavenumber
  205 +
  206 + size_t start_i = std::ceil(band_min / fft_delta); //calculate the first band to store
  207 + size_t size_i = std::floor(band_max / fft_delta) - start_i; //calculate the number of bands to store
  208 + size_t end_i = start_i + size_i; //last band number
  209 + agilent_binary<T> result(R[0], R[1], size_i);
  210 + result.Z[0] = start_i * fft_delta; //set the range for the FFT result
  211 + result.Z[1] = end_i * fft_delta;
  212 +
  213 + for(size_t b = start_i; b < end_i; b++){
  214 + for(size_t x = 0; x < R[0] * R[1]; x++){
  215 + result.ptr[(b - start_i) * R[0] * R[1] + x] = abs(cpu_fft[x * (R[2]/2+1) + b]);
  216 + }
  217 + }
  218 + end = std::chrono::high_resolution_clock::now();
  219 + diff = end-start;
  220 + //std::cout << "Transpose/Crop: " << diff.count() << " s\n";
  221 +
  222 + auto total_end = std::chrono::high_resolution_clock::now();
  223 + diff = total_end-total_start;
  224 +
  225 + cufftDestroy(plan);
  226 + HANDLE_ERROR(cudaFree(gpu_data));
  227 + HANDLE_ERROR(cudaFree(gpu_fft));
  228 + free(cpu_data);
  229 + free(cpu_fft);
  230 +
  231 + return result;
  232 + }
  233 +#endif
  234 +
  235 +};
  236 +
  237 +}
  238 +
  239 +#endif
0 \ No newline at end of file 240 \ No newline at end of file
stim/parser/filename.h
@@ -2,218 +2,292 @@ @@ -2,218 +2,292 @@
2 #define STIM_FILENAME_H 2 #define STIM_FILENAME_H
3 3
4 #include <stdio.h> /* defines FILENAME_MAX */ 4 #include <stdio.h> /* defines FILENAME_MAX */
  5 +#include <sstream>
  6 +#include <vector>
  7 +#include <algorithm>
  8 +#include <iostream>
  9 +#include <iomanip>
  10 +
  11 +#include <stim/parser/parser.h>
  12 +
  13 +// set OS dependent defines, including:
  14 +// 1) path division character ('/' or '\') used for output only
  15 +// 2) command for getting the current working directory
  16 +// 3) header files for getting the current working directory
  17 +// 4) include BOOST filesystem class if compiling on GCC
  18 +#define STIM_DIV '/'
5 #ifdef _WIN32 19 #ifdef _WIN32
6 #include <windows.h> 20 #include <windows.h>
7 - #include <direct.h>  
8 - #define GetCurrentDir _getcwd  
9 - #define STIM_FILENAME_DIV '/' 21 + #include <direct.h>
  22 + #define GetCurrentDir _getcwd
  23 + #define STIM_FILENAME_DIV '\\'
10 #else 24 #else
11 - #include <unistd.h>  
12 - #define GetCurrentDir getcwd 25 + #ifdef BOOST_PRECOMPILED
  26 + #include <boost/filesystem.hpp>
  27 + #endif
  28 + #include <unistd.h>
  29 + #define GetCurrentDir getcwd
13 #define STIM_FILENAME_DIV '/' 30 #define STIM_FILENAME_DIV '/'
14 #endif 31 #endif
15 32
16 -#include <string>  
17 -#include <sstream>  
18 -#include <iomanip>  
19 -#include <vector>  
20 -#include <stack>  
21 -#include <algorithm>  
22 -#include <iostream>  
23 -  
24 -#include "../parser/parser.h"  
25 -#ifdef BOOST_PRECOMPILED  
26 -#include <boost/filesystem.hpp>  
27 -#endif  
28 namespace stim{ 33 namespace stim{
29 34
30 -//filename class designed to work with both Windows and Unix 35 +class filepath{
  36 +protected:
  37 + std::string _drive; //drive on which the file is located (used for Windows)
  38 + std::vector<std::string> _path; //path for the specified file (list of hierarchical directories)
31 39
32 -class filename{ 40 + /// replaces win32 dividers with the Linux standard (used internally by default)
  41 + std::string unix_div(std::string s) {
  42 + std::replace( s.begin(), s.end(), '\\', '/');
  43 + return s;
  44 + }
33 45
34 -private:  
35 - void init(){ 46 + /// gets the directory hierarchy for the current working directory
  47 + static std::string cwd(){
  48 + char cCurrentPath[FILENAME_MAX];
36 49
37 - absolute = false; 50 + if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))){
  51 + std::cout<<"ERROR getting current working directory."<<std::endl;
  52 + exit(1);
  53 + }
38 54
  55 + std::stringstream ss;
  56 + ss<<cCurrentPath;
  57 + return ss.str();
39 } 58 }
40 59
41 -protected: 60 + /// convert a relative path to an absolute path
  61 + void get_absolute(std::string &drive, std::vector<std::string> &absolute, std::vector<std::string> relative){
42 62
43 - std::string drive; //drive letter (for Windows)  
44 - std::vector<std::string> path; //directory hierarchy  
45 - std::string prefix; //file prefix (without extension)  
46 - std::string ext; //file extension 63 + std::string current = cwd(); //get the current directory as a string
47 64
48 - bool absolute; //filename is an absolute path 65 + std::string current_drive;
  66 + std::vector<std::string> current_dir;
  67 + parse_path(current_drive, current_dir, current); //get the current drive and directories
49 68
50 - //replaces win32 dividers with the Linux standard  
51 - std::string unix_div(std::string s) {  
52 - std::replace( s.begin(), s.end(), '\\', '/');  
53 - return s;  
54 - }  
55 -  
56 - //break up a filename into a prefix and extension  
57 - void parse_name(std::string fname){ 69 + // step through each directory in the relative path, adjusting the current directory
  70 + // index depending on whether the relative path is specified with '.' or '..'
  71 + int current_i = (int)current_dir.size() - 1;
  72 + int relative_i;
  73 + for(relative_i = 0; relative_i < relative.size(); relative_i++){
  74 + if(relative[relative_i] == "..") current_i--;
  75 + else if(relative[relative_i] != ".") break;
  76 + }
  77 + if(current_i < 0){
  78 + std::cerr<<"ERROR stim::filepath - relative path is incompatible with working directory"<<std::endl;
  79 + exit(1);
  80 + }
58 81
59 - //find the extension  
60 - size_t xpos = fname.find_last_of('.'); //find the position of the extension period (if there is one)  
61 - if(xpos != std::string::npos){ //split the prefix and extension  
62 - prefix = fname.substr(0, xpos);  
63 - ext = fname.substr(xpos + 1); 82 + absolute.clear();
  83 + for(size_t i = 0; i <= current_i; i++){
  84 + absolute.push_back(current_dir[i]);
  85 + }
  86 + for(size_t i = relative_i; i < relative.size(); i++){
  87 + absolute.push_back(relative[i]);
64 } 88 }
65 - else  
66 - prefix = fname;  
67 } 89 }
68 90
69 - //parse a file locator string  
70 - void parse(std::string loc){  
71 - if(loc.size() == 0) return;  
72 -  
73 - loc = unix_div(loc);  
74 -  
75 - //determine the drive (if Windows)  
76 - drive = "";  
77 - #ifdef _WIN32  
78 - //if the second character is a colon, the character right before it is the drive  
79 - if(loc[1] == ':'){  
80 - absolute = true; //this is an absolute path  
81 - drive = loc[0]; //copy the drive letter  
82 - loc = loc.substr(3); //remove the drive information from the locator string 91 + /// Parses a directory string into a drive (NULL if not Windows) and list of hierarchical directories
  92 + /// Returns true if the path is relative, false if it is absolute
  93 + void parse_path(std::string &drive, std::vector<std::string> &absolute, std::string dir){
  94 + drive = ""; //initialize the drive to NULL (it will stay that way for Windows)
  95 + std::vector<std::string> path;
  96 + bool relative = true; //the default path is relative
  97 +
  98 + if(dir.length() == 0) return; //return if the file locator is empty
  99 + std::string unix_dir = unix_div(dir); //replace any Windows division characters with Unix
  100 +
  101 + if(unix_dir.length() > 1 && unix_dir[1] == ':'){ //if a drive identifier is given
  102 + if(unix_dir[0] > 64 && unix_dir[0] < 91) //if the drive letter is upper case
  103 + _drive = unix_dir[0] + 32; //convert it to lower case
  104 + else if(unix_dir[0] > 96 && unix_dir[0] < 123) //if the drive character is lower case
  105 + _drive = unix_dir[0]; //store it as-is
  106 + else{ //otherwise throw an error
  107 + std::cerr<<"ERROR stim::filename - drive letter is invalid: "<<unix_dir[0]<<std::endl;
  108 + exit(1);
83 } 109 }
84 - #else  
85 - if(loc[0] == STIM_FILENAME_DIV){  
86 - absolute = true;  
87 - loc = loc.substr(1);  
88 - }  
89 - #endif  
90 -  
91 - //determine the file name  
92 - std::string fname = loc.substr( loc.find_last_of('/') + 1 ); //find the file name (including extension) 110 + unix_dir = unix_dir.substr(2, unix_dir.length()-2); //extract the directory structure
  111 + }
93 112
94 - //parse the file name  
95 - parse_name(fname); 113 + if(unix_dir.front() == '/'){ //if there is a leading slash
  114 + relative = false; //the path is not relative
  115 + unix_dir = unix_dir.substr(1, unix_dir.length() - 1); //remove the slash
  116 + }
  117 + if(unix_dir.back() == '/')
  118 + unix_dir = unix_dir.substr(0, unix_dir.length() - 1);
96 119
97 - //find the directory hierarchy  
98 - std::string dir = loc.substr(0, loc.find_last_of('/') + 1 );  
99 - path = stim::parser::split(dir, '/'); 120 + path = stim::parser::split(unix_dir, '/'); //split up the directory structure
  121 +
  122 + if(relative)
  123 + get_absolute(drive, absolute, path);
  124 + else
  125 + absolute = path;
100 } 126 }
101 127
102 -public: 128 +
103 129
104 - filename(){  
105 - init(); 130 +public:
  131 + filepath(){
  132 + _drive = "";
106 } 133 }
107 134
108 - filename(std::string loc){  
109 - init();  
110 - parse(loc); 135 + filepath(const stim::filepath& p){
  136 + *this = p;
111 } 137 }
112 138
  139 + filepath(const std::string s){
  140 + parse_path(_drive, _path, s);
  141 + }
113 142
114 - /// Outputs the file name (including prefix and extension)  
115 - std::string get_name(){  
116 - if(prefix == "" && ext == "")  
117 - return "";  
118 - else  
119 - return prefix + "." + ext; 143 + stim::filepath& operator=(const std::string s){
  144 + parse_path(_drive, _path, s); //parse the string to get the drive and relative path
  145 + return *this;
120 } 146 }
121 147
122 - /// Output the file extension only (usually three characters after a '.')  
123 - std::string get_extension(){  
124 - return ext; 148 + std::string str(){
  149 + std::stringstream ss;
  150 + if(_drive != "") //if a drive letter is specified
  151 + ss<<_drive<<":"; //add it to the string
  152 + for(size_t i = 0; i < _path.size(); i++)
  153 + ss<<STIM_FILENAME_DIV<<_path[i];
  154 + ss<<STIM_FILENAME_DIV;
  155 + return ss.str();
  156 + }
  157 +}; //end filepath
  158 +
  159 +class filename : public filepath{
  160 +protected:
  161 + std::string _prefix; //filename prefix
  162 + std::string _extension; //filename extension
  163 +
  164 + void set_filename(std::string fname){
  165 + size_t ext_i = fname.find_last_of('.'); //calculate the index of the '.'
  166 + if(ext_i != std::string::npos){ //if there is an extension
  167 + _prefix = fname.substr(0, ext_i); //store the prefix
  168 + _extension = fname.substr(ext_i + 1, fname.size() - ext_i - 1); //store the extension
  169 + }
  170 + else //otherwise just store the prefix
  171 + _prefix = fname;
125 } 172 }
126 173
127 - /// Output the file prefix only (name before the extension)  
128 - std::string get_prefix(){  
129 - return prefix; 174 +public:
  175 + filename(){}
  176 +
  177 + filename(stim::filepath p, std::string fname) : stim::filepath(p){
  178 + set_filename(fname);
130 } 179 }
131 180
132 - /// Output the entire path (not including the filename)  
133 - /// ex. "c:\this\is\the\directory\"  
134 - std::string dir(){  
135 - std::stringstream ss; 181 + stim::filename& operator=(const std::string s){
  182 + std::string unix_s = unix_div(s); //convert dividers to unix
  183 + size_t name_i = unix_s.find_last_of('/'); //find the index of the last divider
136 184
137 - //if the path is absolute  
138 - if(absolute){  
139 - //output the drive letter if in Windows  
140 - #ifdef _WIN32  
141 - ss<<drive<<":";  
142 - #endif  
143 - ss<<STIM_FILENAME_DIV; 185 + if(name_i == std::string::npos){ //if there is no divider, this is just a filename
  186 + unix_s = "./" + unix_s; //append a ./ to the beginning so that the working directory is used
  187 + name_i = 1;
144 } 188 }
145 189
146 - //output the directory  
147 - for(unsigned int d = 0; d < path.size(); d++)  
148 - ss<<path[d]<<STIM_FILENAME_DIV; 190 + name_i++;
149 191
150 - return ss.str();  
151 192
  193 + std::string filename = unix_s.substr(name_i, unix_s.size() - name_i); //extract the filename
  194 + std::string filepath = unix_s.substr(0, name_i-1); //extract the filepath
  195 +
  196 + filepath::operator=(filepath); //parse and store the file path
  197 +
  198 + set_filename(filename);
  199 + return *this;
152 } 200 }
153 201
154 - void clear()  
155 - {  
156 - drive = ""; //drive letter (for Windows)  
157 - path.resize(0);  
158 - prefix= ""; //file prefix (without extension)  
159 - ext = ""; //file extension 202 + filename(std::string s){
  203 + operator=(s);
160 } 204 }
161 205
162 - /// Output the entire string, including the path and filename  
163 - /// ex. "c:\this\is\a\directory\file.txt" 206 +
  207 +
164 std::string str(){ 208 std::string str(){
165 - std::stringstream ss; //create a string stream  
166 - ss<<dir()<<get_name(); //push the directory and filename to that stream  
167 - return ss.str(); //convert the stream to a string and return it 209 + std::stringstream ss;
  210 + ss<<filepath::str()<<_prefix;
  211 + if(_extension.size() != 0)
  212 + ss<<"."<<_extension;
  213 + return ss.str();
168 } 214 }
169 215
170 - //*****************************************************************************************************************  
171 - // output is the directory and the prefix and the extension of the files, which are looking for in that directory.  
172 - /// David: I have no idea what this is doing. It looks identical to dir()  
173 - std::string dir_fname(){  
174 - std::stringstream ss; 216 + /// Create a matching file locator with a prefix s
  217 + stim::filename prefix(std::string s){
  218 + stim::filename result = *this;
  219 + result._prefix = s;
  220 + return result;
  221 + }
175 222
176 - //if the path is absolute  
177 - if(absolute){  
178 - //output the drive letter if in Windows  
179 - #ifdef _WIN32  
180 - ss<<drive<<":";  
181 - #endif  
182 - ss<<STIM_FILENAME_DIV;  
183 - } 223 + std::string prefix(){
  224 + return _prefix;
  225 + }
184 226
  227 + std::string get_prefix(){
  228 + return _prefix;
  229 + }
185 230
186 - for(unsigned int d = 0; d < path.size(); d++)  
187 - ss<<path[d]<<STIM_FILENAME_DIV;  
188 - ss<<get_name(); 231 + /// Create a matching file locator with the extension changed to s
  232 + stim::filename extension(std::string s){
  233 + stim::filename result = *this;
  234 + result._extension = s;
  235 + return result;
  236 + }
189 237
190 - return ss.str(); 238 + std::string extension(){
  239 + return _extension;
  240 + }
191 241
  242 + stim::filename fname(std::string s){
  243 + stim::filename result = *this;
  244 + size_t ext_i = s.find_last_of('.'); //calculate the index of the '.'
  245 + if(ext_i != std::string::npos){ //if there is an extension
  246 + result._prefix = s.substr(0, ext_i); //store the prefix
  247 + result._extension = s.substr(ext_i + 1, s.size() - ext_i - 1); //store the extension
  248 + }
  249 + else //otherwise just store the prefix
  250 + result._prefix = s;
  251 + return result;
192 } 252 }
193 253
194 - // output is the directory and the name of the file which are found in that given directory  
195 - std::string f_name(std::string file_name){  
196 - std::stringstream ss; 254 + /// create a matching file locator with the path changed to s
  255 + stim::filename path(std::string s){
  256 + stim::filename result = *this;
  257 + result.parse_path(result._drive, result._path, s);
  258 + return result;
  259 + }
197 260
198 - if(absolute){ //if the path is absolute  
199 - #ifdef _WIN32  
200 - ss<<drive<<":"; //output the drive letter if in Windows  
201 - #endif  
202 - ss<<STIM_FILENAME_DIV; //output a path divider  
203 - } 261 + std::string path(){
  262 + return filepath::str();
  263 + }
204 264
205 - for(unsigned int d = 0; d < path.size(); d++) //for each directory in the current path  
206 - ss<<path[d]<<STIM_FILENAME_DIV; //add that directory, interspersing path dividers 265 + /// Casting operator, casts to a string
  266 + operator std::string(){
  267 + return str();
  268 + }
207 269
208 - stim::filename fn = file_name;  
209 - std::string fn_prefix = fn.prefix;  
210 - std::string fn_ext = fn.ext;  
211 - ss<<fn_prefix + '.' + fn_ext; 270 + /// This function replaces a wildcard in the prefix with the specified string
  271 + stim::filename insert(std::string str){
212 272
213 - return ss.str(); 273 + stim::filename result = *this; //initialize the result filename to the current filename
  274 + size_t loc = result._prefix.find('*'); //find a wild card in the string
  275 + if(loc == std::string::npos) //if a wildcard isn't found
  276 + result._prefix += str; //append the value to the prefix
  277 + else
  278 + result._prefix.replace(loc, 1, str); //replace the wildcard with the string
  279 + return result; //return the result
  280 + }
  281 +
  282 + /// This function replaces a wildcard in the prefix with the specified integer (with a padding of n)
  283 + stim::filename insert(size_t i, size_t n = 2){
214 284
  285 + std::stringstream ss;
  286 + ss << std::setw(n) << std::setfill('0') << i;
  287 + return insert(ss.str());
215 } 288 }
216 289
  290 +
217 /// Returns a list of files using the current filename as a template. 291 /// Returns a list of files using the current filename as a template.
218 /// For example: 292 /// For example:
219 /// C:\this\is\a\path\file*.txt 293 /// C:\this\is\a\path\file*.txt
@@ -223,28 +297,33 @@ public: @@ -223,28 +297,33 @@ public:
223 //the Unix version requires Boost 297 //the Unix version requires Boost
224 298
225 #ifdef _WIN32 299 #ifdef _WIN32
226 - stim::filename filepath(dir_fname()); //initialize filepath with the mask  
227 300
228 HANDLE hFind = INVALID_HANDLE_VALUE; //allocate data structures for looping through files 301 HANDLE hFind = INVALID_HANDLE_VALUE; //allocate data structures for looping through files
229 WIN32_FIND_DATAA FindFileData; 302 WIN32_FIND_DATAA FindFileData;
230 std::vector<stim::filename> file_list; //initialize a list to hold all matching filenames 303 std::vector<stim::filename> file_list; //initialize a list to hold all matching filenames
231 304
232 - hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData); //find the first file that matches the specified file path 305 + std::string path_string = str();
  306 + hFind = FindFirstFileA(path_string.c_str(), &FindFileData); //find the first file that matches the specified file path
233 307
234 if (hFind == INVALID_HANDLE_VALUE) { //if there are no matching files 308 if (hFind == INVALID_HANDLE_VALUE) { //if there are no matching files
235 - printf ("Invalid file handle. Error is %u.\n", GetLastError()); //print an error 309 + //printf ("Invalid file handle. Error is %u.\n", GetLastError()); //print an error
  310 + return file_list;
236 } 311 }
237 else { 312 else {
238 std::string file_name = FindFileData.cFileName; //save the file name 313 std::string file_name = FindFileData.cFileName; //save the file name
239 - std::string file_path = dir(); //the file is in the specified directory, so save it 314 + std::string file_path = path(); //the file is in the specified directory, so save it
240 stim::filename current_file(file_path + file_name); //create a stim::filename structure representing this file 315 stim::filename current_file(file_path + file_name); //create a stim::filename structure representing this file
241 - file_list.push_back(current_file); //push the new stim::filename to the file list 316 + if(!(FindFileData.cFileName[0] == '.' && FindFileData.cFileName[1] == '\0'))
  317 + file_list.push_back(current_file); //push the new stim::filename to the file list
  318 +
242 319
243 // List all the other files in the directory. 320 // List all the other files in the directory.
244 while (FindNextFileA(hFind, &FindFileData) != 0){ //iterate until there are no more matching files 321 while (FindNextFileA(hFind, &FindFileData) != 0){ //iterate until there are no more matching files
245 - file_name = FindFileData.cFileName; //save the next file  
246 - current_file = (f_name(file_name)); //append the directory  
247 - file_list.push_back(current_file); //push it to the list 322 + if(!(FindFileData.cFileName[0] == '.' && FindFileData.cFileName[1] == '.' && FindFileData.cFileName[2] == '\0')){ //account for the possibility of the '..' filename
  323 + file_name = FindFileData.cFileName; //save the next file
  324 + current_file = fname(file_name); //append the directory
  325 + file_list.push_back(current_file); //push it to the list
  326 + }
248 } 327 }
249 FindClose(hFind); //close the file data structure 328 FindClose(hFind); //close the file data structure
250 } 329 }
@@ -287,108 +366,6 @@ public: @@ -287,108 +366,6 @@ public:
287 #endif 366 #endif
288 367
289 } 368 }
290 - //**************************************************************************************************  
291 -  
292 - //gets the current working directory  
293 - static stim::filename cwd(){  
294 -  
295 -  
296 - char cCurrentPath[FILENAME_MAX];  
297 -  
298 - if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))){  
299 - std::cout<<"ERROR getting current working directory."<<std::endl;  
300 - exit(1);  
301 - }  
302 -  
303 - std::cout<<cCurrentPath<<std::endl;  
304 - return stim::filename(std::string(cCurrentPath) + STIM_FILENAME_DIV);  
305 - }  
306 -  
307 - void set_name(std::string fname){  
308 - parse_name(fname);  
309 - }  
310 -  
311 - //append a string to the filename and return a new filename  
312 - stim::filename append(std::string s){  
313 - stim::filename result = *this; //create a new filename, copy the current filename  
314 - result.prefix = prefix + s; //append the string to the filename  
315 - return result;  
316 - }  
317 -  
318 - //get a path relative to the current one  
319 - stim::filename get_relative(std::string rel){  
320 -  
321 - std::vector<std::string> rel_path = stim::parser::split(rel, STIM_FILENAME_DIV);  
322 -  
323 - //if the relative path doesn't contain a file, add a blank string to be used as the filename  
324 - if(rel[rel.size()-1] == STIM_FILENAME_DIV)  
325 - rel_path.push_back("");  
326 -  
327 - //create a stack representing the current absolute path  
328 - std::stack<std::string, std::vector<std::string> > s(path);  
329 -  
330 - //for each token in the relative path  
331 - for(int d=0; d<rel_path.size() - 1; d++){  
332 -  
333 - //if the token is a double-dot, pop a directory off of the stack  
334 - if(rel_path[d] == "..")  
335 - s.pop();  
336 - else  
337 - s.push(rel_path[d]);  
338 - }  
339 -  
340 - std::string* end = &s.top() + 1;  
341 - std::string* begin = end - s.size();  
342 - std::vector<std::string> result_path(begin, end);  
343 -  
344 - //create a new path to be returned  
345 - stim::filename result = *this;  
346 - result.path = result_path;  
347 - result.set_name(rel_path.back());  
348 -  
349 - return result;  
350 - }  
351 -  
352 - /// This function replaces a wildcard in the prefix with the specified string  
353 - stim::filename insert(std::string str){  
354 -  
355 - stim::filename result = *this; //initialize the result filename to the current filename  
356 - size_t loc = result.prefix.find('*'); //find a wild card in the string  
357 - if(loc == std::string::npos) //if a wildcard isn't found  
358 - result.prefix += str; //append the value to the prefix  
359 - else  
360 - result.prefix.replace(loc, 1, str); //replace the wildcard with the string  
361 - return result; //return the result  
362 - }  
363 -  
364 - stim::filename insert(size_t i, size_t n = 2){  
365 -  
366 - std::stringstream ss;  
367 - ss << std::setw(n) << std::setfill('0') << i;  
368 - return insert(ss.str());  
369 - }  
370 -  
371 - bool is_relative(){  
372 - return !absolute;  
373 - }  
374 -  
375 - bool is_absolute(){  
376 - return absolute;  
377 - }  
378 -  
379 -  
380 -  
381 -  
382 -  
383 -  
384 -  
385 -  
386 -  
387 -};  
388 -  
389 -  
390 -} //end namespace stim  
391 -  
392 -  
393 -#endif  
394 - 369 +}; //end filename
  370 +} //end namespace stim
  371 +#endif
395 \ No newline at end of file 372 \ No newline at end of file