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
... ...
envi/envi.h
1   -#ifndef RTS_ENVI_H
2   -#define RTS_ENVI_H
  1 +#ifndef ENVI_HEADER_H
  2 +#define ENVI_HEADER_H
3 3  
4 4 #include <string>
5   -#include <iostream>
  5 +#include <iostream>
6 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 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 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 55 int index; //result of the max operation
56 56 rts::complex<T> result;
57 57  
58   - if(sizeof(T) == 4)
  58 + if(sizeof(T) == 8)
59 59 stat = cublasIcamax(handle, L, (const cuComplex*)X[n], 1, &index);
60 60 else
61 61 stat = cublasIzamax(handle, L, (const cuDoubleComplex*)X[n], 1, &index);
... ... @@ -114,7 +114,7 @@ public:
114 114  
115 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 119 //get cuda parameters
120 120 dim3 blocks, grids;
... ... @@ -122,7 +122,7 @@ public:
122 122  
123 123 if(type == magnitude){
124 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 134 } //end namespace rts
135 135  
136 136  
137   -#endif
138 137 \ No newline at end of file
  138 +#endif
... ...
math/field.cuh
... ... @@ -5,10 +5,14 @@
5 5 #include <string>
6 6 #include <sstream>
7 7  
  8 +#include "cublas_v2.h"
  9 +#include <cuda_runtime.h>
  10 +
8 11 #include "../math/rect.h"
9 12 #include "../cuda/threads.h"
10 13 #include "../cuda/error.h"
11 14 #include "../cuda/devices.h"
  15 +#include "../visualization/colormap.h"
12 16  
13 17  
14 18 namespace rts{
... ... @@ -86,6 +90,41 @@ protected:
86 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 128 public:
90 129  
91 130 //returns a list of file names given an input string with wild cards
... ... @@ -286,10 +325,20 @@ public:
286 325 rts::gpu_field_crop <<<dimGrid, dimBlock>>> (result.X[n], X[n], R[0], R[1], width, height);
287 326  
288 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 343 } //end namespace rts
295   -#endif
296 344 \ No newline at end of file
  345 +#endif
... ...
math/function.h
... ... @@ -2,7 +2,6 @@
2 2 #define RTS_FUNCTION_H
3 3  
4 4 #include <string>
5   -#include <cmath>
6 5  
7 6 namespace rts{
8 7  
... ... @@ -59,7 +58,7 @@ protected:
59 58  
60 59 public:
61 60 function(){
62   - range[0] = range[1] = NAN;
  61 + range[0] = range[1] = 0;
63 62 bounding[0] = bounding[1] = 0;
64 63 }
65 64  
... ... @@ -182,7 +181,8 @@ public:
182 181 function<Tx, Ty> & operator= (const Ty & rhs){
183 182 X.clear();
184 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 186 insert(0, rhs);
187 187  
188 188 return *this;
... ...
optics/mirst-1d.cuh
1 1 #include "../optics/material.h"
2 2 #include "../math/complexfield.cuh"
3 3 #include "../math/constants.h"
  4 +#include "../envi/bil.h"
4 5  
5 6 #include "cufft.h"
6 7  
... ... @@ -163,6 +164,8 @@ private:
163 164  
164 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 169 complexfield<T, 1> scratch; //scratch GPU memory used to build samples, transforms, etc.
167 170  
168 171 void fft(int direction = CUFFT_FORWARD){
... ... @@ -251,7 +254,7 @@ private:
251 254 HANDLE_ERROR(cudaMemcpy( gpuRi + inu, &ri, sizeof(complex<T>), cudaMemcpyHostToDevice ));
252 255  
253 256 //save the source profile to the GPU
254   - source = 1;
  257 + source = source_profile(10000 / lambdas[inu]);
255 258 HANDLE_ERROR(cudaMemcpy( gpuSrc + inu, &source, sizeof(T), cudaMemcpyHostToDevice ));
256 259  
257 260 }
... ... @@ -311,6 +314,11 @@ private:
311 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 323 public:
316 324  
... ... @@ -322,6 +330,7 @@ public:
322 330 NA[0] = 0;
323 331 NA[1] = 0.8;
324 332 S = 0;
  333 + source_profile = 1;
325 334 }
326 335  
327 336 //add a layer, thickness = microns
... ... @@ -334,6 +343,11 @@ public:
334 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 351 //adds a block of wavenumbers (cm^-1) to the simulation parameters
338 352 void add_wavenumbers(unsigned int start, unsigned int stop, unsigned int step){
339 353 unsigned int nu = start;
... ... @@ -368,6 +382,10 @@ public:
368 382 na(0, out);
369 383 }
370 384  
  385 + rts::function<T, T> get_source(){
  386 + return source_profile;
  387 + }
  388 +
371 389 void save_sample(std::string filename){
372 390 //create a sample and save the magnitude as an image
373 391 build_sample();
... ... @@ -375,7 +393,7 @@ public:
375 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 397 //apply the MIRST filter to a sample and save the image
380 398  
381 399 //build the sample in the Fourier domain
... ... @@ -390,7 +408,10 @@ public:
390 408 crop();
391 409  
392 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 432 for(unsigned int l=0; l<layers.size(); l++)
412 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 438 return ss.str();
415 439  
416 440  
... ...