Commit 180d7f3ae17a1a239a774f2106a3d79e7392d15f

Authored by David Mayerich
1 parent 0ef519a4

added binary file framework

envi/bil.h 0 → 100644
  1 +#ifndef RTS_BIL_H
  2 +#define RTS_BIL_H
  3 +
  4 +#include "../envi/envi.h"
  5 +
  6 +namespace rts{
  7 +
  8 +//This class specifies a BIL binary file that can be streamed to and from storage media
  9 +template< typename T >
  10 +class bil{
  11 +
  12 +protected:
  13 +
  14 + rts::envi header;
  15 +
  16 +
  17 +public:
  18 +
  19 + bil(){
  20 + init();
  21 + }
  22 +
  23 +};
  24 +
  25 +}
  26 +
  27 +#endif
envi/binary.h 0 → 100644
  1 +#ifndef RTS_BINARY_H
  2 +#define RTS_BINARY_H
  3 +
  4 +#include "../envi/envi.h"
  5 +
  6 +#include <fstream>
  7 +#include <sys/stat.h>
  8 +
  9 +namespace rts{
  10 +
  11 +//This class contains a bunch of functions useful for multidimensional binary file access
  12 +template< typename T, unsigned int D = 3 >
  13 +class binary{
  14 +
  15 +protected:
  16 +
  17 + std::fstream file; //file stream used for reading and writing
  18 + std::string name; //file name
  19 +
  20 + unsigned int R[D]; //resolution
  21 + unsigned int header; //header size (in bytes)
  22 +
  23 +
  24 + //basic initialization
  25 + void init(){
  26 + memset(R, 0, sizeof(unsigned int) * D); //initialize the resolution to zero
  27 + header = 0; //initialize the header size to zero
  28 + }
  29 +
  30 + //returns the file size
  31 + unsigned int get_file_size(){
  32 +
  33 + struct stat results;
  34 + if(stat(name.c_str(), &results) == 0)
  35 + return results.st_size;
  36 + else return 0;
  37 + }
  38 +
  39 + bool test_file_size(){
  40 + unsigned int sum = header; //initialize the sum (in bytes) to the header size
  41 + for(unsigned int i = 0; i<D; i++) //iterate over each dimension, summing the byte size
  42 + sum += R[i] * sizeof(T);
  43 + if(sum == get_file_size()) return true; //if the byte size matches the file size, we're golden
  44 + else return false; //otherwise return an error
  45 +
  46 + }
  47 +
  48 + bool open_file(std::string filename){
  49 + //open the file as binary for reading and writing
  50 + file.open(filename.c_str(), std::ios::in | std::ios::out | std::ios::binary);
  51 +
  52 + //if the file is successful
  53 + if(file){
  54 + name = filename; //set the name
  55 + if(test_file_size()) //test the file size
  56 + return true;
  57 + }
  58 +
  59 + return false;
  60 + }
  61 +
  62 +public:
  63 +
  64 + bool open(std::string filename, vec<unsigned int, D> r, unsigned int h = 0){
  65 + if(!open_file(filename)) return false;
  66 +
  67 + for(unsigned int i = 0; i < D; i++)
  68 + R[i] = r[i];
  69 +
  70 + header = h;
  71 +
  72 + return test_file_size();
  73 + }
  74 +
  75 + bool open(std::string filename, unsigned int X, unsigned int h = 0){
  76 + return open(filename, vec<unsigned int, 1>(X), h);
  77 + }
  78 +
  79 + bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int h = 0){
  80 + return open(filename, vec<unsigned int, 2>(X, Y), h);
  81 +
  82 +
  83 + }
  84 +
  85 + bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int Z, unsigned int h = 0){
  86 + return open(filename, vec<unsigned int, 3>(X, Y, Z), h);
  87 + }
  88 +
  89 +};
  90 +
  91 +}
  92 +
  93 +#endif
1 -#ifndef RTS_ENVI_H  
2 -#define RTS_ENVI_H 1 +#ifndef ENVI_HEADER_H
  2 +#define ENVI_HEADER_H
3 3
4 #include <string> 4 #include <string>
5 -#include <iostream> 5 +#include <iostream>
6 #include <fstream> 6 #include <fstream>
7 -#include <sstream>  
8 -  
9 -#include "rts/envi/envi_header.h"  
10 -  
11 -/* This is a class for reading and writing ENVI binary files. This class will be updated as needed.  
12 -  
13 -What this class CAN currently do:  
14 - *) Write band images to a BSQ file.  
15 - *) Append band images to a BSQ file.  
16 - *) Interpolate and query bands in a float32 BSQ file  
17 -*/  
18 -class EnviFile 7 +#include <sstream>
  8 +#include <vector>
  9 +#include <stdlib.h>
  10 +
  11 +//information from an ENVI header file
  12 +//A good resource can be found here: http://www.exelisvis.com/docs/enviheaderfiles.html
  13 +
  14 +namespace rts{
  15 +
  16 +struct envi
19 { 17 {
20 - EnviHeader header;  
21 - FILE* data;  
22 - std::string mode; 18 + enum dataType {dummy0, int8, int16, int32, float32, float64, complex32, dummy7, dummy8, complex64, dummy10, dummy11, uint16, uint32, int64, uint64};
  19 + enum interleaveType {BIP, BIL, BSQ}; //bip = Z,X,Y; bil = X,Z,Y; bsq = X,Y,Z
  20 + enum endianType {endianLittle, endianBig};
23 21
24 - //a locked file has alread had data written..certain things can't be changed  
25 - // accessor functions deal with these issues  
26 - bool locked; 22 + std::string name;
27 23
28 - void init()  
29 - {  
30 - locked = false;  
31 - data = NULL; 24 + std::string description;
  25 +
  26 + unsigned int samples; //x-axis
  27 + unsigned int lines; //y-axis
  28 + unsigned int bands; //spectral axis
  29 + unsigned int header_offset; //header offset for binary file (in bytes)
  30 + std::string file_type; //should be "ENVI Standard"
  31 +
  32 + envi::dataType data_type; //data representation; common value is 4 (32-bit float)
  33 +
  34 +
  35 + envi::interleaveType interleave;
  36 +
  37 + std::string sensor_type; //not really used
  38 +
  39 + envi::endianType byte_order; //little = least significant bit first (most systems)
  40 +
  41 + double x_start, y_start; //coordinates of the upper-left corner of the image
  42 + std::string wavelength_units; //stored wavelength units
  43 + std::string z_plot_titles[2];
  44 +
  45 + double pixel_size[2]; //pixel size along X and Y
  46 +
  47 + std::vector<std::string> band_names; //name for each band in the image
  48 + std::vector<double> wavelength; //wavelength for each band
  49 +
  50 + envi(){
  51 + name = "";
  52 +
  53 + //specify default values for a new or empty ENVI file
  54 + samples = 0;
  55 + lines = 0;
  56 + bands = 0;
  57 + header_offset = 0;
  58 + data_type = float32;
  59 + interleave = BSQ;
  60 + byte_order = endianLittle;
  61 + x_start = y_start = 0;
  62 + pixel_size[0] = pixel_size[1] = 1;
  63 +
  64 + //strings
  65 + file_type = "ENVI Standard";
  66 + sensor_type = "Unknown";
  67 + wavelength_units = "Unknown";
  68 + z_plot_titles[0] = z_plot_titles[1] = "Unknown";
32 } 69 }
33 70
34 - void readonly()  
35 - {  
36 - if(mode == "r") 71 + std::string trim(std::string line){
  72 + //trims whitespace from the beginning and end of line
  73 + unsigned int start_i, end_i;
  74 + for(start_i=0; start_i < line.length(); start_i++)
  75 + if(line[start_i] != 32)
  76 + {
  77 + break;
  78 + }
  79 +
  80 + for(end_i = line.length()-1; end_i >= start_i; end_i--)
  81 + if(line[end_i] != ' ')
  82 + {
  83 + break;
  84 + }
  85 +
  86 + return line.substr(start_i, end_i - start_i+1);
  87 + }
  88 +
  89 +
  90 + std::string get_token(std::string line){
  91 + //returns a variable name; in this case we look for the '=' sign
  92 + size_t i = line.find_first_of('=');
  93 +
  94 + std::string result;
  95 + if(i != std::string::npos)
  96 + result = trim(line.substr(0, i-1));
  97 +
  98 + return result;
  99 + }
  100 +
  101 + std::string get_data_str(std::string line){
  102 + size_t i = line.find_first_of('=');
  103 +
  104 + std::string result;
  105 + if(i != std::string::npos)
  106 + result = trim(line.substr(i+1));
  107 + else
37 { 108 {
38 - std::cout<<"ENVI Error: changes cannot be made to a read-only file."<<std::endl; 109 + std::cout<<"ENVI Header error - data not found for token: "<<get_token(line)<<std::endl;
39 exit(1); 110 exit(1);
40 } 111 }
  112 + return result;
41 } 113 }
42 114
43 - //this function determines if the current software is capable of the requested change  
44 - bool caps(EnviHeader new_header) 115 + std::string get_brace_str(std::string token, std::string line, std::ifstream &file)
45 { 116 {
46 - readonly(); //if the file is read-only, throw an exception 117 + //this function assembles all of the characters between curly braces
  118 + //this is how strings are defined within an ENVI file
47 119
48 - //we currently only support BSQ  
49 - if(new_header.interleave == Envi::BIP || new_header.interleave == Envi::BIL) 120 + std::string result;
  121 +
  122 + //first, find the starting brace
  123 + size_t i;
  124 + do
  125 + {
  126 + i = line.find_first_of('{');
  127 + if(i != std::string::npos)
  128 + break;
  129 + }while(file);
  130 +
  131 + //if i is still npos, we have reached the end of the file without a brace...something is wrong
  132 + if(i == std::string::npos)
50 { 133 {
51 - std::cout<<"This software only supports BSQ.";  
52 - return false; 134 + std::cout<<"ENVI Header error - string token declared without being defined: "<<token<<std::endl;
  135 + exit(1);
53 } 136 }
  137 + line = line.substr(i+1);
54 138
55 - //if the number of bands has changed  
56 - if(header.bands != new_header.bands) 139 + //copy character data into the result string until we find a closing brace
  140 + while(file)
57 { 141 {
58 - //the new header must be a BSQ file  
59 - if(new_header.interleave != Envi::BSQ) 142 + i = line.find_first_of('}');
  143 +
  144 +
  145 + if(i != std::string::npos)
60 { 146 {
61 - std::cout<<"ENVI Error: can only add bands to a BSQ file."<<std::endl;  
62 - return false; 147 + result += line.substr(0, i);
  148 + break;
63 } 149 }
  150 + else
  151 + result += line;
  152 +
  153 + getline(file, line);
64 } 154 }
65 155
66 - //disallow anything that can't be done when the file is locked  
67 - if(locked) 156 + if(i == std::string::npos)
68 { 157 {
69 - if(header.lines != new_header.lines)  
70 - {  
71 - std::cout<<"ENVI Error: cannot change the number of lines from "<<header.lines<<" to "<<new_header.lines<<" in a locked BSQ file."<<std::endl;  
72 - return false;  
73 - }  
74 - if(header.samples != new_header.samples)  
75 - {  
76 - std::cout<<"ENVI Error: cannot change the number of samples in a locked BSQ file."<<std::endl;  
77 - return false;  
78 - }  
79 - if(header.data_type != new_header.data_type)  
80 - {  
81 - std::cout<<"ENVI Error: cannot change the data type of a locked file."<<std::endl;  
82 - return false;  
83 - }  
84 - if(header.byte_order != new_header.byte_order)  
85 - {  
86 - std::cout<<"ENVI Error: cannot change the byte order of a locked file."<<std::endl;  
87 - return false;  
88 - }  
89 - }  
90 -  
91 - return true; 158 + std::cout<<"ENVI Header error - string token declared without a terminating '}': "<<token<<std::endl;
  159 + exit(1);
  160 + }
92 161
  162 + return trim(result);
93 } 163 }
94 164
95 - EnviHeader load_header(std::string header_file) 165 + std::vector<std::string> get_string_seq(std::string token, std::string sequence)
96 { 166 {
97 - EnviHeader new_header;  
98 - new_header.load(header_file);  
99 - return new_header; 167 + //this function returns a sequence of comma-delimited strings
  168 + std::vector<std::string> result;
  169 +
  170 + std::string entry;
  171 + size_t i;
  172 + do
  173 + {
  174 + i = sequence.find_first_of(',');
  175 + entry = sequence.substr(0, i);
  176 + sequence = sequence.substr(i+1);
  177 + result.push_back(trim(entry));
  178 + }while(i != std::string::npos);
  179 +
  180 + return result;
100 } 181 }
101 182
102 - void set_header(EnviHeader new_header) 183 + std::vector<double> get_double_seq(std::string token, std::string sequence)
103 { 184 {
104 - if(caps(new_header))  
105 - header = new_header;  
106 - else  
107 - exit(1);  
108 - }  
109 -  
110 - bool test_exist(std::string filename)  
111 - {  
112 - //tests for the existance of the specified binary file  
113 - FILE* f;  
114 - long sz = 0;  
115 - f = fopen(filename.c_str(), "rb");  
116 - if(f == NULL)  
117 - {  
118 - //std::cout<<"ENVI Error: error testing file existance."<<std::endl;  
119 - //exit(1);  
120 - return false;  
121 - }  
122 -  
123 - fseek(f, 0, SEEK_END);  
124 - sz = ftell(f);  
125 - fclose(f);  
126 -  
127 - if(sz>0)  
128 - return true;  
129 - else  
130 - return false;  
131 -  
132 - }  
133 -  
134 - void get_surrounding_bands(double wavelength, unsigned int &low, unsigned int &high)  
135 - {  
136 - int i;  
137 - int nBands = header.wavelength.size();  
138 - low = high = 0;  
139 - //std::cout<<"Wavelength to search: "<<wavelength<<" Number of Bands: "<<nBands<<std::endl;  
140 - for(i=0; i<nBands; i++)  
141 - {  
142 - if(header.wavelength[i] < wavelength)  
143 - {  
144 - if(header.wavelength[low] > wavelength)  
145 - low = i;  
146 - if(header.wavelength[i] > header.wavelength[low])  
147 - low = i;  
148 - }  
149 -  
150 - if(header.wavelength[i] > wavelength)  
151 - {  
152 - if(header.wavelength[high] < wavelength)  
153 - high = i;  
154 - if(header.wavelength[i] < header.wavelength[high])  
155 - high = i;  
156 - }  
157 - //std::cout<<"Low: "<<low<<" High: "<<high<<std::endl;  
158 - }  
159 - //exit(1);  
160 - }  
161 -  
162 - void interpolate_band(void* result, void* A, void* B, double a)  
163 - {  
164 - //interpolate between two bands independent of data type  
165 - // CURRENTLY ONLY HANDLES FLOAT  
166 - int X = header.samples;  
167 - int Y = header.lines;  
168 - int N = X * Y;  
169 -  
170 - if(header.data_type != Envi::float32)  
171 - {  
172 - std::cout<<"ENVI Error: this software only handles interpolation of 32-bit floats."<<std::endl;  
173 - exit(1);  
174 - }  
175 -  
176 - float v0, v1;  
177 - for(int n=0; n<N; n++)  
178 - {  
179 - v0 = ((float*)A)[n];  
180 - v1 = ((float*)B)[n];  
181 - float r = v0 * a + v1 * (1.0 - a);  
182 - //((float*)result)[n] = ((float*)A)[n] * a + ((float*)B)[n] * (1.0 - a);  
183 - ((float*)result)[n] = r;  
184 - }  
185 -  
186 - }  
187 -  
188 -public:  
189 -  
190 - EnviFile()  
191 - {  
192 - mode = "w";  
193 - init(); 185 + //this function returns a sequence of comma-delimited strings
  186 + std::vector<double> result;
  187 + std::string entry;
  188 + size_t i;
  189 + do
  190 + {
  191 + i = sequence.find_first_of(',');
  192 + entry = sequence.substr(0, i);
  193 + sequence = sequence.substr(i+1);
  194 + result.push_back(atof(entry.c_str()));
  195 + //std::cout<<entry<<" ";
  196 + }while(i != std::string::npos);
  197 +
  198 + return result;
194 } 199 }
195 200
196 - EnviFile(std::string filename, std::string file_mode = "r") 201 + bool load(std::string filename)
197 { 202 {
198 - init();  
199 - open(filename, filename + ".hdr", file_mode);  
200 - } 203 + //open the header file
  204 + std::ifstream file(filename.c_str());
201 205
202 - void open(std::string file_name, std::string header_name, std::string file_mode = "r")  
203 - {  
204 -  
205 - //load the header file  
206 - // if the file doesn't exist, that is okay unless it is read-only  
207 -  
208 - //if the file is being written, create a new header  
209 - if(file_mode == "w")  
210 - header.name = header_name;  
211 - else if(!header.load(header_name))  
212 - {  
213 - if(file_mode == "r")  
214 - {  
215 - std::cout<<"ENVI Error: header file not found: "<<header_name<<std::endl;  
216 - exit(1);  
217 - }  
218 - //otherwise use the default header and save the name  
219 - header.name = header_name;  
220 - }  
221 -  
222 - mode = file_mode;  
223 -  
224 - //lock the file if it is read-only  
225 - if(mode == "r")  
226 - locked = true;  
227 - else if(mode == "a" || mode == "r+" || mode == "a+")  
228 - {  
229 - //if the file can be edited, lock it if data has already been written  
230 - if(test_exist(file_name))  
231 - locked = true; 206 + if(!file)
  207 + {
  208 + return false;
232 } 209 }
233 -  
234 -  
235 - //open the data file  
236 - std::string tmpmode = mode+"b";  
237 - //std::cout<<"Mode: "<<tmpmode<<std::endl;  
238 - data = fopen(file_name.c_str(), tmpmode.c_str());  
239 - if(data == NULL) 210 +
  211 + //the first line should just be "ENVI"
  212 + std::string line;
  213 + file>>line;
  214 + if(line != "ENVI")
240 { 215 {
241 - std::cout<<"ENVI Error: unable to open binary file: "<<file_name<<std::endl; 216 + std::cout<<"ENVI Header Error: The header doesn't appear to be an ENVI file. The first line should be 'ENVI'."<<std::endl;
242 exit(1); 217 exit(1);
243 } 218 }
244 219
  220 + //for each line in the file, get the token
  221 + std::string token;
245 222
246 - } 223 + //get a line
  224 + getline(file, line);
  225 + while(file)
  226 + {
247 227
248 - void setDescription(std::string desc)  
249 - {  
250 - readonly(); //if the file is read-only, throw an exception  
251 - header.description = desc;  
252 - }  
253 228
254 - void setZPlotTitles(std::string spectrum, std::string value)  
255 - {  
256 - readonly(); //if the file is read-only, throw an exception  
257 - header.z_plot_titles[0] = spectrum;  
258 - header.z_plot_titles[1] = value;  
259 - }  
260 229
261 - void setPixelSize(double sx, double sy)  
262 - {  
263 - readonly(); //if the file is read-only, throw an exception  
264 - header.pixel_size[0] = sx;  
265 - header.pixel_size[1] = sy;  
266 - } 230 + //get the token
  231 + token = get_token(line);
267 232
268 - void setWavelengthUnits(std::string units)  
269 - {  
270 - readonly(); //if the file is read-only, throw an exception  
271 - header.wavelength_units = units;  
272 - } 233 + if(token == "description")
  234 + description = get_brace_str(token, line, file);
  235 + else if(token == "band names")
  236 + {
  237 + std::string string_sequence = get_brace_str(token, line, file);
  238 + band_names = get_string_seq(token, string_sequence);
  239 + }
  240 + else if(token == "wavelength")
  241 + {
  242 + std::string string_sequence = get_brace_str(token, line, file);
  243 + wavelength = get_double_seq(token, string_sequence);
  244 + }
  245 + else if(token == "pixel size")
  246 + {
  247 + std::string string_sequence = get_brace_str(token, line, file);
  248 + std::vector<double> pxsize = get_double_seq(token, string_sequence);
  249 + pixel_size[0] = pxsize[0];
  250 + pixel_size[1] = pxsize[1];
  251 + }
  252 + else if(token == "z plot titles")
  253 + {
  254 + std::string string_sequence = get_brace_str(token, line, file);
  255 + std::vector<std::string> titles = get_string_seq(token, string_sequence);
  256 + z_plot_titles[0] = titles[0];
  257 + z_plot_titles[1] = titles[1];
  258 + }
273 259
274 - void setCoordinates(double x, double y)  
275 - {  
276 - readonly(); //if the file is read-only, throw an exception  
277 - header.x_start = x;  
278 - header.y_start = y; 260 + else if(token == "samples")
  261 + samples = atoi(get_data_str(line).c_str());
  262 + else if(token == "lines")
  263 + lines = atoi(get_data_str(line).c_str());
  264 + else if(token == "bands")
  265 + bands = atoi(get_data_str(line).c_str());
  266 + else if(token == "header offset")
  267 + header_offset = atoi(get_data_str(line).c_str());
  268 + else if(token == "file type")
  269 + file_type = get_data_str(line);
  270 + else if(token == "data type")
  271 + data_type = (dataType)atoi(get_data_str(line).c_str());
  272 + else if(token == "interleave")
  273 + {
  274 + std::string interleave_str = get_data_str(line);
  275 + if(interleave_str == "bip")
  276 + interleave = BIP;
  277 + else if(interleave_str == "bil")
  278 + interleave = BIL;
  279 + else if(interleave_str == "bsq")
  280 + interleave = BSQ;
  281 + }
  282 + else if(token == "sensor type")
  283 + sensor_type = get_data_str(line);
  284 + else if(token == "byte order")
  285 + byte_order = (endianType)atoi(get_data_str(line).c_str());
  286 + else if(token == "x start")
  287 + x_start = atof(get_data_str(line).c_str());
  288 + else if(token == "y start")
  289 + y_start = atof(get_data_str(line).c_str());
  290 + else if(token == "wavelength units")
  291 + wavelength_units = get_data_str(line);
  292 +
  293 + //get the next line
  294 + getline(file, line);
  295 + }
  296 +
  297 + //make sure the number of bands matches the number of wavelengths
  298 + unsigned int wavelengths = wavelength.size();
  299 + if(bands != wavelengths)
  300 + {
  301 + std::cout<<"ENVI Header Error -- Number of wavelengths doesn't match the number of bands. Bands = "<<bands<<", Wavelengths = "<<wavelength.size()<<std::endl;
  302 + exit(1);
  303 + }
  304 +
  305 + //close the file
  306 + file.close();
  307 +
  308 + //set the file name
  309 + name = filename;
  310 +
  311 + return true;
279 } 312 }
280 313
281 - //FUNCTIONS THAT MAY BE DISALLOWED IN A LOCKED FILE  
282 - void setSamples(unsigned int samples) 314 + void save(std::string filename)
283 { 315 {
284 - EnviHeader newHeader = header;  
285 - newHeader.samples = samples;  
286 - set_header(newHeader); 316 + //open a file
  317 + std::ofstream outfile(filename.c_str());
  318 +
  319 + //write the ENVI type identifier
  320 + outfile<<"ENVI"<<std::endl;
  321 +
  322 + //output all of the data
  323 + outfile<<"description = {"<<std::endl;
  324 + outfile<<" "<<description<<"}"<<std::endl;
  325 +
  326 + outfile<<"samples = "<<samples<<std::endl;
  327 + outfile<<"lines = "<<lines<<std::endl;
  328 + outfile<<"bands = "<<bands<<std::endl;
  329 + outfile<<"header offset = "<<header_offset<<std::endl;
  330 + outfile<<"file type = "<<file_type<<std::endl;
  331 + outfile<<"data type = "<<data_type<<std::endl;
  332 + outfile<<"interleave = ";
  333 + if(interleave == BIP)
  334 + outfile<<"bip";
  335 + if(interleave == BIL)
  336 + outfile<<"bil";
  337 + if(interleave == BSQ)
  338 + outfile<<"bsq";
  339 + outfile<<std::endl;
  340 + outfile<<"sensor type = "<<sensor_type<<std::endl;
  341 + outfile<<"byte order = "<<byte_order<<std::endl;
  342 + outfile<<"x start = "<<x_start<<std::endl;
  343 + outfile<<"y start = "<<y_start<<std::endl;
  344 + outfile<<"wavelength units = "<<wavelength_units<<std::endl;
  345 + outfile<<"z plot titles = {";
  346 + outfile<<z_plot_titles[0]<<", "<<z_plot_titles[1]<<"}"<<std::endl;
  347 + outfile<<"pixel size = {"<<pixel_size[0]<<", "<<pixel_size[1]<<", units=Meters}"<<std::endl;
  348 + if(band_names.size() > 0)
  349 + {
  350 + outfile<<"band names = {"<<std::endl;
  351 + for(unsigned int i=0; i<band_names.size(); i++)
  352 + {
  353 + outfile<<band_names[i];
  354 + if(i < band_names.size() - 1)
  355 + outfile<<", ";
  356 + }
  357 + outfile<<"}"<<std::endl;
  358 + }
  359 + outfile<<"wavelength = {"<<std::endl;
  360 + for(unsigned int i=0; i<wavelength.size()-1; i++)
  361 + outfile<<wavelength[i]<<", ";
  362 + outfile<<wavelength.back()<<"}"<<std::endl;
  363 +
  364 + outfile.close();
287 } 365 }
288 366
289 - void setLines(unsigned int lines)  
290 - {  
291 - EnviHeader newHeader = header;  
292 - newHeader.lines = lines;  
293 - set_header(newHeader);  
294 - }  
295 -  
296 - unsigned int lines() {return header.lines;}  
297 - unsigned int samples() {return header.samples;}  
298 - unsigned int bands() {return header.bands;}  
299 - double wavelength(unsigned int b) {return header.wavelength[b];}  
300 -  
301 - void setBands(unsigned int bands) 367 + void save()
302 { 368 {
303 - EnviHeader newHeader = header;  
304 - newHeader.bands = bands;  
305 - set_header(newHeader);  
306 - }  
307 -  
308 - unsigned int getElementSize()  
309 - {  
310 - //return the size of each element in bytes  
311 - return header.valsize();  
312 - }  
313 - unsigned int getBandSize()  
314 - {  
315 - //returns the size of a band in bytes  
316 - return header.valsize() * header.lines * header.samples;  
317 - }  
318 -  
319 - Envi::dataType getDataType()  
320 - {  
321 - return header.data_type;  
322 - }  
323 -  
324 - //DATA MANIPULATION  
325 - void addBand(void* band, unsigned int samples, unsigned int lines, double wavelength, std::string band_name ="")  
326 - {  
327 - //add a band to the file  
328 -  
329 - EnviHeader newHeader = header;  
330 - newHeader.bands++;  
331 - newHeader.samples = samples;  
332 - newHeader.lines = lines;  
333 - newHeader.wavelength.push_back(wavelength);  
334 - if(band_name != "")  
335 - newHeader.band_names.push_back(band_name);  
336 - set_header(newHeader);  
337 -  
338 - //copy the data to the file  
339 - fwrite(band, header.valsize(), samples * lines, data);  
340 -  
341 - //since data was written, the file must be locked  
342 - locked = true;  
343 - }  
344 -  
345 - //DATA RETRIEVAL  
346 - void getBand(void* ptr, unsigned int n)  
347 - {  
348 - //reads the n'th band and writes it to the given pointer  
349 - // memory has been assumed to be allocated  
350 -  
351 - if(n > header.wavelength.size())  
352 - {  
353 - std::cout<<"ENVI Error: Invalid band number."<<std::endl;  
354 - return;  
355 - }  
356 -  
357 -  
358 - if(header.interleave == Envi::BSQ)  
359 - {  
360 -  
361 - //compute the position of the desired band (relative to the beginning of the file)  
362 - int bandpos = header.header_offset + getBandSize() * n;  
363 -  
364 - //seek to that position  
365 - int seek_result = fseek(data, bandpos, SEEK_SET);  
366 - if(seek_result)  
367 - {  
368 - std::cout<<"ENVI Error: Error seeking through data file."<<std::endl;  
369 - return;  
370 - }  
371 -  
372 - //read the band data from the file  
373 - size_t n_read = fread(ptr, getElementSize(), header.samples * header.lines, data);  
374 - if(n_read != header.samples * header.lines)  
375 - {  
376 - std::cout<<"ENVI Error -- Error reading band data: "<<n_read<<"/"<<samples() * lines()<<" pixels read"<<std::endl;  
377 - exit(1);  
378 - }  
379 -  
380 - return;  
381 - }  
382 - else  
383 - {  
384 - std::cout<<"ENVI Error: Only BSQ operations are currently supported."<<std::endl;  
385 - return;  
386 - }  
387 - }  
388 -  
389 - void getWavelength(void* band, double wavelength)  
390 - {  
391 - //this function retrieves a band via interpolation of wavelength values  
392 -  
393 - //get the low and high band numbers  
394 - unsigned int low, high;  
395 - get_surrounding_bands(wavelength, low, high);  
396 - //std::cout<<"High: "<<high<<" Low: "<<low<<std::endl;  
397 -  
398 - //calculate the position between the two bands  
399 - double a;  
400 - if(low == high)  
401 - a = 1.0;  
402 - else  
403 - a = (wavelength - header.wavelength[low]) / (header.wavelength[high] - header.wavelength[low]);  
404 -  
405 - //read both bands  
406 - void* A;  
407 - A = malloc( getBandSize() );  
408 - getBand(A, low);  
409 -  
410 - void* B;  
411 - B = malloc( getBandSize() );  
412 - getBand(B, high);  
413 -  
414 - //interpolate between the bands  
415 - interpolate_band(band, A, B, a);  
416 -  
417 - //free the surrounding bands  
418 - free(A);  
419 - free(B);  
420 - }  
421 -  
422 - //close file  
423 - void close()  
424 - {  
425 - //std::cout<<"ENVI File Mode: "<<mode<<std::endl;  
426 -  
427 - //close the data stream  
428 - fclose(data);  
429 -  
430 - //close the header  
431 - if(mode != "r")  
432 - header.save(); 369 + //std::cout<<"ENVI Header Name: "<<name<<std::endl;
  370 + save(name);
433 } 371 }
434 372
435 -}; //end EnviFile  
436 - 373 + //returns the size of a single value (in bytes)
  374 + unsigned int valsize()
  375 + {
  376 + switch(data_type)
  377 + {
  378 + case int8: //1 = 8-bit byte
  379 + return 1;
  380 + case int16: //16-bit signed integer
  381 + case uint16: //16-bit unsigned integer
  382 + return 2;
  383 + case int32: //32-bit signed long integer
  384 + case float32: //32-bit floating point
  385 + case uint32: //32-bit unsigned long integer
  386 + return 4;
  387 + case float64: //64-bit double-precision floating point
  388 + case complex32: //32-bit complex value
  389 + case int64: //64-bit signed long integer
  390 + case uint64: //64-bit unsigned long integer
  391 + return 8;
  392 + case complex64: //64-bit complex value
  393 + return 16;
  394 + default:
  395 + return 0;
  396 + }
437 397
438 -#endif 398 + }
  399 +}; //end EnviHeader
  400 +}
  401 +#endif
math/complexfield.cuh
@@ -55,7 +55,7 @@ public: @@ -55,7 +55,7 @@ public:
55 int index; //result of the max operation 55 int index; //result of the max operation
56 rts::complex<T> result; 56 rts::complex<T> result;
57 57
58 - if(sizeof(T) == 4) 58 + if(sizeof(T) == 8)
59 stat = cublasIcamax(handle, L, (const cuComplex*)X[n], 1, &index); 59 stat = cublasIcamax(handle, L, (const cuComplex*)X[n], 1, &index);
60 else 60 else
61 stat = cublasIzamax(handle, L, (const cuDoubleComplex*)X[n], 1, &index); 61 stat = cublasIzamax(handle, L, (const cuDoubleComplex*)X[n], 1, &index);
@@ -114,7 +114,7 @@ public: @@ -114,7 +114,7 @@ public:
114 114
115 void toImage(std::string filename, attribute type = magnitude, unsigned int n=0){ 115 void toImage(std::string filename, attribute type = magnitude, unsigned int n=0){
116 116
117 - realfield<T, 1, true> rf(R[0], R[1]); 117 + field<T, 1> rf(R[0], R[1]);
118 118
119 //get cuda parameters 119 //get cuda parameters
120 dim3 blocks, grids; 120 dim3 blocks, grids;
@@ -122,7 +122,7 @@ public: @@ -122,7 +122,7 @@ public:
122 122
123 if(type == magnitude){ 123 if(type == magnitude){
124 gpu_complexfield_mag <<<grids, blocks>>> (rf.ptr(), X[n], R[0], R[1]); 124 gpu_complexfield_mag <<<grids, blocks>>> (rf.ptr(), X[n], R[0], R[1]);
125 - rf.toImages(filename, 0); 125 + rf.toImage(filename, n, true);
126 } 126 }
127 127
128 } 128 }
@@ -134,4 +134,4 @@ public: @@ -134,4 +134,4 @@ public:
134 } //end namespace rts 134 } //end namespace rts
135 135
136 136
137 -#endif  
138 \ No newline at end of file 137 \ No newline at end of file
  138 +#endif
@@ -5,10 +5,14 @@ @@ -5,10 +5,14 @@
5 #include <string> 5 #include <string>
6 #include <sstream> 6 #include <sstream>
7 7
  8 +#include "cublas_v2.h"
  9 +#include <cuda_runtime.h>
  10 +
8 #include "../math/rect.h" 11 #include "../math/rect.h"
9 #include "../cuda/threads.h" 12 #include "../cuda/threads.h"
10 #include "../cuda/error.h" 13 #include "../cuda/error.h"
11 #include "../cuda/devices.h" 14 #include "../cuda/devices.h"
  15 +#include "../visualization/colormap.h"
12 16
13 17
14 namespace rts{ 18 namespace rts{
@@ -86,6 +90,41 @@ protected: @@ -86,6 +90,41 @@ protected:
86 grids = dim3((R[0] + SQRT_BLOCK -1)/SQRT_BLOCK, (R[1] + SQRT_BLOCK - 1)/SQRT_BLOCK); 90 grids = dim3((R[0] + SQRT_BLOCK -1)/SQRT_BLOCK, (R[1] + SQRT_BLOCK - 1)/SQRT_BLOCK);
87 } 91 }
88 92
  93 + //find the maximum value of component n
  94 + T find_max(unsigned int n){
  95 + cublasStatus_t stat;
  96 + cublasHandle_t handle;
  97 +
  98 + //create a CUBLAS handle
  99 + stat = cublasCreate(&handle);
  100 + if(stat != CUBLAS_STATUS_SUCCESS){
  101 + std::cout<<"CUBLAS Error: initialization failed"<<std::endl;
  102 + exit(1);
  103 + }
  104 +
  105 + int L = R[0] * R[1]; //compute the number of discrete points in a slice
  106 + int index; //result of the max operation
  107 + T result;
  108 +
  109 + if(sizeof(T) == 4)
  110 + stat = cublasIsamax(handle, L, (const float*)X[n], 1, &index);
  111 + else
  112 + stat = cublasIdamax(handle, L, (const double*)X[n], 1, &index);
  113 +
  114 + index -= 1; //adjust for 1-based indexing
  115 +
  116 + //if there was a GPU error, terminate
  117 + if(stat != CUBLAS_STATUS_SUCCESS){
  118 + std::cout<<"CUBLAS Error: failure finding maximum value."<<std::endl;
  119 + exit(1);
  120 + }
  121 +
  122 + //retrieve the maximum value for this slice and store it in the maxVal array
  123 + std::cout<<X[n]<<std::endl;
  124 + HANDLE_ERROR(cudaMemcpy(&result, X[n] + index, sizeof(T), cudaMemcpyDeviceToHost));
  125 + return result;
  126 + }
  127 +
89 public: 128 public:
90 129
91 //returns a list of file names given an input string with wild cards 130 //returns a list of file names given an input string with wild cards
@@ -286,10 +325,20 @@ public: @@ -286,10 +325,20 @@ public:
286 rts::gpu_field_crop <<<dimGrid, dimBlock>>> (result.X[n], X[n], R[0], R[1], width, height); 325 rts::gpu_field_crop <<<dimGrid, dimBlock>>> (result.X[n], X[n], R[0], R[1], width, height);
287 326
288 return result; 327 return result;
  328 + }
  329 +
  330 + //save an image representing component n
  331 + void toImage(std::string filename, unsigned int n = 0,
  332 + bool positive = false, rts::colormapType cmap = rts::cmBrewer){
  333 + T max_val = find_max(n); //find the maximum value
289 334
  335 + if(positive) //if the field is positive, use the range [0 max_val]
  336 + rts::gpu2image<T>(X[n], filename, R[0], R[1], 0, max_val, cmap);
  337 + else
  338 + rts::gpu2image<T>(X[n], filename, R[0], R[1], -max_val, max_val, cmap);
290 } 339 }
291 340
292 }; 341 };
293 342
294 } //end namespace rts 343 } //end namespace rts
295 -#endif  
296 \ No newline at end of file 344 \ No newline at end of file
  345 +#endif
@@ -2,7 +2,6 @@ @@ -2,7 +2,6 @@
2 #define RTS_FUNCTION_H 2 #define RTS_FUNCTION_H
3 3
4 #include <string> 4 #include <string>
5 -#include <cmath>  
6 5
7 namespace rts{ 6 namespace rts{
8 7
@@ -59,7 +58,7 @@ protected: @@ -59,7 +58,7 @@ protected:
59 58
60 public: 59 public:
61 function(){ 60 function(){
62 - range[0] = range[1] = NAN; 61 + range[0] = range[1] = 0;
63 bounding[0] = bounding[1] = 0; 62 bounding[0] = bounding[1] = 0;
64 } 63 }
65 64
@@ -182,7 +181,8 @@ public: @@ -182,7 +181,8 @@ public:
182 function<Tx, Ty> & operator= (const Ty & rhs){ 181 function<Tx, Ty> & operator= (const Ty & rhs){
183 X.clear(); 182 X.clear();
184 Y.clear(); 183 Y.clear();
185 - if(rhs != 0) //if the RHS is zero, just clear, otherwise add one value of RHS 184 + bounding[0] = bounding[1] = rhs; //set the boundary values to rhs
  185 + if(rhs != 0) //if the RHS is zero, just clear, otherwise add one value of RHS
186 insert(0, rhs); 186 insert(0, rhs);
187 187
188 return *this; 188 return *this;
optics/mirst-1d.cuh
1 #include "../optics/material.h" 1 #include "../optics/material.h"
2 #include "../math/complexfield.cuh" 2 #include "../math/complexfield.cuh"
3 #include "../math/constants.h" 3 #include "../math/constants.h"
  4 +#include "../envi/bil.h"
4 5
5 #include "cufft.h" 6 #include "cufft.h"
6 7
@@ -163,6 +164,8 @@ private: @@ -163,6 +164,8 @@ private:
163 164
164 T NA[2]; //numerical aperature (central obscuration and outer diameter) 165 T NA[2]; //numerical aperature (central obscuration and outer diameter)
165 166
  167 + function<T, T> source_profile; //profile (spectrum) of the source (expressed in inverse centimeters)
  168 +
166 complexfield<T, 1> scratch; //scratch GPU memory used to build samples, transforms, etc. 169 complexfield<T, 1> scratch; //scratch GPU memory used to build samples, transforms, etc.
167 170
168 void fft(int direction = CUFFT_FORWARD){ 171 void fft(int direction = CUFFT_FORWARD){
@@ -251,7 +254,7 @@ private: @@ -251,7 +254,7 @@ private:
251 HANDLE_ERROR(cudaMemcpy( gpuRi + inu, &ri, sizeof(complex<T>), cudaMemcpyHostToDevice )); 254 HANDLE_ERROR(cudaMemcpy( gpuRi + inu, &ri, sizeof(complex<T>), cudaMemcpyHostToDevice ));
252 255
253 //save the source profile to the GPU 256 //save the source profile to the GPU
254 - source = 1; 257 + source = source_profile(10000 / lambdas[inu]);
255 HANDLE_ERROR(cudaMemcpy( gpuSrc + inu, &source, sizeof(T), cudaMemcpyHostToDevice )); 258 HANDLE_ERROR(cudaMemcpy( gpuSrc + inu, &source, sizeof(T), cudaMemcpyHostToDevice ));
256 259
257 } 260 }
@@ -311,6 +314,11 @@ private: @@ -311,6 +314,11 @@ private:
311 scratch = scratch.crop(Z, S); 314 scratch = scratch.crop(Z, S);
312 } 315 }
313 316
  317 + //save the scratch field as a binary file
  318 + void to_binary(std::string filename){
  319 +
  320 + }
  321 +
314 322
315 public: 323 public:
316 324
@@ -322,6 +330,7 @@ public: @@ -322,6 +330,7 @@ public:
322 NA[0] = 0; 330 NA[0] = 0;
323 NA[1] = 0.8; 331 NA[1] = 0.8;
324 S = 0; 332 S = 0;
  333 + source_profile = 1;
325 } 334 }
326 335
327 //add a layer, thickness = microns 336 //add a layer, thickness = microns
@@ -334,6 +343,11 @@ public: @@ -334,6 +343,11 @@ public:
334 add_layer(material<T>(filename), thickness); 343 add_layer(material<T>(filename), thickness);
335 } 344 }
336 345
  346 + //adds a profile spectrum for the light source
  347 + void set_source(std::string filename){
  348 + source_profile.load(filename);
  349 + }
  350 +
337 //adds a block of wavenumbers (cm^-1) to the simulation parameters 351 //adds a block of wavenumbers (cm^-1) to the simulation parameters
338 void add_wavenumbers(unsigned int start, unsigned int stop, unsigned int step){ 352 void add_wavenumbers(unsigned int start, unsigned int stop, unsigned int step){
339 unsigned int nu = start; 353 unsigned int nu = start;
@@ -368,6 +382,10 @@ public: @@ -368,6 +382,10 @@ public:
368 na(0, out); 382 na(0, out);
369 } 383 }
370 384
  385 + rts::function<T, T> get_source(){
  386 + return source_profile;
  387 + }
  388 +
371 void save_sample(std::string filename){ 389 void save_sample(std::string filename){
372 //create a sample and save the magnitude as an image 390 //create a sample and save the magnitude as an image
373 build_sample(); 391 build_sample();
@@ -375,7 +393,7 @@ public: @@ -375,7 +393,7 @@ public:
375 scratch.toImage(filename, rts::complexfield<T, 1>::magnitude); 393 scratch.toImage(filename, rts::complexfield<T, 1>::magnitude);
376 } 394 }
377 395
378 - void save_mirst(std::string filename){ 396 + void save_mirst(std::string filename, bool binary = true){
379 //apply the MIRST filter to a sample and save the image 397 //apply the MIRST filter to a sample and save the image
380 398
381 //build the sample in the Fourier domain 399 //build the sample in the Fourier domain
@@ -390,7 +408,10 @@ public: @@ -390,7 +408,10 @@ public:
390 crop(); 408 crop();
391 409
392 //save the image 410 //save the image
393 - scratch.toImage(filename, rts::complexfield<T, 1>::magnitude); 411 + if(binary)
  412 + to_binary(filename);
  413 + else
  414 + scratch.toImage(filename, rts::complexfield<T, 1>::magnitude);
394 } 415 }
395 416
396 417
@@ -411,6 +432,9 @@ public: @@ -411,6 +432,9 @@ public:
411 for(unsigned int l=0; l<layers.size(); l++) 432 for(unsigned int l=0; l<layers.size(); l++)
412 ss<<"layer "<<l<<": "<<layers[l]<<" um"<<"---------"<<std::endl<<matlist[l].str()<<std::endl; 433 ss<<"layer "<<l<<": "<<layers[l]<<" um"<<"---------"<<std::endl<<matlist[l].str()<<std::endl;
413 434
  435 + ss<<"source profile-----------"<<std::endl;
  436 + ss<<get_source().str()<<std::endl;
  437 +
414 return ss.str(); 438 return ss.str();
415 439
416 440