Commit 7a2d001231356d6903d068e28fb914a9af0071c0

Authored by David Mayerich
1 parent 24aab7c9

mirst1d updates

math/complexfield.cuh
... ... @@ -6,16 +6,36 @@
6 6  
7 7 #include "../math/field.cuh"
8 8 #include "../math/complex.h"
  9 +#include "../math/realfield.cuh"
9 10  
10 11 namespace rts{
11 12  
  13 +template<typename T>
  14 +__global__ void gpu_complexfield_mag(T* dest, complex<T>* source, unsigned int r0, unsigned int r1){
  15 +
  16 + int iu = blockIdx.x * blockDim.x + threadIdx.x;
  17 + int iv = blockIdx.y * blockDim.y + threadIdx.y;
  18 +
  19 + //make sure that the thread indices are in-bounds
  20 + if(iu >= r0 || iv >= r1) return;
  21 +
  22 + //compute the index into the field
  23 + int i = iv*r0 + iu;
  24 +
  25 + //calculate and store the result
  26 + dest[i] = source[i].abs();
  27 +}
  28 +
12 29 /*This class stores functions for saving images of complex fields
13 30 */
14   -template<typename T, unsigned int D>
  31 +template<typename T, unsigned int D = 1>
15 32 class complexfield : public field< rts::complex<T>, D >{
16 33 using field< rts::complex<T>, D >::R;
17 34 using field< rts::complex<T>, D >::X;
18 35 using field< rts::complex<T>, D >::shape;
  36 + using field< rts::complex<T>, D >::cuda_params;
  37 +
  38 +
19 39  
20 40 public:
21 41  
... ... @@ -56,12 +76,20 @@ public:
56 76  
57 77 public:
58 78  
  79 + enum attribute {magnitude, real, imaginary};
  80 +
59 81 //constructor (no parameters)
60 82 complexfield() : field<rts::complex<T>, D>(){};
61 83  
62 84 //constructor (resolution specified)
63 85 complexfield(unsigned int r0, unsigned int r1) : field<rts::complex<T>, D>(r0, r1){};
64 86  
  87 + //assignment from a field of complex values
  88 + complexfield & operator=(const field< rts::complex<T>, D > rhs){
  89 + field< complex<T>, D >::operator=(rhs);
  90 + return *this;
  91 + }
  92 +
65 93 //assignment operator (scalar value)
66 94 complexfield & operator= (const complex<T> rhs){
67 95  
... ... @@ -76,7 +104,26 @@ public:
76 104 return *this;
77 105 }
78 106  
79   - void toImage(std::string filename, unsigned int n){
  107 + //cropping
  108 + complexfield crop(unsigned int width, unsigned int height){
  109 +
  110 + complexfield<T, D> result;
  111 + result = field< complex<T>, D>::crop(width, height);
  112 + return result;
  113 + }
  114 +
  115 + void toImage(std::string filename, attribute type = magnitude, unsigned int n=0){
  116 +
  117 + realfield<T, 1, true> rf(R[0], R[1]);
  118 +
  119 + //get cuda parameters
  120 + dim3 blocks, grids;
  121 + cuda_params(grids, blocks);
  122 +
  123 + if(type == magnitude){
  124 + gpu_complexfield_mag <<<grids, blocks>>> (rf.ptr(), X[n], R[0], R[1]);
  125 + rf.toImages(filename, 0);
  126 + }
80 127  
81 128 }
82 129  
... ...
math/field.cuh
... ... @@ -47,7 +47,27 @@ __global__ void gpu_field_assign(T* ptr, T val, unsigned int r0, unsigned int r1
47 47 ptr[i] = val;
48 48 }
49 49  
50   -template<typename T, unsigned int D>
  50 +//crop the field to the new dimensions (width x height)
  51 +template<typename T>
  52 +__global__ void gpu_field_crop(T* dest, T* source,
  53 + unsigned int r0, unsigned int r1,
  54 + unsigned int width, unsigned int height){
  55 +
  56 + int iu = blockIdx.x * blockDim.x + threadIdx.x;
  57 + int iv = blockIdx.y * blockDim.y + threadIdx.y;
  58 +
  59 + //make sure that the thread indices are in-bounds
  60 + if(iu >= width || iv >= height) return;
  61 +
  62 + //compute the index into the field
  63 + int is = iv*r0 + iu;
  64 + int id = iv*width + iu;
  65 +
  66 + //calculate and store the result
  67 + dest[id] = source[is];
  68 +}
  69 +
  70 +template<typename T, unsigned int D = 1>
51 71 class field{
52 72  
53 73 protected:
... ... @@ -56,6 +76,16 @@ protected:
56 76 unsigned int R[2]; //field resolution
57 77 rts::rect<T> shape; //position and shape of the field slice
58 78  
  79 + //calculates the optimal block and grid sizes using information from the GPU
  80 + void cuda_params(dim3& grids, dim3& blocks){
  81 + int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size
  82 + int SQRT_BLOCK = (int)std::sqrt((float)maxThreads);
  83 +
  84 + //create one thread for each detector pixel
  85 + blocks = dim3(SQRT_BLOCK, SQRT_BLOCK);
  86 + grids = dim3((R[0] + SQRT_BLOCK -1)/SQRT_BLOCK, (R[1] + SQRT_BLOCK - 1)/SQRT_BLOCK);
  87 + }
  88 +
59 89 public:
60 90  
61 91 //returns a list of file names given an input string with wild cards
... ... @@ -101,7 +131,6 @@ public:
101 131 HANDLE_ERROR(cudaFree(X[n]));
102 132 }
103 133  
104   -
105 134 public:
106 135 //field constructor
107 136 field(){
... ... @@ -241,6 +270,25 @@ public:
241 270 HANDLE_ERROR(cudaMemset(X[n], 0, sizeof(T) * R[0] * R[1]));
242 271 }
243 272  
  273 + //crop the field
  274 + field<T, D> crop(unsigned int width, unsigned int height){
  275 + int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size
  276 + int SQRT_BLOCK = (int)std::sqrt((float)maxThreads);
  277 +
  278 + //create one thread for each detector pixel
  279 + dim3 dimBlock(SQRT_BLOCK, SQRT_BLOCK);
  280 + dim3 dimGrid((width + SQRT_BLOCK -1)/SQRT_BLOCK, (height + SQRT_BLOCK - 1)/SQRT_BLOCK);
  281 +
  282 + //create a scalar field to store the result
  283 + field<T, D> result(width, height);
  284 +
  285 + for(int n=0; n<D; n++)
  286 + rts::gpu_field_crop <<<dimGrid, dimBlock>>> (result.X[n], X[n], R[0], R[1], width, height);
  287 +
  288 + return result;
  289 +
  290 + }
  291 +
244 292 };
245 293  
246 294 } //end namespace rts
... ...
math/realfield.cuh
... ... @@ -37,7 +37,7 @@ namespace rts{
37 37  
38 38 //multiply R = X * Y
39 39 template<typename T>
40   -__global__ void gpu_field_multiply(T* R, T* X, T* Y, unsigned int r0, unsigned int r1){
  40 +__global__ void gpu_realfield_multiply(T* R, T* X, T* Y, unsigned int r0, unsigned int r1){
41 41  
42 42 int iu = blockIdx.x * blockDim.x + threadIdx.x;
43 43 int iv = blockIdx.y * blockDim.y + threadIdx.y;
... ... @@ -244,7 +244,7 @@ public:
244 244 realfield<P, N, positive> result(R[0], R[1]);
245 245  
246 246 for(int n=0; n<N; n++)
247   - rts::gpu_field_multiply <<<dimGrid, dimBlock>>> (result.X[n], X[n], rhs.X[n], R[0], R[1]);
  247 + rts::gpu_realfield_multiply <<<dimGrid, dimBlock>>> (result.X[n], X[n], rhs.X[n], R[0], R[1]);
248 248  
249 249 return result;
250 250 }
... ...
optics/material.h
... ... @@ -403,9 +403,9 @@ namespace rts{
403 403 #endif
404 404 }
405 405  
406   - material(T lambda = 1.0, T n = 1.4, T k = 0.0)
  406 + material(T lambda = 1, T n = 1, T k = 0)
407 407 {
408   - dispersion.insert(lambda, complex<T>(0.0, k));
  408 + dispersion.insert(lambda, complex<T>(n, k));
409 409 /*//create a default refractive index
410 410 refIndex<T> def;
411 411 def.lambda = lambda;
... ... @@ -414,7 +414,7 @@ namespace rts{
414 414 add(def);
415 415 */
416 416 //set n0
417   - n0 = n;
  417 + n0 = 0;
418 418 }
419 419  
420 420 material(std::string filename, std::string format = "", T scaleA = 1.0)
... ...
optics/mirst-1d.cuh 0 → 100644
  1 +#include "../optics/material.h"
  2 +#include "../math/complexfield.cuh"
  3 +
  4 +#include "cufft.h"
  5 +
  6 +#include <vector>
  7 +#include <sstream>
  8 +
  9 +namespace rts{
  10 +
  11 +//this function writes a sinc function to "dest" such that an iFFT produces a slab
  12 +template<typename T>
  13 +__global__ void gpu_mirst1d_layer_fft(complex<T>* dest, complex<T>* ri,
  14 + T* src, T* zf,
  15 + T w, unsigned int zR, unsigned int nuR){
  16 + //dest = complex field representing the sample
  17 + //ri = refractive indices for each wavelength
  18 + //src = intensity of the light source for each wavelength
  19 + //zf = z position of the slab interface for each wavelength (accounting for optical path length)
  20 + //w = width of the slab (in pixels)
  21 + //zR = number of z-axis samples
  22 + //nuR = number of wavelengths
  23 +
  24 + //get the current coordinate in the plane slice
  25 + int ifz = blockIdx.x * blockDim.x + threadIdx.x;
  26 + int inu = blockIdx.y * blockDim.y + threadIdx.y;
  27 +
  28 + //make sure that the thread indices are in-bounds
  29 + if(inu >= nuR || ifz >= zR) return;
  30 +
  31 + int i = inu * zR + ifz;
  32 +
  33 + T fz;
  34 + if(ifz < zR/2)
  35 + fz = ifz / (T)zR;
  36 + else
  37 + fz = -(zR - ifz) / (T)zR;
  38 +
  39 + //if the slab starts outside of the simulation domain, just return
  40 + if(zf[inu] >= zR) return;
  41 +
  42 + //fill the array along z with a sinc function representing the Fourier transform of the layer
  43 +
  44 + T opl = w * ri[inu].real(); //optical path length
  45 +
  46 + //handle the case where the slab goes outside the simulation domain
  47 + if(zf[inu] + opl >= zR)
  48 + opl = zR - zf[inu];
  49 +
  50 + if(opl == 0) return;
  51 +
  52 + //T l = w * ri[inu].real();
  53 + //complex<T> e(0.0, -2 * PI * fz * (zf[inu] + zR/2 - l/2.0));
  54 + complex<T> e(0, -2 * PI * fz * (zf[inu] + opl/2));
  55 +
  56 + complex<T> eta = ri[inu] * ri[inu] - 1;
  57 +
  58 + //dest[i] = fz;//exp(e) * m[inu] * src[inu] * sin(PI * fz * l) / (PI * fz);
  59 + if(ifz == 0)
  60 + dest[i] += opl * exp(e) * eta * src[inu];
  61 + else
  62 + dest[i] += opl * exp(e) * eta * src[inu] * sin(PI * fz * opl) / (PI * fz * opl);
  63 +}
  64 +
  65 +template<typename T>
  66 +__global__ void gpu_mirst1d_increment_z(T* zf, complex<T>* ri, T w, unsigned int S){
  67 + //zf = current z depth (optical path length) in pixels
  68 + //ri = refractive index of the material
  69 + //w = actual width of the layer (in pixels)
  70 +
  71 +
  72 + //compute the index for this thread
  73 + int i = blockIdx.x * blockDim.x + threadIdx.x;
  74 + if(i >= S) return;
  75 +
  76 + if(ri == NULL)
  77 + zf[i] += w;
  78 + else
  79 + zf[i] += ri[i].real() * w;
  80 +}
  81 +
  82 +//apply the 1D MIRST filter to an existing sample (overwriting the sample)
  83 +template<typename T>
  84 +__global__ void gpu_mirst1d_apply_filter(complex<T>* sampleFFT, T* lambda,
  85 + T dFz,
  86 + T inNA, T outNA,
  87 + unsigned int lambdaR, unsigned int zR,
  88 + T sigma = 0){
  89 + //sampleFFT = the sample in the Fourier domain (will be overwritten)
  90 + //lambda = list of wavelengths
  91 + //dFz = delta along the Fz axis in the frequency domain
  92 + //inNA = NA of the internal obscuration
  93 + //outNA = NA of the objective
  94 + //zR = number of pixels along the Fz axis (same as the z-axis)
  95 + //lambdaR = number of wavelengths
  96 + //sigma = width of the Gaussian source
  97 + int ifz = blockIdx.x * blockDim.x + threadIdx.x;
  98 + int inu = blockIdx.y * blockDim.y + threadIdx.y;
  99 +
  100 + if(inu >= lambdaR || ifz >= zR) return;
  101 +
  102 + //calculate the index into the sample FT
  103 + int i = inu * zR + ifz;
  104 +
  105 + //compute the frequency (and set all negative spatial frequencies to zero)
  106 + T fz;
  107 + if(ifz < zR / 2)
  108 + fz = ifz * dFz;
  109 + //if the spatial frequency is negative, set it to zero and exit
  110 + else{
  111 + sampleFFT[i] = 0;
  112 + return;
  113 + }
  114 +
  115 + //compute the frequency in inverse microns
  116 + T nu = 1/lambda[inu];
  117 +
  118 + //determine the radius of the integration circle
  119 + T nu_sq = nu * nu;
  120 + T fz_sq = (fz * fz) / 4;
  121 +
  122 + //cut off frequencies above the diffraction limit
  123 + T r;
  124 + if(fz_sq < nu_sq)
  125 + r = sqrt(nu_sq - fz_sq);
  126 + else
  127 + r = 0;
  128 +
  129 + //account for the optics
  130 + T Q = 0;
  131 + if(r > nu * inNA && r < nu * outNA)
  132 + Q = 1;
  133 +
  134 + //account for the source
  135 + //T sigma = 30.0;
  136 + T s = exp( - (r*r * sigma*sigma) / 2 );
  137 + //T s=1;
  138 +
  139 + //compute the final filter
  140 + T mirst = 0;
  141 + if(fz != 0)
  142 + mirst = 2 * PI * r * s * Q * (1/fz);
  143 +
  144 + sampleFFT[i] *= mirst;
  145 +
  146 +}
  147 +
  148 +/*This object performs a 1-dimensional (layered) MIRST simulation
  149 +*/
  150 +template<typename T>
  151 +class mirst1d{
  152 +
  153 +private:
  154 + unsigned int Z; //z-axis resolution
  155 + unsigned int pad; //pixel padding on either side of the sample
  156 +
  157 + std::vector< material<T> > matlist; //list of materials
  158 + std::vector< T > layers; //list of layer thicknesses
  159 +
  160 + std::vector< T > lambdas; //list of wavelengths that are being simulated
  161 + unsigned int S; //number of wavelengths (size of "lambdas")
  162 +
  163 + T NA[2]; //numerical aperature (central obscuration and outer diameter)
  164 +
  165 + complexfield<T, 1> scratch; //scratch GPU memory used to build samples, transforms, etc.
  166 +
  167 + void fft(int direction = CUFFT_FORWARD){
  168 +
  169 + unsigned padZ = Z + pad;
  170 +
  171 + //create cuFFT handles
  172 + cufftHandle plan;
  173 + cufftResult result;
  174 +
  175 + if(sizeof(T) == 4)
  176 + result = cufftPlan1d(&plan, padZ, CUFFT_C2C, lambdas.size()); //single precision
  177 + else
  178 + result = cufftPlan1d(&plan, padZ, CUFFT_Z2Z, lambdas.size()); //double precision
  179 +
  180 + //check for Plan 1D errors
  181 + if(result != CUFFT_SUCCESS){
  182 + std::cout<<"Error creating CUFFT plan for computing the FFT:"<<std::endl;
  183 + CufftError(result);
  184 + exit(1);
  185 + }
  186 +
  187 + if(sizeof(T) == 4)
  188 + result = cufftExecC2C(plan, (cufftComplex*)scratch.ptr(), (cufftComplex*)scratch.ptr(), direction);
  189 + else
  190 + result = cufftExecZ2Z(plan, (cufftDoubleComplex*)scratch.ptr(), (cufftDoubleComplex*)scratch.ptr(), direction);
  191 +
  192 + //check for FFT errors
  193 + if(result != CUFFT_SUCCESS){
  194 + std::cout<<"Error executing CUFFT to compute the FFT."<<std::endl;
  195 + CufftError(result);
  196 + exit(1);
  197 + }
  198 +
  199 + cufftDestroy(plan);
  200 + }
  201 +
  202 +
  203 + //initialize the scratch memory
  204 + void init_scratch(){
  205 + scratch = complexfield<T, 1>(Z + pad , lambdas.size());
  206 + scratch = 0;
  207 + }
  208 +
  209 + //get the list of scattering efficiency (eta) values for a specified layer
  210 + std::vector< complex<T> > layer_etas(unsigned int l){
  211 +
  212 + std::vector< complex<T> > etas;
  213 +
  214 + //fill the list of etas
  215 + for(unsigned int i=0; i<lambdas.size(); i++)
  216 + etas.push_back( matlist[l].eta(lambdas[i]) );
  217 + return etas;
  218 + }
  219 +
  220 + //calculates the optimal block and grid sizes using information from the GPU
  221 + void cuda_params(dim3& grids, dim3& blocks){
  222 + int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size
  223 + int SQRT_BLOCK = (int)std::sqrt((float)maxThreads);
  224 +
  225 + //create one thread for each detector pixel
  226 + blocks = dim3(SQRT_BLOCK, SQRT_BLOCK);
  227 + grids = dim3(((Z + 2 * pad) + SQRT_BLOCK -1)/SQRT_BLOCK, (S + SQRT_BLOCK - 1)/SQRT_BLOCK);
  228 + }
  229 +
  230 + //add the fourier transform of layer n to the scratch space
  231 + void build_layer_fft(unsigned int n, T* zf){
  232 + unsigned int paddedZ = Z + pad;
  233 +
  234 + T wpx = layers[n] / dz(); //calculate the width of the layer in pixels
  235 +
  236 + //allocate memory for the refractive index
  237 + complex<T>* gpuRi;
  238 + HANDLE_ERROR(cudaMalloc( (void**)&gpuRi, sizeof(complex<T>) * S));
  239 +
  240 + //allocate memory for the source profile
  241 + T* gpuSrc;
  242 + HANDLE_ERROR(cudaMalloc( (void**)&gpuSrc, sizeof(T) * S));
  243 +
  244 + complex<T> ri;
  245 + T source;
  246 + //store the refractive index and source profile in a CPU array
  247 + for(int inu=0; inu<S; inu++){
  248 + //save the refractive index to the GPU
  249 + ri = matlist[n].getN(lambdas[inu]);
  250 + HANDLE_ERROR(cudaMemcpy( gpuRi + inu, &ri, sizeof(complex<T>), cudaMemcpyHostToDevice ));
  251 +
  252 + //save the source profile to the GPU
  253 + source = 1;
  254 + HANDLE_ERROR(cudaMemcpy( gpuSrc + inu, &source, sizeof(T), cudaMemcpyHostToDevice ));
  255 +
  256 + }
  257 +
  258 + //create one thread for each pixel of the field slice
  259 + dim3 gridDim, blockDim;
  260 + cuda_params(gridDim, blockDim);
  261 + rts::gpu_mirst1d_layer_fft<<<gridDim, blockDim>>>(scratch.ptr(), gpuRi, gpuSrc, zf, wpx, paddedZ, S);
  262 +
  263 + int linBlock = rts::maxThreadsPerBlock(); //compute the optimal block size
  264 + int linGrid = S / linBlock + 1;
  265 + rts::gpu_mirst1d_increment_z <<<linGrid, linBlock>>>(zf, gpuRi, wpx, S);
  266 +
  267 + //free memory
  268 + HANDLE_ERROR(cudaFree(gpuRi));
  269 + HANDLE_ERROR(cudaFree(gpuSrc));
  270 + }
  271 +
  272 + void build_sample(){
  273 + init_scratch(); //initialize the GPU scratch space
  274 + //build_layer(1);
  275 +
  276 + T* zf;
  277 + HANDLE_ERROR(cudaMalloc(&zf, sizeof(T) * S));
  278 + HANDLE_ERROR(cudaMemset(zf, 0, sizeof(T) * S));
  279 +
  280 + //render each layer of the sample
  281 + for(unsigned int l=0; l<layers.size(); l++){
  282 + build_layer_fft(l, zf);
  283 + }
  284 +
  285 + HANDLE_ERROR(cudaFree(zf));
  286 + }
  287 +
  288 + void apply_filter(){
  289 + dim3 gridDim, blockDim;
  290 + cuda_params(gridDim, blockDim);
  291 +
  292 + unsigned int Zpad = Z + pad;
  293 +
  294 + T sim_range = dz() * Zpad;
  295 + T dFz = 1 / sim_range;
  296 +
  297 + //copy the array of wavelengths to the GPU
  298 + T* gpuLambdas;
  299 + HANDLE_ERROR(cudaMalloc(&gpuLambdas, sizeof(T) * Zpad));
  300 + HANDLE_ERROR(cudaMemcpy(gpuLambdas, &lambdas[0], sizeof(T) * Zpad, cudaMemcpyHostToDevice));
  301 + rts::gpu_mirst1d_apply_filter <<<gridDim, blockDim>>>(scratch.ptr(), gpuLambdas,
  302 + dFz,
  303 + NA[0], NA[1],
  304 + S, Zpad);
  305 + }
  306 +
  307 + //crop the image to the sample thickness - keep in mind that sample thickness != optical path length
  308 + void crop(){
  309 +
  310 + scratch = scratch.crop(Z, S);
  311 + }
  312 +
  313 +
  314 +public:
  315 +
  316 + //constructor
  317 + mirst1d(unsigned int rZ = 100,
  318 + unsigned int padding = 0){
  319 + Z = rZ;
  320 + pad = padding;
  321 + NA[0] = 0;
  322 + NA[1] = 0.8;
  323 + }
  324 +
  325 + //add a layer, thickness = microns
  326 + void add_layer(material<T> mat, T thickness){
  327 + matlist.push_back(mat);
  328 + layers.push_back(thickness);
  329 + }
  330 +
  331 + void add_layer(std::string filename, T thickness){
  332 + add_layer(material<T>(filename), thickness);
  333 + }
  334 +
  335 + //adds a block of wavenumbers (cm^-1) to the simulation parameters
  336 + void add_wavenumbers(unsigned int start, unsigned int stop, unsigned int step){
  337 + unsigned int nu = start;
  338 + while(nu <= stop){
  339 + lambdas.push_back((T)10000 / nu);
  340 + nu += step;
  341 + }
  342 + S = lambdas.size(); //increment the number of wavelengths (shorthand for later)
  343 + }
  344 +
  345 + T thickness(){
  346 + T t = 0;
  347 + for(unsigned int l=0; l<layers.size(); l++)
  348 + t += layers[l];
  349 + return t;
  350 + }
  351 +
  352 + void padding(unsigned int padding = 0){
  353 + pad = padding;
  354 + }
  355 +
  356 + T dz(){
  357 + return thickness() / Z; //calculate the z-axis step size
  358 + }
  359 +
  360 + void na(T in, T out){
  361 + NA[0] = in;
  362 + NA[1] = out;
  363 + }
  364 +
  365 + void na(T out){
  366 + na(0, out);
  367 + }
  368 +
  369 + void save_sample(std::string filename){
  370 + //create a sample and save the magnitude as an image
  371 + build_sample();
  372 + fft(CUFFT_INVERSE);
  373 + scratch.toImage(filename, rts::complexfield<T, 1>::magnitude);
  374 + }
  375 +
  376 + void save_mirst(std::string filename){
  377 + //apply the MIRST filter to a sample and save the image
  378 +
  379 + //build the sample in the Fourier domain
  380 + build_sample();
  381 +
  382 + //apply the MIRST filter
  383 + apply_filter();
  384 +
  385 + //apply an inverse FFT to bring the results back into the spatial domain
  386 + fft(CUFFT_INVERSE);
  387 +
  388 + crop();
  389 +
  390 + //save the image
  391 + scratch.toImage(filename, rts::complexfield<T, 1>::magnitude);
  392 + }
  393 +
  394 +
  395 +
  396 +
  397 + std::string str(){
  398 +
  399 + stringstream ss;
  400 +
  401 + ss<<"z-axis resolution: "<<Z<<std::endl;
  402 + ss<<"number of wavelengths: "<<lambdas.size()<<std::endl;
  403 + ss<<"padding: "<<pad<<std::endl;
  404 + ss<<"sample thickness: "<<thickness()<<" um"<<std::endl;
  405 + ss<<"dz: "<<dz()<<" um"<<std::endl;
  406 + ss<<std::endl;
  407 + ss<<"layers: "<<layers.size()<<" -----------------"<<std::endl;
  408 + for(unsigned int l=0; l<layers.size(); l++)
  409 + ss<<"layer "<<l<<": "<<layers[l]<<" um"<<" ("<<matlist[l].getName()<<")"<<std::endl;
  410 +
  411 + return ss.str();
  412 +
  413 +
  414 + }
  415 +
  416 +
  417 +
  418 +};
  419 +
  420 +}
0 421 \ No newline at end of file
... ...
tools/arguments.h renamed to ui/arguments.h
1   -#ifndef RTS_ARGUMENTS
2   -#define RTS_ARGUMENTS
3   -
4   -#include <string>
5   -#include <vector>
6   -#include <iostream>
7   -#include <iomanip>
8   -#include <sstream>
9   -#include <iterator>
10   -#include <algorithm>
11   -
12   -#ifdef _WIN32
13   -#include <Windows.h>
14   -#endif
15   -
16   -namespace rts{
17   -
18   - class argument
19   - {
20   - private:
21   - bool ansi;
22   -
23   - //argument name
24   - std::string name;
25   -
26   - //description of the argument
27   - std::vector<std::string> desc;
28   -
29   - //argument values
  1 +#ifndef RTS_ARGUMENTS
  2 +#define RTS_ARGUMENTS
  3 +
  4 +#include <string>
  5 +#include <vector>
  6 +#include <iostream>
  7 +#include <iomanip>
  8 +#include <sstream>
  9 +#include <iterator>
  10 +#include <algorithm>
  11 +
  12 +#ifdef _WIN32
  13 +#include <Windows.h>
  14 +#endif
  15 +
  16 +namespace rts{
  17 +
  18 + class argument
  19 + {
  20 + private:
  21 + bool ansi;
  22 +
  23 + //argument name
  24 + std::string name;
  25 +
  26 + //description of the argument
  27 + std::vector<std::string> desc;
  28 +
  29 + //argument values
30 30 std::vector<std::string> vals;
31 31  
32 32 //range or example
33 33 std::string range;
34 34  
35 35 //flag is true when the argument is user-specified
36   - bool flag;
37   -
38   - void parse_val(const std::string &s){
39   -
  36 + bool flag;
  37 +
  38 + void parse_val(const std::string &s){
  39 +
40 40 vals.clear();
41 41  
42   - std::stringstream ss(s);
43   - std::string item;
44   - while (std::getline(ss, item, ' ')) {
45   - vals.push_back(item);
46   - }
47   - }
48   -
49   - void parse_desc(const std::string &s){
50   -
51   - desc.clear();
52   -
53   - std::stringstream ss(s);
54   - std::string item;
55   - while (std::getline(ss, item, '\n')) {
56   - desc.push_back(item);
57   - }
58   - }
59   -
  42 + std::stringstream ss(s);
  43 + std::string item;
  44 + while (std::getline(ss, item, ' ')) {
  45 + vals.push_back(item);
  46 + }
  47 + }
  48 +
  49 + void parse_desc(const std::string &s){
  50 +
  51 + desc.clear();
  52 +
  53 + std::stringstream ss(s);
  54 + std::string item;
  55 + while (std::getline(ss, item, '\n')) {
  56 + desc.push_back(item);
  57 + }
  58 + }
  59 +
60 60 public:
61 61 void set_ansi(bool b){ ansi = b; }
62   - //create an argument with a given name, description, and default value
63   - argument(std::string _name, std::string _desc, std::string _default = "", std::string _range = "")
64   - {
65   - name = _name;
66   - parse_desc(_desc);
  62 + //create an argument with a given name, description, and default value
  63 + argument(std::string _name, std::string _desc, std::string _default = "", std::string _range = "")
  64 + {
  65 + name = _name;
  66 + parse_desc(_desc);
67 67 parse_val(_default);
68 68  
69 69 //if a default value is provided, set the flag
... ... @@ -73,7 +73,7 @@ namespace rts{
73 73  
74 74 range = _range;
75 75  
76   -
  76 +
77 77 }
78 78  
79 79 int nargs()
... ... @@ -156,26 +156,26 @@ namespace rts{
156 156 n += 4;
157 157  
158 158 return n;
159   - }
160   -
161   -
162   - //string output
163   - std::string toStr(int width = 0)
164   - {
  159 + }
  160 +
  161 +
  162 + //string output
  163 + std::string toStr(int width = 0)
  164 + {
165 165 std::stringstream ss;
166 166  
167 167 int color_size = 0;
168 168  
169   -
170   - //create the left column
171   - std::string left_part = std::string(" --") + name;
172   - if(vals.size() != 0)
  169 +
  170 + //create the left column
  171 + std::string left_part = std::string(" --") + name;
  172 + if(vals.size() != 0)
173 173 {
174 174 if(ansi)
175 175 left_part += "\033[1;32m";
176   - left_part += " ( = ";
177   - for(int v=0; v<vals.size(); v++)
178   - left_part += vals[v] + std::string(" ");
  176 + left_part += " ( = ";
  177 + for(int v=0; v<vals.size(); v++)
  178 + left_part += vals[v] + std::string(" ");
179 179 left_part += ")";
180 180 if(ansi)
181 181 left_part += "\033[0m";
... ... @@ -183,30 +183,30 @@ namespace rts{
183 183 color_size = 11;
184 184 }
185 185 else
186   - color_size = 0;
187   -
188   - //if no width is passed, put 4 spaces between left and right columns
  186 + color_size = 0;
  187 +
  188 + //if no width is passed, put 4 spaces between left and right columns
189 189 if(width == 0) width = col_width();
190   -
191   - ss<<std::left<<std::setw(width + color_size)<<left_part;
192   -
193   - //output right column
194   - for(int d=0; d<desc.size(); d++)
195   - {
196   - if(d == 0)
197   - ss<<desc[0];
  190 +
  191 + ss<<std::left<<std::setw(width + color_size)<<left_part;
  192 +
  193 + //output right column
  194 + for(int d=0; d<desc.size(); d++)
  195 + {
  196 + if(d == 0)
  197 + ss<<desc[0];
198 198 else
199 199 ss<<std::endl<<setfill(' ')<<setw(width)<<" "<<desc[d];
200   -
  200 +
201 201 }
202 202  
203 203 //output the range in the right column
204 204 if(range != "" && ansi)
205   - ss<<std::endl<<setfill(' ')<<setw(width)<<" "<<" "<<std::string("\033[1;36m") + range + "\033[0m";
206   - else if(range != "")
207   - ss<<std::endl<<setfill(' ')<<setw(width)<<" "<<" "<<range;
208   -
209   - return ss.str();
  205 + ss<<std::endl<<setfill(' ')<<setw(width)<<" "<<" "<<std::string("\033[1;36m") + range + "\033[0m";
  206 + else if(range != "")
  207 + ss<<std::endl<<setfill(' ')<<setw(width)<<" "<<" "<<range;
  208 +
  209 + return ss.str();
210 210 }
211 211  
212 212 //compare the name of the argument to a string
... ... @@ -227,8 +227,8 @@ namespace rts{
227 227 bool is_set()
228 228 {
229 229 return flag;
230   - }
231   -
  230 + }
  231 +
232 232 };
233 233  
234 234 struct argsection
... ... @@ -280,7 +280,7 @@ namespace rts{
280 280 }
281 281  
282 282 //output the arguments (generally in response to --help)
283   - std::string toStr()
  283 + std::string str()
284 284 {
285 285 std::stringstream ss;
286 286  
... ... @@ -407,10 +407,10 @@ namespace rts{
407 407 }
408 408  
409 409  
410   - };
411   -
412   -
413   -
  410 + };
  411 +
  412 +
  413 +
414 414 } //end namespace rts
415 415  
416 416 #endif
... ...
tools/progressbar.h renamed to ui/progressbar.h