From 180d7f3ae17a1a239a774f2106a3d79e7392d15f Mon Sep 17 00:00:00 2001 From: David Mayerich Date: Thu, 14 Aug 2014 12:15:08 -0500 Subject: [PATCH] added binary file framework --- envi/bil.h | 27 +++++++++++++++++++++++++++ envi/binary.h | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ envi/envi.h | 729 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- math/complexfield.cuh | 8 ++++---- math/field.cuh | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- math/function.h | 6 +++--- optics/mirst-1d.cuh | 30 +++++++++++++++++++++++++++--- 7 files changed, 550 insertions(+), 394 deletions(-) create mode 100644 envi/bil.h create mode 100644 envi/binary.h diff --git a/envi/bil.h b/envi/bil.h new file mode 100644 index 0000000..f813944 --- /dev/null +++ b/envi/bil.h @@ -0,0 +1,27 @@ +#ifndef RTS_BIL_H +#define RTS_BIL_H + +#include "../envi/envi.h" + +namespace rts{ + +//This class specifies a BIL binary file that can be streamed to and from storage media +template< typename T > +class bil{ + +protected: + + rts::envi header; + + +public: + + bil(){ + init(); + } + +}; + +} + +#endif diff --git a/envi/binary.h b/envi/binary.h new file mode 100644 index 0000000..9fea3a1 --- /dev/null +++ b/envi/binary.h @@ -0,0 +1,93 @@ +#ifndef RTS_BINARY_H +#define RTS_BINARY_H + +#include "../envi/envi.h" + +#include +#include + +namespace rts{ + +//This class contains a bunch of functions useful for multidimensional binary file access +template< typename T, unsigned int D = 3 > +class binary{ + +protected: + + std::fstream file; //file stream used for reading and writing + std::string name; //file name + + unsigned int R[D]; //resolution + unsigned int header; //header size (in bytes) + + + //basic initialization + void init(){ + memset(R, 0, sizeof(unsigned int) * D); //initialize the resolution to zero + header = 0; //initialize the header size to zero + } + + //returns the file size + unsigned int get_file_size(){ + + struct stat results; + if(stat(name.c_str(), &results) == 0) + return results.st_size; + else return 0; + } + + bool test_file_size(){ + unsigned int sum = header; //initialize the sum (in bytes) to the header size + for(unsigned int i = 0; i r, unsigned int h = 0){ + if(!open_file(filename)) return false; + + for(unsigned int i = 0; i < D; i++) + R[i] = r[i]; + + header = h; + + return test_file_size(); + } + + bool open(std::string filename, unsigned int X, unsigned int h = 0){ + return open(filename, vec(X), h); + } + + bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int h = 0){ + return open(filename, vec(X, Y), h); + + + } + + bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int Z, unsigned int h = 0){ + return open(filename, vec(X, Y, Z), h); + } + +}; + +} + +#endif diff --git a/envi/envi.h b/envi/envi.h index df82b8f..aa545e2 100644 --- a/envi/envi.h +++ b/envi/envi.h @@ -1,438 +1,401 @@ -#ifndef RTS_ENVI_H -#define RTS_ENVI_H +#ifndef ENVI_HEADER_H +#define ENVI_HEADER_H #include -#include +#include #include -#include - -#include "rts/envi/envi_header.h" - -/* This is a class for reading and writing ENVI binary files. This class will be updated as needed. - -What this class CAN currently do: - *) Write band images to a BSQ file. - *) Append band images to a BSQ file. - *) Interpolate and query bands in a float32 BSQ file -*/ -class EnviFile +#include +#include +#include + +//information from an ENVI header file +//A good resource can be found here: http://www.exelisvis.com/docs/enviheaderfiles.html + +namespace rts{ + +struct envi { - EnviHeader header; - FILE* data; - std::string mode; + enum dataType {dummy0, int8, int16, int32, float32, float64, complex32, dummy7, dummy8, complex64, dummy10, dummy11, uint16, uint32, int64, uint64}; + enum interleaveType {BIP, BIL, BSQ}; //bip = Z,X,Y; bil = X,Z,Y; bsq = X,Y,Z + enum endianType {endianLittle, endianBig}; - //a locked file has alread had data written..certain things can't be changed - // accessor functions deal with these issues - bool locked; + std::string name; - void init() - { - locked = false; - data = NULL; + std::string description; + + unsigned int samples; //x-axis + unsigned int lines; //y-axis + unsigned int bands; //spectral axis + unsigned int header_offset; //header offset for binary file (in bytes) + std::string file_type; //should be "ENVI Standard" + + envi::dataType data_type; //data representation; common value is 4 (32-bit float) + + + envi::interleaveType interleave; + + std::string sensor_type; //not really used + + envi::endianType byte_order; //little = least significant bit first (most systems) + + double x_start, y_start; //coordinates of the upper-left corner of the image + std::string wavelength_units; //stored wavelength units + std::string z_plot_titles[2]; + + double pixel_size[2]; //pixel size along X and Y + + std::vector band_names; //name for each band in the image + std::vector wavelength; //wavelength for each band + + envi(){ + name = ""; + + //specify default values for a new or empty ENVI file + samples = 0; + lines = 0; + bands = 0; + header_offset = 0; + data_type = float32; + interleave = BSQ; + byte_order = endianLittle; + x_start = y_start = 0; + pixel_size[0] = pixel_size[1] = 1; + + //strings + file_type = "ENVI Standard"; + sensor_type = "Unknown"; + wavelength_units = "Unknown"; + z_plot_titles[0] = z_plot_titles[1] = "Unknown"; } - void readonly() - { - if(mode == "r") + std::string trim(std::string line){ + //trims whitespace from the beginning and end of line + unsigned int start_i, end_i; + for(start_i=0; start_i < line.length(); start_i++) + if(line[start_i] != 32) + { + break; + } + + for(end_i = line.length()-1; end_i >= start_i; end_i--) + if(line[end_i] != ' ') + { + break; + } + + return line.substr(start_i, end_i - start_i+1); + } + + + std::string get_token(std::string line){ + //returns a variable name; in this case we look for the '=' sign + size_t i = line.find_first_of('='); + + std::string result; + if(i != std::string::npos) + result = trim(line.substr(0, i-1)); + + return result; + } + + std::string get_data_str(std::string line){ + size_t i = line.find_first_of('='); + + std::string result; + if(i != std::string::npos) + result = trim(line.substr(i+1)); + else { - std::cout<<"ENVI Error: changes cannot be made to a read-only file."< get_string_seq(std::string token, std::string sequence) { - EnviHeader new_header; - new_header.load(header_file); - return new_header; + //this function returns a sequence of comma-delimited strings + std::vector result; + + std::string entry; + size_t i; + do + { + i = sequence.find_first_of(','); + entry = sequence.substr(0, i); + sequence = sequence.substr(i+1); + result.push_back(trim(entry)); + }while(i != std::string::npos); + + return result; } - void set_header(EnviHeader new_header) + std::vector get_double_seq(std::string token, std::string sequence) { - if(caps(new_header)) - header = new_header; - else - exit(1); - } - - bool test_exist(std::string filename) - { - //tests for the existance of the specified binary file - FILE* f; - long sz = 0; - f = fopen(filename.c_str(), "rb"); - if(f == NULL) - { - //std::cout<<"ENVI Error: error testing file existance."<0) - return true; - else - return false; - - } - - void get_surrounding_bands(double wavelength, unsigned int &low, unsigned int &high) - { - int i; - int nBands = header.wavelength.size(); - low = high = 0; - //std::cout<<"Wavelength to search: "< wavelength) - low = i; - if(header.wavelength[i] > header.wavelength[low]) - low = i; - } - - if(header.wavelength[i] > wavelength) - { - if(header.wavelength[high] < wavelength) - high = i; - if(header.wavelength[i] < header.wavelength[high]) - high = i; - } - //std::cout<<"Low: "< result; + std::string entry; + size_t i; + do + { + i = sequence.find_first_of(','); + entry = sequence.substr(0, i); + sequence = sequence.substr(i+1); + result.push_back(atof(entry.c_str())); + //std::cout<>line; + if(line != "ENVI") { - std::cout<<"ENVI Error: unable to open binary file: "< pxsize = get_double_seq(token, string_sequence); + pixel_size[0] = pxsize[0]; + pixel_size[1] = pxsize[1]; + } + else if(token == "z plot titles") + { + std::string string_sequence = get_brace_str(token, line, file); + std::vector titles = get_string_seq(token, string_sequence); + z_plot_titles[0] = titles[0]; + z_plot_titles[1] = titles[1]; + } - void setCoordinates(double x, double y) - { - readonly(); //if the file is read-only, throw an exception - header.x_start = x; - header.y_start = y; + else if(token == "samples") + samples = atoi(get_data_str(line).c_str()); + else if(token == "lines") + lines = atoi(get_data_str(line).c_str()); + else if(token == "bands") + bands = atoi(get_data_str(line).c_str()); + else if(token == "header offset") + header_offset = atoi(get_data_str(line).c_str()); + else if(token == "file type") + file_type = get_data_str(line); + else if(token == "data type") + data_type = (dataType)atoi(get_data_str(line).c_str()); + else if(token == "interleave") + { + std::string interleave_str = get_data_str(line); + if(interleave_str == "bip") + interleave = BIP; + else if(interleave_str == "bil") + interleave = BIL; + else if(interleave_str == "bsq") + interleave = BSQ; + } + else if(token == "sensor type") + sensor_type = get_data_str(line); + else if(token == "byte order") + byte_order = (endianType)atoi(get_data_str(line).c_str()); + else if(token == "x start") + x_start = atof(get_data_str(line).c_str()); + else if(token == "y start") + y_start = atof(get_data_str(line).c_str()); + else if(token == "wavelength units") + wavelength_units = get_data_str(line); + + //get the next line + getline(file, line); + } + + //make sure the number of bands matches the number of wavelengths + unsigned int wavelengths = wavelength.size(); + if(bands != wavelengths) + { + std::cout<<"ENVI Header Error -- Number of wavelengths doesn't match the number of bands. Bands = "< 0) + { + outfile<<"band names = {"< header.wavelength.size()) - { - std::cout<<"ENVI Error: Invalid band number."< result; - if(sizeof(T) == 4) + if(sizeof(T) == 8) stat = cublasIcamax(handle, L, (const cuComplex*)X[n], 1, &index); else stat = cublasIzamax(handle, L, (const cuDoubleComplex*)X[n], 1, &index); @@ -114,7 +114,7 @@ public: void toImage(std::string filename, attribute type = magnitude, unsigned int n=0){ - realfield rf(R[0], R[1]); + field rf(R[0], R[1]); //get cuda parameters dim3 blocks, grids; @@ -122,7 +122,7 @@ public: if(type == magnitude){ gpu_complexfield_mag <<>> (rf.ptr(), X[n], R[0], R[1]); - rf.toImages(filename, 0); + rf.toImage(filename, n, true); } } @@ -134,4 +134,4 @@ public: } //end namespace rts -#endif \ No newline at end of file +#endif diff --git a/math/field.cuh b/math/field.cuh index 98186b3..f5a6f99 100644 --- a/math/field.cuh +++ b/math/field.cuh @@ -5,10 +5,14 @@ #include #include +#include "cublas_v2.h" +#include + #include "../math/rect.h" #include "../cuda/threads.h" #include "../cuda/error.h" #include "../cuda/devices.h" +#include "../visualization/colormap.h" namespace rts{ @@ -86,6 +90,41 @@ protected: grids = dim3((R[0] + SQRT_BLOCK -1)/SQRT_BLOCK, (R[1] + SQRT_BLOCK - 1)/SQRT_BLOCK); } + //find the maximum value of component n + T find_max(unsigned int n){ + cublasStatus_t stat; + cublasHandle_t handle; + + //create a CUBLAS handle + stat = cublasCreate(&handle); + if(stat != CUBLAS_STATUS_SUCCESS){ + std::cout<<"CUBLAS Error: initialization failed"<>> (result.X[n], X[n], R[0], R[1], width, height); return result; + } + + //save an image representing component n + void toImage(std::string filename, unsigned int n = 0, + bool positive = false, rts::colormapType cmap = rts::cmBrewer){ + T max_val = find_max(n); //find the maximum value + if(positive) //if the field is positive, use the range [0 max_val] + rts::gpu2image(X[n], filename, R[0], R[1], 0, max_val, cmap); + else + rts::gpu2image(X[n], filename, R[0], R[1], -max_val, max_val, cmap); } }; } //end namespace rts -#endif \ No newline at end of file +#endif diff --git a/math/function.h b/math/function.h index 97a9c69..786b921 100644 --- a/math/function.h +++ b/math/function.h @@ -2,7 +2,6 @@ #define RTS_FUNCTION_H #include -#include namespace rts{ @@ -59,7 +58,7 @@ protected: public: function(){ - range[0] = range[1] = NAN; + range[0] = range[1] = 0; bounding[0] = bounding[1] = 0; } @@ -182,7 +181,8 @@ public: function & operator= (const Ty & rhs){ X.clear(); Y.clear(); - if(rhs != 0) //if the RHS is zero, just clear, otherwise add one value of RHS + bounding[0] = bounding[1] = rhs; //set the boundary values to rhs + if(rhs != 0) //if the RHS is zero, just clear, otherwise add one value of RHS insert(0, rhs); return *this; diff --git a/optics/mirst-1d.cuh b/optics/mirst-1d.cuh index 066f3a9..ce17cf8 100644 --- a/optics/mirst-1d.cuh +++ b/optics/mirst-1d.cuh @@ -1,6 +1,7 @@ #include "../optics/material.h" #include "../math/complexfield.cuh" #include "../math/constants.h" +#include "../envi/bil.h" #include "cufft.h" @@ -163,6 +164,8 @@ private: T NA[2]; //numerical aperature (central obscuration and outer diameter) + function source_profile; //profile (spectrum) of the source (expressed in inverse centimeters) + complexfield scratch; //scratch GPU memory used to build samples, transforms, etc. void fft(int direction = CUFFT_FORWARD){ @@ -251,7 +254,7 @@ private: HANDLE_ERROR(cudaMemcpy( gpuRi + inu, &ri, sizeof(complex), cudaMemcpyHostToDevice )); //save the source profile to the GPU - source = 1; + source = source_profile(10000 / lambdas[inu]); HANDLE_ERROR(cudaMemcpy( gpuSrc + inu, &source, sizeof(T), cudaMemcpyHostToDevice )); } @@ -311,6 +314,11 @@ private: scratch = scratch.crop(Z, S); } + //save the scratch field as a binary file + void to_binary(std::string filename){ + + } + public: @@ -322,6 +330,7 @@ public: NA[0] = 0; NA[1] = 0.8; S = 0; + source_profile = 1; } //add a layer, thickness = microns @@ -334,6 +343,11 @@ public: add_layer(material(filename), thickness); } + //adds a profile spectrum for the light source + void set_source(std::string filename){ + source_profile.load(filename); + } + //adds a block of wavenumbers (cm^-1) to the simulation parameters void add_wavenumbers(unsigned int start, unsigned int stop, unsigned int step){ unsigned int nu = start; @@ -368,6 +382,10 @@ public: na(0, out); } + rts::function get_source(){ + return source_profile; + } + void save_sample(std::string filename){ //create a sample and save the magnitude as an image build_sample(); @@ -375,7 +393,7 @@ public: scratch.toImage(filename, rts::complexfield::magnitude); } - void save_mirst(std::string filename){ + void save_mirst(std::string filename, bool binary = true){ //apply the MIRST filter to a sample and save the image //build the sample in the Fourier domain @@ -390,7 +408,10 @@ public: crop(); //save the image - scratch.toImage(filename, rts::complexfield::magnitude); + if(binary) + to_binary(filename); + else + scratch.toImage(filename, rts::complexfield::magnitude); } @@ -411,6 +432,9 @@ public: for(unsigned int l=0; l