Commit 6f99700eb3a4bcc03eae9f0e41fad87ee545d186
Merge branch 'master' of git.stim.ee.uh.edu:codebase/stimlib
Showing
8 changed files
with
338 additions
and
46 deletions
Show diff stats
stim/envi/bsq.h
... | ... | @@ -1021,12 +1021,13 @@ public: |
1021 | 1021 | //for each band |
1022 | 1022 | for (unsigned long long z = b0; z < b1; z++) |
1023 | 1023 | { |
1024 | + //std::cout<<z<<std::endl; | |
1024 | 1025 | for (unsigned long long y = 0; y < lines; y++) |
1025 | 1026 | { |
1026 | 1027 | file.read((char *)(temp + y * samples), sizeof(T) * samples); |
1027 | 1028 | file.seekg(jumpl, std::ios::cur); //go to the next band |
1028 | 1029 | |
1029 | - if(PROGRESS) progress = (double)((z+1) * lines + y + 1) / ((b1 - b0) * lines) * 100; | |
1030 | + if(PROGRESS) progress = (double)((z - b0 + 1) * lines + y + 1) / ((b1 - b0) * lines) * 100; | |
1030 | 1031 | } |
1031 | 1032 | out.write(reinterpret_cast<const char*>(temp), L); //write slice data into target file |
1032 | 1033 | file.seekg(jumpb, std::ios::cur); | ... | ... |
stim/math/fft.h
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | |
4 | 4 | namespace stim{ |
5 | 5 | |
6 | - template<class T> | |
6 | + /*template<class T> | |
7 | 7 | void circshift(T *out, const T *in, size_t xdim, size_t ydim, size_t xshift, size_t yshift){ |
8 | 8 | size_t i, j, ii, jj; |
9 | 9 | for (i =0; i < xdim; i++) { |
... | ... | @@ -13,16 +13,31 @@ namespace stim{ |
13 | 13 | out[ii * ydim + jj] = in[i * ydim + j]; |
14 | 14 | } |
15 | 15 | } |
16 | + }*/ | |
17 | + | |
18 | + template<typename T> | |
19 | + void circshift(T *out, const T *in, int xdim, int ydim, int xshift, int yshift) | |
20 | + { | |
21 | + for (int i =0; i < xdim; i++) { | |
22 | + int ii = (i + xshift) % xdim; | |
23 | + if (ii<0) ii = xdim + ii; | |
24 | + for (int j = 0; j < ydim; j++) { | |
25 | + int jj = (j + yshift) % ydim; | |
26 | + if (jj<0) jj = ydim + jj; | |
27 | + //out[ii * ydim + jj] = in[i * ydim + j]; | |
28 | + out[jj * xdim + ii] = in[j * xdim + i]; | |
29 | + } | |
30 | + } | |
16 | 31 | } |
17 | 32 | |
18 | 33 | template<typename T> |
19 | 34 | void cpu_fftshift(T* out, T* in, size_t xdim, size_t ydim){ |
20 | - circshift(out, in, xdim, ydim, xdim/2, ydim/2); | |
35 | + circshift(out, in, xdim, ydim, std::floor(xdim/2), std::floor(ydim/2)); | |
21 | 36 | } |
22 | 37 | |
23 | 38 | template<typename T> |
24 | 39 | void cpu_ifftshift(T* out, T* in, size_t xdim, size_t ydim){ |
25 | - circshift(out, in, xdim, ydim, xdim/2, ydim/2); | |
40 | + circshift(out, in, xdim, ydim, std::ceil(xdim/2), std::ceil(ydim/2)); | |
26 | 41 | } |
27 | 42 | |
28 | 43 | ... | ... |
stim/optics/scalarbeam.h
... | ... | @@ -213,13 +213,13 @@ void gpu_scalar_psf_local(stim::complex<T>* E, size_t N, T* r, T* phi, T lambda, |
213 | 213 | T dr = (r_max - r_min) / (Nlut_j-1); //distance between values in the LUT |
214 | 214 | T jl; |
215 | 215 | for(size_t ri = 0; ri < Nlut_j; ri++){ //for each value in the LUT |
216 | - for(size_t l = 0; l <= Nl; l++){ //for each order | |
216 | + for(unsigned l = 0; l <= (unsigned)Nl; l++){ //for each order | |
217 | 217 | jl = boost::math::sph_bessel<T>(l, k*(r_min + ri * dr)); //use boost to calculate the spherical bessel function |
218 | 218 | j_lut[ri * (Nl + 1) + l] = jl; //store the bessel function result |
219 | 219 | } |
220 | 220 | } |
221 | 221 | |
222 | - stim::cpu2image<T>(j_lut, "j_lut.bmp", Nl+1, Nlut_j, stim::cmBrewer); | |
222 | + //stim::cpu2image<T>(j_lut, "j_lut.bmp", Nl+1, Nlut_j, stim::cmBrewer); | |
223 | 223 | //Allocate device memory and copy everything to the GPU |
224 | 224 | |
225 | 225 | T* gpu_C; |
... | ... | @@ -316,6 +316,7 @@ void gpu_scalar_psf_cart(stim::complex<T>* E, size_t N, T* x, T* y, T* z, T lamb |
316 | 316 | |
317 | 317 | stim::quaternion<T> q; //create a quaternion |
318 | 318 | q.CreateRotation(d, stim::vec3<T>(0, 0, 1)); //create a mapping from the propagation direction to the PSF space |
319 | + stim::matrix<T, 3> rot = q.toMatrix3(); | |
319 | 320 | int threads = stim::maxThreadsPerBlock(); //get the maximum number of threads per block for the CUDA device |
320 | 321 | dim3 blocks( (unsigned)(N / threads + 1)); //calculate the optimal number of blocks |
321 | 322 | cuda_cart2psf<T> <<< blocks, threads >>> (gpu_r, gpu_phi, N, x, y, z, f, q); //call the CUDA kernel to move the cartesian coordinates to PSF space |
... | ... | @@ -442,15 +443,19 @@ public: |
442 | 443 | return samples; |
443 | 444 | } |
444 | 445 | |
446 | + void eval(stim::scalarfield<T>& E, T* X, T* Y, T* Z, int order = 500){ | |
447 | + cpu_scalar_psf_cart<T>(E.ptr(), E.size(), X, Y, Z, lambda, A, f, d, NA[0], NA[1], order, E.spacing()); | |
448 | + } | |
449 | + | |
445 | 450 | /// Evaluate the beam to a scalar field using Debye focusing |
446 | - void eval(stim::scalarfield<T>& E, size_t order = 500){ | |
451 | + void eval(stim::scalarfield<T>& E, int order = 500){ | |
447 | 452 | size_t array_size = E.grid_bytes(); |
448 | 453 | T* X = (T*) malloc( array_size ); //allocate space for the coordinate meshes |
449 | 454 | T* Y = (T*) malloc( array_size ); |
450 | 455 | T* Z = (T*) malloc( array_size ); |
451 | 456 | |
452 | 457 | E.meshgrid(X, Y, Z, stim::CPUmem); //calculate the coordinate meshes |
453 | - cpu_scalar_psf_cart<T>(E.ptr(), E.size(), X, Y, Z, lambda, A, f, d, NA[0], NA[1], order, E.spacing()); | |
458 | + eval(E, X, Y, Z, order); | |
454 | 459 | |
455 | 460 | free(X); //free the coordinate meshes |
456 | 461 | free(Y); | ... | ... |
stim/optics/scalarfield.h
1 | 1 | #ifndef STIM_SCALARFIELD_H |
2 | 2 | #define STIM_SCALARFIELD_H |
3 | 3 | |
4 | + | |
4 | 5 | #include "../math/rect.h" |
5 | 6 | #include "../math/complex.h" |
7 | +#include "../math/fft.h" | |
6 | 8 | |
7 | 9 | namespace stim{ |
8 | 10 | |
11 | + /// Perform a k-space transform of a scalar field (FFT). The given field has a width of x and the calculated momentum space has a | |
12 | + /// width of kx (in radians). | |
13 | + /// @param K is a pointer to the output array of all plane waves in the field | |
14 | + /// @param kx is the width of the frame in momentum space | |
15 | + /// @param ky is the height of the frame in momentum space | |
16 | + /// @param E is the field to be transformed | |
17 | + /// @param x is the width of the field in the spatial domain | |
18 | + /// @param y is the height of the field in the spatial domain | |
19 | + /// @param nx is the number of pixels representing the field in the x (and kx) direction | |
20 | + /// @param ny is the number of pixels representing the field in the y (and ky) direction | |
21 | + template<typename T> | |
22 | + void cpu_scalar_to_kspace(stim::complex<T>* K, T& kx, T& ky, stim::complex<T>* E, T x, T y, size_t nx, size_t ny){ | |
23 | + | |
24 | + kx = stim::TAU * nx / x; //calculate the width of the momentum space | |
25 | + ky = stim::TAU * ny / y; | |
26 | + | |
27 | + stim::complex<T>* dev_FFT; | |
28 | + HANDLE_ERROR( cudaMalloc(&dev_FFT, sizeof(stim::complex<T>) * nx * ny) ); //allocate space on the CUDA device for the output array | |
29 | + | |
30 | + stim::complex<T>* dev_E; | |
31 | + HANDLE_ERROR( cudaMalloc(&dev_E, sizeof(stim::complex<T>) * nx * ny) ); //allocate space for the field | |
32 | + HANDLE_ERROR( cudaMemcpy(dev_E, E, sizeof(stim::complex<T>) * nx * ny, cudaMemcpyHostToDevice) ); //copy the field to GPU memory | |
33 | + | |
34 | + cufftResult result; | |
35 | + cufftHandle plan; | |
36 | + result = cufftPlan2d(&plan, nx, ny, CUFFT_C2C); | |
37 | + if(result != CUFFT_SUCCESS){ | |
38 | + std::cout<<"Error creating cuFFT plan."<<std::endl; | |
39 | + exit(1); | |
40 | + } | |
41 | + | |
42 | + result = cufftExecC2C(plan, (cufftComplex*)dev_E, (cufftComplex*)dev_FFT, CUFFT_FORWARD); | |
43 | + if(result != CUFFT_SUCCESS){ | |
44 | + std::cout<<"Error using cuFFT to perform a forward Fourier transform of the field."<<std::endl; | |
45 | + exit(1); | |
46 | + } | |
47 | + | |
48 | + stim::complex<T>* fft = (stim::complex<T>*) malloc(sizeof(stim::complex<T>) * nx * ny); | |
49 | + HANDLE_ERROR( cudaMemcpy(fft, dev_FFT, sizeof(stim::complex<T>) * nx * ny, cudaMemcpyDeviceToHost) ); | |
50 | + | |
51 | + stim::cpu_fftshift(K, fft, nx, ny); | |
52 | + //memcpy(K, fft, sizeof(stim::complex<T>) * nx * ny); | |
53 | + } | |
54 | + | |
55 | + template<typename T> | |
56 | + void cpu_scalar_from_kspace(stim::complex<T>* E, T& x, T& y, stim::complex<T>* K, T kx, T ky, size_t nx, size_t ny){ | |
57 | + | |
58 | + x = stim::TAU * nx / kx; //calculate the width of the momentum space | |
59 | + y = stim::TAU * ny / ky; | |
60 | + | |
61 | + stim::complex<T>* fft = (stim::complex<T>*) malloc(sizeof(stim::complex<T>) * nx * ny); | |
62 | + stim::cpu_ifftshift(fft, K, nx, ny); | |
63 | + //memcpy(fft, K, sizeof(stim::complex<T>) * nx * ny); | |
64 | + | |
65 | + stim::complex<T>* dev_FFT; | |
66 | + HANDLE_ERROR( cudaMalloc(&dev_FFT, sizeof(stim::complex<T>) * nx * ny) ); //allocate space on the CUDA device for the output array | |
67 | + HANDLE_ERROR( cudaMemcpy(dev_FFT, fft, sizeof(stim::complex<T>) * nx * ny, cudaMemcpyHostToDevice) ); //copy the field to GPU memory | |
68 | + | |
69 | + stim::complex<T>* dev_E; | |
70 | + HANDLE_ERROR( cudaMalloc(&dev_E, sizeof(stim::complex<T>) * nx * ny) ); //allocate space for the field | |
71 | + | |
72 | + cufftResult result; | |
73 | + cufftHandle plan; | |
74 | + result = cufftPlan2d(&plan, nx, ny, CUFFT_C2C); | |
75 | + if(result != CUFFT_SUCCESS){ | |
76 | + std::cout<<"Error creating cuFFT plan."<<std::endl; | |
77 | + exit(1); | |
78 | + } | |
79 | + | |
80 | + result = cufftExecC2C(plan, (cufftComplex*)dev_FFT, (cufftComplex*)dev_E, CUFFT_INVERSE); | |
81 | + if(result != CUFFT_SUCCESS){ | |
82 | + std::cout<<"Error using cuFFT to perform a forward Fourier transform of the field."<<std::endl; | |
83 | + exit(1); | |
84 | + } | |
85 | + | |
86 | + HANDLE_ERROR( cudaMemcpy(E, dev_E, sizeof(stim::complex<T>) * nx * ny, cudaMemcpyDeviceToHost) ); | |
87 | + | |
88 | + | |
89 | + } | |
90 | + | |
91 | + /// Propagate a field slice along its orthogonal direction by a given distance z | |
92 | + /// @param Enew is the resulting propogated field | |
93 | + /// @param E is the field to be propogated | |
94 | + /// @param sx is the size of the field in the lateral x direction | |
95 | + /// @param sy is the size of the field in the lateral y direction | |
96 | + /// @param z is the distance to be propagated | |
97 | + /// @param k is the wavenumber 2*pi/lambda | |
98 | + /// @param nx is the number of samples in the field along the lateral x direction | |
99 | + /// @param ny is the number of samples in the field along the lateral y direction | |
100 | + template<typename T> | |
101 | + void cpu_scalar_propagate(stim::complex<T>* Enew, stim::complex<T>* E, T sx, T sy, T z, T k, size_t nx, size_t ny){ | |
102 | + | |
103 | + stim::complex<T>* K = (stim::complex<T>*) malloc( sizeof(stim::complex<T>) * nx * ny ); | |
104 | + | |
105 | + T Kx, Ky; //width and height in k space | |
106 | + cpu_scalar_to_kspace(K, Kx, Ky, E ,sx, sy, nx, ny); | |
107 | + | |
108 | + T* mag = (T*) malloc( sizeof(T) * nx * ny ); | |
109 | + stim::abs(mag, K, nx * ny); | |
110 | + stim::cpu2image<float>(mag, "kspace_pre_shift.bmp", nx, ny, stim::cmBrewer); | |
111 | + | |
112 | + size_t kxi, kyi; | |
113 | + size_t i; | |
114 | + T kx, kx_sq, ky, ky_sq, k_sq; | |
115 | + T kz; | |
116 | + stim::complex<T> shift; | |
117 | + T min_kx = -Kx / 2; | |
118 | + T dkx = Kx / (nx); | |
119 | + | |
120 | + T min_ky = -Ky / 2; | |
121 | + T dky = Ky / (ny); | |
122 | + | |
123 | + for(kyi = 0; kyi < ny; kyi++){ //for each plane wave in the ky direction | |
124 | + for(kxi = 0; kxi < nx; kxi++){ //for each plane wave in the ky direction | |
125 | + i = kyi * nx + kxi; | |
126 | + | |
127 | + kx = min_kx + kxi * dkx; //calculate the position of the current plane wave | |
128 | + ky = min_ky + kyi * dky; | |
129 | + | |
130 | + kx_sq = kx * kx; | |
131 | + ky_sq = ky * ky; | |
132 | + k_sq = k*k; | |
133 | + | |
134 | + if(kx_sq + ky_sq < k_sq){ | |
135 | + kz = sqrt(k_sq - kx_sq - ky_sq); //estimate kz using the Fresnel approximation | |
136 | + shift = -exp(stim::complex<T>(0, kz * z)); | |
137 | + K[i] *= shift; | |
138 | + K[i] /= (nx*ny); //normalize the DFT | |
139 | + } | |
140 | + else{ | |
141 | + K[i] = 0; | |
142 | + } | |
143 | + } | |
144 | + } | |
145 | + | |
146 | + stim::abs(mag, K, nx * ny); | |
147 | + stim::cpu2image<float>(mag, "kspace_post_shift.bmp", nx, ny, stim::cmBrewer); | |
148 | + | |
149 | + cpu_scalar_from_kspace(Enew, sx, sy, K, Kx, Ky, nx, ny); | |
150 | + } | |
151 | + | |
152 | + /// Apply a lowpass filter to a field slice | |
153 | + /// @param Enew is the resulting propogated field | |
154 | + /// @param E is the field to be propogated | |
155 | + /// @param sx is the size of the field in the lateral x direction | |
156 | + /// @param sy is the size of the field in the lateral y direction | |
157 | + /// @param highest is the highest spatial frequency that can pass through the filter | |
158 | + /// @param nx is the number of samples in the field along the lateral x direction | |
159 | + /// @param ny is the number of samples in the field along the lateral y direction | |
160 | + template<typename T> | |
161 | + void cpu_scalar_lowpass(stim::complex<T>* Enew, stim::complex<T>* E, T sx, T sy, T highest, size_t nx, size_t ny){ | |
162 | + | |
163 | + stim::complex<T>* K = (stim::complex<T>*) malloc( sizeof(stim::complex<T>) * nx * ny ); | |
164 | + | |
165 | + T Kx, Ky; //width and height in k space | |
166 | + cpu_scalar_to_kspace(K, Kx, Ky, E ,sx, sy, nx, ny); | |
167 | + | |
168 | + T* mag = (T*) malloc( sizeof(T) * nx * ny ); | |
169 | + stim::abs(mag, K, nx * ny); | |
170 | + stim::cpu2image<float>(mag, "kspace_pre_lowpass.bmp", nx, ny, stim::cmBrewer); | |
171 | + | |
172 | + size_t kxi, kyi; | |
173 | + size_t i; | |
174 | + T kx, kx_sq, ky, ky_sq, k_sq; | |
175 | + T kz; | |
176 | + stim::complex<T> shift; | |
177 | + T min_kx = -Kx / 2; | |
178 | + T dkx = Kx / (nx); | |
179 | + | |
180 | + T min_ky = -Ky / 2; | |
181 | + T dky = Ky / (ny); | |
182 | + | |
183 | + T highest_sq = highest * highest; | |
184 | + | |
185 | + for(kyi = 0; kyi < ny; kyi++){ //for each plane wave in the ky direction | |
186 | + for(kxi = 0; kxi < nx; kxi++){ //for each plane wave in the ky direction | |
187 | + i = kyi * nx + kxi; | |
188 | + | |
189 | + kx = min_kx + kxi * dkx; //calculate the position of the current plane wave | |
190 | + ky = min_ky + kyi * dky; | |
191 | + | |
192 | + kx_sq = kx * kx; | |
193 | + ky_sq = ky * ky; | |
194 | + | |
195 | + if(kx_sq + ky_sq > highest_sq){ | |
196 | + K[i] = 0; | |
197 | + } | |
198 | + else | |
199 | + K[i] /= nx * ny; //normalize the DFT | |
200 | + } | |
201 | + } | |
202 | + | |
203 | + stim::abs(mag, K, nx * ny); | |
204 | + stim::cpu2image<float>(mag, "kspace_post_lowpass.bmp", nx, ny, stim::cmBrewer); | |
205 | + | |
206 | + cpu_scalar_from_kspace(Enew, sx, sy, K, Kx, Ky, nx, ny); | |
207 | + } | |
208 | + | |
9 | 209 | enum locationType {CPUmem, GPUmem}; |
10 | 210 | |
11 | 211 | /// Class represents a scalar optical field. |
... | ... | @@ -22,23 +222,20 @@ protected: |
22 | 222 | size_t R[2]; |
23 | 223 | locationType loc; |
24 | 224 | |
25 | - | |
26 | - | |
27 | -public: | |
28 | - | |
29 | - CUDA_CALLABLE scalarfield(size_t X, size_t Y, T size = 1, T z_pos = 0) : rect<T>::rect(size, z_pos){ | |
30 | - R[0] = X; //set the field resolution | |
31 | - R[1] = Y; | |
32 | - | |
33 | - E = (stim::complex<T>*) malloc(sizeof(stim::complex<T>) * R[0] * R[1]); //allocate in CPU memory | |
34 | - loc = CPUmem; | |
225 | + /// Convert the field to a k-space representation (do an FFT) | |
226 | + void to_kspace(T& kx, T& ky){ | |
227 | + cpu_scalar_to_kspace(E, kx, ky, E, X.len(), Y.len(), R[0], R[1]); | |
35 | 228 | } |
36 | 229 | |
37 | - CUDA_CALLABLE ~scalarfield(){ | |
38 | - if(loc == CPUmem) free(E); | |
39 | - else cudaFree(E); | |
230 | + void from_kspace(){ | |
231 | + kx = stim::TAU * R[0] / X.len(); //calculate the width of the momentum space | |
232 | + ky = stim::TAU * R[1] / Y.len(); | |
233 | + T x, y; | |
234 | + cpu_scalar_from_kspace(E, x, y, E, kx, ky, R[0], R[1]); | |
40 | 235 | } |
41 | 236 | |
237 | +public: | |
238 | + | |
42 | 239 | /// Returns the number of values in the field |
43 | 240 | CUDA_CALLABLE size_t size(){ |
44 | 241 | return R[0] * R[1]; |
... | ... | @@ -48,6 +245,20 @@ public: |
48 | 245 | return sizeof(stim::complex<T>) * R[0] * R[1]; |
49 | 246 | } |
50 | 247 | |
248 | + scalarfield(size_t X, size_t Y, T size = 1, T z_pos = 0) : rect<T>::rect(size, z_pos){ | |
249 | + R[0] = X; //set the field resolution | |
250 | + R[1] = Y; | |
251 | + | |
252 | + E = (stim::complex<T>*) malloc(grid_bytes()); //allocate in CPU memory | |
253 | + memset(E, 0, grid_bytes()); | |
254 | + loc = CPUmem; | |
255 | + } | |
256 | + | |
257 | + ~scalarfield(){ | |
258 | + if(loc == CPUmem) free(E); | |
259 | + else cudaFree(E); | |
260 | + } | |
261 | + | |
51 | 262 | /// Calculates the distance between points on the grid |
52 | 263 | T spacing(){ |
53 | 264 | T du = rect<T>::X.len() / R[0]; |
... | ... | @@ -78,6 +289,16 @@ public: |
78 | 289 | } |
79 | 290 | } |
80 | 291 | |
292 | + /// Propagate the field along its orthogonal direction by a distance d | |
293 | + void propagate(T d, T k){ | |
294 | + cpu_scalar_propagate(E, E, X.len(), Y.len(), d, k, R[0], R[1]); | |
295 | + } | |
296 | + | |
297 | + /// Propagate the field along its orthogonal direction by a distance d | |
298 | + void lowpass(T highest){ | |
299 | + cpu_scalar_lowpass(E, E, X.len(), Y.len(), highest, R[0], R[1]); | |
300 | + } | |
301 | + | |
81 | 302 | std::string str(){ |
82 | 303 | std::stringstream ss; |
83 | 304 | ss<<rect<T>::str()<<std::endl; |
... | ... | @@ -96,11 +317,11 @@ public: |
96 | 317 | |
97 | 318 | /// Evaluate the cartesian coordinates of each point in the field. The resulting arrays are allocated in the same memory where the field is stored. |
98 | 319 | void meshgrid(T* X, T* Y, T* Z, locationType location){ |
99 | - size_t array_size = sizeof(T) * R[0] * R[1]; | |
320 | + //size_t array_size = sizeof(T) * R[0] * R[1]; | |
100 | 321 | if(location == CPUmem){ |
101 | 322 | |
102 | - T du = 1.0 / (R[0] - 1); //calculate the spacing between points in the grid | |
103 | - T dv = 1.0 / (R[1] - 1); | |
323 | + T du = (T)1.0 / (R[0] - 1); //calculate the spacing between points in the grid | |
324 | + T dv = (T)1.0 / (R[1] - 1); | |
104 | 325 | |
105 | 326 | size_t ui, vi, i; |
106 | 327 | stim::vec3<T> p; |
... | ... | @@ -114,9 +335,9 @@ public: |
114 | 335 | i++; |
115 | 336 | } |
116 | 337 | } |
117 | - stim::cpu2image(X, "X.bmp", R[0], R[1], stim::cmBrewer); | |
118 | - stim::cpu2image(Y, "Y.bmp", R[0], R[1], stim::cmBrewer); | |
119 | - stim::cpu2image(Z, "Z.bmp", R[0], R[1], stim::cmBrewer); | |
338 | + //stim::cpu2image(X, "X.bmp", R[0], R[1], stim::cmBrewer); | |
339 | + //stim::cpu2image(Y, "Y.bmp", R[0], R[1], stim::cmBrewer); | |
340 | + //stim::cpu2image(Z, "Z.bmp", R[0], R[1], stim::cmBrewer); | |
120 | 341 | } |
121 | 342 | else{ |
122 | 343 | std::cout<<"GPU allocation of a meshgrid isn't supported yet. You'll have to write kernels to do the calculation."; |
... | ... | @@ -124,6 +345,14 @@ public: |
124 | 345 | } |
125 | 346 | } |
126 | 347 | |
348 | + //clear the field, setting all values to zero | |
349 | + void clear(){ | |
350 | + if(loc == GPUmem) | |
351 | + HANDLE_ERROR(cudaMemset(E, 0, grid_bytes())); | |
352 | + else | |
353 | + memset(E, 0, grid_bytes()); | |
354 | + } | |
355 | + | |
127 | 356 | void image(std::string filename, stim::complexComponentType type = complexMag, stim::colormapType cmap = stim::cmBrewer){ |
128 | 357 | |
129 | 358 | if(loc == GPUmem) to_cpu(); //if the field is in the GPU, move it to the CPU | ... | ... |
stim/optics/mie.h renamed to stim/optics/scalarmie.h
... | ... | @@ -366,7 +366,7 @@ __global__ void cuda_scalar_mie_internal(stim::complex<T>* E, size_t N, T* x, T* |
366 | 366 | (z == NULL) ? p[2] = 0 : p[2] = z[i]; |
367 | 367 | |
368 | 368 | T r = p.len(); //calculate the distance from the sphere |
369 | - if(r > a) return; //exit if the point is inside the sphere (we only calculate the internal field) | |
369 | + if(r >= a) return; //exit if the point is inside the sphere (we only calculate the internal field) | |
370 | 370 | T fij = (r - r_min)/dr; //FP index into the spherical bessel LUT |
371 | 371 | size_t ij = (size_t) fij; //convert to an integral index |
372 | 372 | T alpha = fij - ij; //calculate the fractional portion of the index |
... | ... | @@ -608,6 +608,39 @@ void cpu_scalar_mie_internal(stim::complex<T>* E, size_t N, T* x, T* y, T* z, st |
608 | 608 | cpu_scalar_mie_internal(E, N, x, y, z, W, a, n, r_spacing); |
609 | 609 | } |
610 | 610 | |
611 | -} | |
611 | + | |
612 | +/// Class stim::scalarmie represents a scalar Mie scattering model that can be used to calculate the fields produced by a scattering sphere. | |
613 | +template<typename T> | |
614 | +class scalarmie | |
615 | +{ | |
616 | +private: | |
617 | + T radius; //radius of the scattering sphere | |
618 | + stim::complex<T> n; //refractive index of the scattering sphere | |
619 | + | |
620 | +public: | |
621 | + | |
622 | + scalarmie(T r, stim::complex<T> ri){ | |
623 | + radius = r; | |
624 | + n = ri; | |
625 | + } | |
626 | + | |
627 | + void eval(stim::scalarfield<T>& E, stim::scalarbeam<T> b, int order = 500, int samples = 1000){ | |
628 | + | |
629 | + size_t array_size = E.grid_bytes(); //calculate the number of bytes in the scalar grid | |
630 | + float* X = (float*) malloc( array_size ); //allocate space for the coordinate meshes | |
631 | + float* Y = (float*) malloc( array_size ); | |
632 | + float* Z = (float*) malloc( array_size ); | |
633 | + E.meshgrid(X, Y, Z, stim::CPUmem); //calculate the coordinate meshes | |
634 | + | |
635 | + b.eval(E, X, Y, Z, order); //evaluate the incident field using a plane wave expansion | |
636 | + | |
637 | + std::vector< stim::scalarwave<float> > wave_array = b.mc(samples); //decompose the beam into an array of plane waves | |
638 | + stim::cpu_scalar_mie_scatter<float>(E.ptr(), E.size(), X, Y, Z, wave_array, radius, n, E.spacing()); | |
639 | + stim::cpu_scalar_mie_internal<float>(E.ptr(), E.size(), X, Y, Z, wave_array, radius, n, E.spacing()); | |
640 | + } | |
641 | + | |
642 | +}; //end stim::scalarmie | |
643 | + | |
644 | +} //end namespace stim | |
612 | 645 | |
613 | 646 | #endif |
614 | 647 | \ No newline at end of file | ... | ... |
stim/optics/scalarwave.h
... | ... | @@ -210,7 +210,7 @@ template<typename T> |
210 | 210 | __global__ void cuda_scalarwave(stim::complex<T>* F, size_t N, T* x, T* y, T* z, stim::scalarwave<T>* W, size_t n_waves){ |
211 | 211 | extern __shared__ stim::scalarwave<T> shared_W[]; //declare the list of waves in shared memory |
212 | 212 | |
213 | - stim::cuda::sharedMemcpy(shared_W, W, n_waves, threadIdx.x, blockDim.x); //copy the plane waves into shared memory for faster access | |
213 | + stim::cuda::threadedMemcpy(shared_W, W, n_waves, threadIdx.x, blockDim.x); //copy the plane waves into shared memory for faster access | |
214 | 214 | __syncthreads(); //synchronize threads to insure all data is copied |
215 | 215 | |
216 | 216 | size_t i = blockIdx.x * blockDim.x + threadIdx.x; //get the index into the array | ... | ... |
stim/parser/arguments.h
... | ... | @@ -42,11 +42,13 @@ namespace stim{ |
42 | 42 | bool char_numerical(char c){ |
43 | 43 | if( (c >= '0' && c <= '9') || c == '-' || c == '.') |
44 | 44 | return true; |
45 | + return false; | |
45 | 46 | } |
46 | 47 | |
47 | 48 | bool char_integral(char c){ |
48 | 49 | if( (c >= '0' && c <= '9') || c == '-') |
49 | 50 | return true; |
51 | + return false; | |
50 | 52 | } |
51 | 53 | |
52 | 54 | /// Test if a given string contains a numerical (real) value |
... | ... | @@ -475,31 +477,31 @@ namespace stim{ |
475 | 477 | ///Determines of a parameter has been set and returns true if it has |
476 | 478 | |
477 | 479 | /// @param _name is the name of the argument |
478 | - bool operator()(std::string _name) | |
479 | - { | |
480 | - size_t i = find(opts.begin(), opts.end(), _name) - opts.begin(); | |
480 | + bool operator()(std::string _name){ | |
481 | + std::vector<cmd_option>::iterator it; | |
482 | + it = std::find(opts.begin(), opts.end(), _name);// - opts.begin(); | |
481 | 483 | |
482 | - if(i < 0){ | |
484 | + if(it == opts.end()){ | |
483 | 485 | std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl; |
484 | 486 | exit(1); |
485 | 487 | } |
486 | 488 | |
487 | - return opts[i].is_set(); | |
489 | + return it->is_set(); | |
488 | 490 | } |
489 | 491 | |
490 | 492 | ///Returns the number of parameters for a specified argument |
491 | 493 | |
492 | 494 | /// @param _name is the name of the argument whose parameter number will be returned |
493 | - size_t nargs(std::string _name) | |
494 | - { | |
495 | - size_t i = find(opts.begin(), opts.end(), _name) - opts.begin(); | |
495 | + size_t nargs(std::string _name){ | |
496 | + std::vector<cmd_option>::iterator it; | |
497 | + it = find(opts.begin(), opts.end(), _name);// - opts.begin(); | |
496 | 498 | |
497 | - if(i < 0){ | |
499 | + if(it == opts.end()){ | |
498 | 500 | std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl; |
499 | 501 | exit(1); |
500 | 502 | } |
501 | 503 | |
502 | - return opts[i].nargs(); | |
504 | + return it->nargs(); | |
503 | 505 | } |
504 | 506 | |
505 | 507 | ///Returns the number of arguments that have been set |
... | ... | @@ -525,17 +527,16 @@ namespace stim{ |
525 | 527 | ///Returns an object describing the argument |
526 | 528 | |
527 | 529 | /// @param _name is the name of the requested argument |
528 | - cmd_option operator[](std::string _name) | |
529 | - { | |
530 | - size_t i = find(opts.begin(), opts.end(), _name) - opts.begin(); | |
530 | + cmd_option operator[](std::string _name){ | |
531 | + std::vector<cmd_option>::iterator it; | |
532 | + it = find(opts.begin(), opts.end(), _name);// - opts.begin(); | |
531 | 533 | |
532 | - if(i < 0 || i >= opts.size()) | |
533 | - { | |
534 | + if(it == opts.end()){ | |
534 | 535 | std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl; |
535 | 536 | exit(1); |
536 | 537 | } |
537 | 538 | |
538 | - return opts[i]; | |
539 | + return *it; | |
539 | 540 | } |
540 | 541 | |
541 | 542 | ... | ... |
stim/parser/filename.h
... | ... | @@ -68,6 +68,7 @@ protected: |
68 | 68 | |
69 | 69 | //parse a file locator string |
70 | 70 | void parse(std::string loc){ |
71 | + if(loc.size() == 0) return; | |
71 | 72 | |
72 | 73 | loc = unix_div(loc); |
73 | 74 | |
... | ... | @@ -307,6 +308,13 @@ public: |
307 | 308 | parse_name(fname); |
308 | 309 | } |
309 | 310 | |
311 | + //append a string to the filename and return a new filename | |
312 | + stim::filename append(std::string s){ | |
313 | + stim::filename result = *this; //create a new filename, copy the current filename | |
314 | + result.prefix = prefix + s; //append the string to the filename | |
315 | + return result; | |
316 | + } | |
317 | + | |
310 | 318 | //get a path relative to the current one |
311 | 319 | stim::filename get_relative(std::string rel){ |
312 | 320 | ... | ... |