Authored by David Mayerich
1 parent d609550e

### wave interactions with a planar surface

Showing 12 changed files with 851 additions and 213 deletions
math/bessel.h

 ... ... @@ -759,28 +759,28 @@ int bessjyv(P v,P x,P &vm,P *jv,P *yv, 759 759 } 760 760 vm = n + v0; 761 761 return 0; 762 -} 763 - 764 -template 762 +} 763 + 764 +template 765 765 int bessjyv_sph(int v, P z, P &vm, P* cjv, 766 - P* cyv, P* cjvp, P* cyvp) 767 -{ 768 - //first, compute the bessel functions of fractional order 769 - bessjyv(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); 770 - 771 - //iterate through each and scale 772 - for(int n = 0; n<=v; n++) 773 - { 774 - 775 - cjv[n] = cjv[n] * sqrt(PI/(z * 2.0)); 776 - cyv[n] = cyv[n] * sqrt(PI/(z * 2.0)); 777 - 778 - cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(PI / (z * 2.0)); 779 - cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(PI / (z * 2.0)); 780 - } 781 - 782 - return 0; 783 - 766 + P* cyv, P* cjvp, P* cyvp) 767 +{ 768 + //first, compute the bessel functions of fractional order 769 + bessjyv(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); 770 + 771 + //iterate through each and scale 772 + for(int n = 0; n<=v; n++) 773 + { 774 + 775 + cjv[n] = cjv[n] * sqrt(rtsPI/(z * 2.0)); 776 + cyv[n] = cyv[n] * sqrt(rtsPI/(z * 2.0)); 777 + 778 + cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(rtsPI / (z * 2.0)); 779 + cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(rtsPI / (z * 2.0)); 780 + } 781 + 782 + return 0; 783 + 784 784 } 785 785 786 786 template ... ... @@ -1485,28 +1485,28 @@ int cbessjyva(P v,complex<P> z,P &vm,complex<P>*cjv, 1485 1485 } 1486 1486 vm = n+v0; 1487 1487 return 0; 1488 -} 1489 - 1490 -template 1488 +} 1489 + 1490 +template 1491 1491 int cbessjyva_sph(int v,complex

z,P &vm,complex

*cjv, 1492 - complex

*cyv,complex

*cjvp,complex

*cyvp) 1493 -{ 1494 - //first, compute the bessel functions of fractional order 1495 - cbessjyva

(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); 1496 - 1497 - //iterate through each and scale 1498 - for(int n = 0; n<=v; n++) 1499 - { 1500 - 1501 - cjv[n] = cjv[n] * sqrt(PI/(z * 2.0)); 1502 - cyv[n] = cyv[n] * sqrt(PI/(z * 2.0)); 1503 - 1504 - cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(PI / (z * 2.0)); 1505 - cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(PI / (z * 2.0)); 1506 - } 1507 - 1508 - return 0; 1509 - 1492 + complex

*cyv,complex

*cjvp,complex

*cyvp) 1493 +{ 1494 + //first, compute the bessel functions of fractional order 1495 + cbessjyva

(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); 1496 + 1497 + //iterate through each and scale 1498 + for(int n = 0; n<=v; n++) 1499 + { 1500 + 1501 + cjv[n] = cjv[n] * sqrt(rtsPI/(z * 2.0)); 1502 + cyv[n] = cyv[n] * sqrt(rtsPI/(z * 2.0)); 1503 + 1504 + cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(rtsPI / (z * 2.0)); 1505 + cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(rtsPI / (z * 2.0)); 1506 + } 1507 + 1508 + return 0; 1509 + 1510 1510 } 1511 1511 1512 1512 } //end namespace rts ... ...

math/complex.h

 ... ... @@ -23,7 +23,14 @@ struct complex 23 23 CUDA_CALLABLE complex() 24 24 { 25 25 r = 0; 26 - i = 0; 26 + i = 0; 27 + } 28 + 29 + //constructor when given real and imaginary values 30 + CUDA_CALLABLE complex(T r, T i = 0) 31 + { 32 + this->r = r; 33 + this->i = i; 27 34 } 28 35 29 36 //access methods ... ... @@ -48,12 +55,7 @@ struct complex 48 55 return i_val; 49 56 } 50 57 51 - //constructor when given real and imaginary values 52 - CUDA_CALLABLE complex(T r, T i) 53 - { 54 - this->r = r; 55 - this->i = i; 56 - } 58 + 57 59 58 60 //return the current value multiplied by i 59 61 CUDA_CALLABLE complex imul() ... ...
math/constants.h

 1 1 #ifndef RTS_CONSTANTS_H 2 2 #define RTS_CONSTANTS_H 3 3 4 -namespace rts{ 5 - 6 - double PI = 3.14159; 7 - double TAU = 2 * PI; 8 -} 4 +#define rtsPI 3.14159 5 +#define rtsTAU 2 * rtsPI 9 6 10 7 #endif 11 8 \ No newline at end of file ... ...
math/plane.h 0 โ 100644

 1 +#ifndef RTS_PLANE_H 2 +#define RTS_PLANE_H 3 + 4 +#include 5 +#include "../math/vector.h" 6 +#include "rts/cuda/callable.h" 7 + 8 + 9 +namespace rts{ 10 +template class plane; 11 +} 12 + 13 +template 14 +CUDA_CALLABLE rts::plane operator-(rts::plane v); 15 + 16 +namespace rts{ 17 + 18 +template 19 +class plane{ 20 + 21 + //a plane is defined by a point and a normal 22 + 23 +private: 24 + 25 + vec P; //point on the plane 26 + vec N; //plane normal 27 + 28 + CUDA_CALLABLE void init(){ 29 + P = vec(0, 0, 0); 30 + N = vec(0, 0, 1); 31 + } 32 + 33 + 34 +public: 35 + 36 + //default constructor 37 + CUDA_CALLABLE plane(){ 38 + init(); 39 + } 40 + 41 + CUDA_CALLABLE plane(vec n, vec p = vec(0, 0, 0)){ 42 + P = p; 43 + N = n.norm(); 44 + } 45 + 46 + CUDA_CALLABLE plane(T z_pos){ 47 + init(); 48 + P[2] = z_pos; 49 + } 50 + 51 + //create a plane from three points (a triangle) 52 + CUDA_CALLABLE plane(vec a, vec b, vec c){ 53 + P = c; 54 + N = (c - a).cross(b - a); 55 + if(N.len() == 0) //handle the degenerate case when two vectors are the same, N = 0 56 + N = 0; 57 + else 58 + N = N.norm(); 59 + } 60 + 61 + CUDA_CALLABLE vec norm(){ 62 + return N; 63 + } 64 + 65 + CUDA_CALLABLE vec p(){ 66 + return P; 67 + } 68 + 69 + //flip the plane front-to-back 70 + CUDA_CALLABLE plane flip(){ 71 + plane result = *this; 72 + result.N = -result.N; 73 + return result; 74 + } 75 + 76 + //determines how a vector v intersects the plane (1 = intersects front, 0 = within plane, -1 = intersects back) 77 + CUDA_CALLABLE int face(vec v){ 78 + 79 + T dprod = v.dot(N); //get the dot product between v and N 80 + 81 + //conditional returns the appropriate value 82 + if(dprod < 0) 83 + return 1; 84 + else if(dprod > 0) 85 + return -1; 86 + else 87 + return 0; 88 + } 89 + 90 + //determine on which side of the plane a point lies (1 = front, 0 = on the plane, -1 = back) 91 + CUDA_CALLABLE int side(vec p){ 92 + 93 + vec v = p - P; //get the vector from P to the query point p 94 + 95 + return face(v); 96 + } 97 + 98 + //compute the component of v that is perpendicular to the plane 99 + CUDA_CALLABLE vec perpendicular(vec v){ 100 + return N * v.dot(N); 101 + } 102 + 103 + //compute the projection of v in the plane 104 + CUDA_CALLABLE vec parallel(vec v){ 105 + return v - perpendicular(v); 106 + } 107 + 108 + //get both the parallel and perpendicular components of a vector v w.r.t. the plane 109 + CUDA_CALLABLE void project(vec v, vec &v_par, vec &v_perp){ 110 + 111 + v_perp = v.dot(N); 112 + v_par = v - v_perp; 113 + } 114 + 115 + //compute the reflection of v off of the plane 116 + CUDA_CALLABLE vec reflect(vec v){ 117 + 118 + //compute the reflection using N_prime as the plane normal 119 + vec par = parallel(v); 120 + vec r = (-v) + par * 2; 121 + 122 + /*std::cout<<"----------------REFLECT-----------------------------"< operator- <> (rts::plane v); 142 + 143 + 144 + 145 +}; 146 + 147 +} 148 + 149 +//arithmetic operators 150 + 151 +//negative operator flips the plane (front to back) 152 +template 153 +CUDA_CALLABLE rts::plane operator-(rts::plane p_rhs) 154 +{ 155 + rts::plane p = p_rhs; 156 + 157 + //negate the normal vector 158 + p.N = -p.N; 159 + 160 + return p; 161 +} 162 + 163 + 164 + 165 +#endif 0 166 \ No newline at end of file ... ...
math/realfield.cuh

 ... ... @@ -84,7 +84,7 @@ public: 84 84 { 85 85 R[0] = R[1] = 0; 86 86 init(); 87 - std::cout<<"realfield CONSTRUCTOR"<(vec

(-1, -1, 0), vec

(-1, 1, 0), vec

(1, 1, 0)); //default geometry 100 100 clear(); //zero the field 101 - std::cout<<"realfield CONSTRUCTOR"<

math/vector.h

 ... ... @@ -26,9 +26,10 @@ struct vec 26 26 } 27 27 28 28 //efficiency constructor, makes construction easier for 1D-4D vectors 29 - CUDA_CALLABLE vec(T x) 29 + CUDA_CALLABLE vec(T rhs) 30 30 { 31 - v[0] = x; 31 + for(int i=0; i& other){ 55 + for(int i=0; i operator+(vec rhs) const 137 139 { 138 - vec result; 140 + vec result; 139 141 140 - for(int i=0; i operator+(T rhs) const 148 + { 149 + vec result; 150 + 151 + for(int i=0; i operator-(vec rhs) const 146 157 { ... ... @@ -174,15 +185,21 @@ struct vec 174 185 v[i] = v[i] * rhs; 175 186 return *this; 176 187 } 188 + CUDA_CALLABLE vec & operator=(T rhs){ 189 + for(int i=0; i operator-() const{ 195 + vec r; 177 196 178 - //conversion from a point 179 - /*CUDA_CALLABLE vector & operator=(point rhs) 180 - { 181 - for(int n=0; n rhs) const 188 205 { ... ... @@ -226,18 +243,7 @@ std::ostream& operator<<(std::ostream& os, rts::vec<T, N> v) 226 243 return os; 227 244 } 228 245 229 -//arithmetic operators 230 -template 231 -CUDA_CALLABLE rts::vec operator-(rts::vec v) 232 -{ 233 - rts::vec r; 234 - 235 - //negate the vector 236 - for(int i=0; i 243 249 CUDA_CALLABLE rts::vec operator*(T lhs, rts::vec rhs) ... ...
optics/beam.h

 ... ... @@ -16,10 +16,10 @@ public: 16 16 17 17 private: 18 18 19 - P na[2]; //numerical aperature of the focusing optics 19 + P _na[2]; //numerical aperature of the focusing optics 20 20 vec

f; //focal point 21 21 function apod; //apodization function 22 - unsigned int apod_res; //resolution of complex apodization filters 22 + unsigned int apod_res; //resolution of apodization filter functions 23 23 24 24 void apod_uniform() 25 25 { ... ... @@ -69,28 +69,44 @@ public: 69 69 70 70 ///constructor: build a default beam (NA=1.0) 71 71 beam( 72 - vec

_k = rts::vec

(0, 0, TAU), 72 + vec

k = rts::vec

(0, 0, rtsTAU), 73 73 vec

_E0 = rts::vec

(1, 0, 0), 74 74 beam_type _apod = Uniform) 75 - : planewave

(_k, _E0) 75 + : planewave

(k, _E0) 76 76 { 77 - na[0] = (P)0.0; 78 - na[1] = (P)1.0; 77 + _na[0] = (P)0.0; 78 + _na[1] = (P)1.0; 79 79 f = vec

( (P)0, (P)0, (P)0 ); 80 80 apod_res = 256; //set the default resolution for apodization filters 81 81 set_apod(_apod); //set the apodization function type 82 82 } 83 83 84 + beam

refract(rts::vec

kn) const{ 85 + 86 + beam

new_beam; 87 + new_beam._na[0] = _na[0]; 88 + new_beam._na[1] = _na[1]; 89 + 90 + 91 + rts::planewave

pw = planewave

::bend(kn); 92 + //std::cout<(0, 0, 1)); 118 134 rts::matrix rotation; 119 - if(cos_angle != 1.0) 135 + 136 + //if the cosine of the angle is -1, the rotation is just a flip across the z axis 137 + if(cos_angle == -1){ 138 + rotation(2, 2) = -1; 139 + } 140 + else if(cos_angle != 1.0) 120 141 { 121 142 rts::vec

r_axis = rts::vec

(0, 0, 1).cross(k_hat).norm(); //compute the axis of rotation 122 143 P angle = acos(cos_angle); //compute the angle of rotation ... ... @@ -127,8 +148,8 @@ public: 127 148 128 149 //find the phi values associated with the cassegrain ring 129 150 P PHI[2]; 130 - PHI[0] = (P)asin(na[0]); 131 - PHI[1] = (P)asin(na[1]); 151 + PHI[0] = (P)asin(_na[0]); 152 + PHI[1] = (P)asin(_na[1]); 132 153 133 154 //calculate the z-axis cylinder coordinates associated with these angles 134 155 P Z[2]; ... ... @@ -152,12 +173,28 @@ public: 152 173 vec

k_prime = rotation * cart; //create a sample vector 153 174 154 175 //store a wave refracted along the given direction 155 - samples.push_back(beam::refract(k_prime) * apod(phi/PHI[1])); 176 + //std::cout<<"k prime: "<::refract(k_prime) * apod(phi/PHI[1])); 156 178 } 157 179 158 180 return samples; 159 181 } 160 182 183 + std::string str() 184 + { 185 + std::stringstream ss; 186 + ss<<"Beam:"<

optics/efield.cuh

 ... ... @@ -8,7 +8,14 @@ 8 8 #include "../cuda/devices.h" 9 9 #include "../optics/beam.h" 10 10 11 +namespace rts{ 12 +template class halfspace; 11 13 14 +template class efield; 15 +} 16 + 17 +template 18 +void operator<<(rts::efield &ef, rts::halfspace hs); 12 19 13 20 namespace rts{ 14 21 ... ... @@ -63,6 +70,27 @@ __global__ void gpu_efield_magnitude(complex<T>* X, complex<T>* Y, complex<T>* Z 63 70 } 64 71 65 72 template 73 +__global__ void gpu_efield_real_magnitude(complex* X, complex* Y, complex* Z, unsigned int r0, unsigned int r1, T* M) 74 +{ 75 + int iu = blockIdx.x * blockDim.x + threadIdx.x; 76 + int iv = blockIdx.y * blockDim.y + threadIdx.y; 77 + 78 + //make sure that the thread indices are in-bounds 79 + if(iu >= r0 || iv >= r1) return; 80 + 81 + //compute the index into the field 82 + int i = iv*r0 + iu; 83 + 84 + if(Y == NULL) //if this is a scalar simulation 85 + M[i] = X[i].abs(); //compute the magnitude of the X component 86 + else 87 + { 88 + M[i] = rts::vec(X[i].real(), Y[i].real(), Z[i].real()).len(); 89 + //M[i] = Z[i].abs(); 90 + } 91 +} 92 + 93 +template 66 94 __global__ void gpu_efield_polarization(complex* X, complex* Y, complex* Z, 67 95 unsigned int r0, unsigned int r1, 68 96 T* Px, T* Py, T* Pz) ... ... @@ -79,6 +107,7 @@ __global__ void gpu_efield_polarization(complex<T>* X, complex<T>* Y, complex<T> 79 107 //compute the field polarization 80 108 Px[i] = X[i].abs(); 81 109 Py[i] = Y[i].abs(); 110 + 82 111 Pz[i] = Z[i].abs(); 83 112 } 84 113 ... ... @@ -146,7 +175,6 @@ protected: 146 175 147 176 if(vector) 148 177 { 149 - std::cout<<"vector:"; 150 178 cudaMalloc(&Y, sizeof(rts::complex

) * R[0] * R[1]); 151 179 cudaMemset(Y, 0, sizeof(rts::complex

) * R[0] * R[1]); 152 180 ... ... @@ -280,6 +308,7 @@ public: 280 308 return *this; //return this object 281 309 } 282 310 311 + //assignment operator: build an electric field from a beam 283 312 efield

& operator= (const rts::beam

& rhs) 284 313 { 285 314 //get a vector of monte-carlo samples ... ... @@ -311,6 +340,25 @@ public: 311 340 return M; 312 341 } 313 342 343 + //return a sacalar field representing the field magnitude at an infinitely small point in time 344 + realfield real_mag() 345 + { 346 + int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size 347 + int SQRT_BLOCK = (int)std::sqrt((float)maxThreads); 348 + 349 + //create a scalar field to store the result 350 + realfield M(R[0], R[1]); 351 + 352 + //create one thread for each detector pixel 353 + dim3 dimBlock(SQRT_BLOCK, SQRT_BLOCK); 354 + dim3 dimGrid((R[0] + SQRT_BLOCK -1)/SQRT_BLOCK, (R[1] + SQRT_BLOCK - 1)/SQRT_BLOCK); 355 + 356 + //compute the magnitude and store it in a scalar field 357 + gpu_efield_real_magnitude <<>> (X, Y, Z, R[0], R[1], M.ptr(0)); 358 + 359 + return M; 360 + } 361 + 314 362 //return a vector field representing field polarization 315 363 realfield polarization() 316 364 { ... ... @@ -335,6 +383,8 @@ public: 335 383 return Pol; //return the vector field 336 384 } 337 385 386 + ////////FRIENDSHIP 387 + friend void operator<< <>(rts::efield

&ef, rts::halfspace

hs); 338 388 339 389 340 390 }; ... ...

optics/esphere.cuh

 ... ... @@ -134,7 +134,7 @@ public: 134 134 calcAB(rhs.kmag(), Nl, A, B); //compute the scattering coefficients 135 135 136 136 //determine important parameters for the scattering domain 137 - unsigned int sR = ceil(sqrt( (P)(pow(esphere::R[0],2) + pow(esphere::R[1],2))) ); 137 + unsigned int sR = ceil(sqrt( (P)(pow((P)esphere::R[0],2) + pow((P)esphere::R[1],2))) ); 138 138 unsigned int thetaR = 256; 139 139 140 140 /////////////////////continue scattering code here///////////////////////// ... ...
optics/halfspace.cuh 0 โ 100644

 1 +#ifndef RTS_HALFSPACE_CUH 2 +#define RTS_HALFSPACE_CUH 3 + 4 +#include "../optics/halfspace.h" 5 +#include "../optics/efield.cuh" 6 + 7 +namespace rts{ 8 + 9 +template 10 +__global__ void gpu_halfspace_pw2ef(complex* X, complex* Y, complex* Z, unsigned int r0, unsigned int r1, 11 + plane P, planewave w, rect q, bool at_surface = false) 12 +{ 13 + int iu = blockIdx.x * blockDim.x + threadIdx.x; 14 + int iv = blockIdx.y * blockDim.y + threadIdx.y; 15 + 16 + //make sure that the thread indices are in-bounds 17 + if(iu >= r0 || iv >= r1) return; 18 + 19 + //compute the index into the field 20 + int i = iv*r0 + iu; 21 + 22 + //get the current position 23 + vec p = q( (T)iu/(T)r0, (T)iv/(T)r1 ); 24 + 25 + if(at_surface){ 26 + if(P.side(p) > 0) 27 + return; 28 + } 29 + else{ 30 + if(P.side(p) >= 0) 31 + return; 32 + } 33 + 34 + //if the current position is on the wrong side of the plane 35 + 36 + //vec r(p[0], p[1], p[2]); 37 + 38 + complex x( 0.0f, w.kvec().dot(p) ); 39 + complex phase( 0.0f, w.phase()); 40 + 41 + if(Y == NULL) //if this is a scalar simulation 42 + X[i] += w.E().len() * exp(x); //use the vector magnitude as the plane wave amplitude 43 + else 44 + { 45 + //X[i] = Y[i] = Z[i] = 1; 46 + X[i] += w.E()[0] * exp(x) * exp(phase); 47 + Y[i] += w.E()[1] * exp(x) * exp(phase); 48 + Z[i] += w.E()[2] * exp(x) * exp(phase); 49 + } 50 +} 51 +} 52 + 53 +template 54 +void operator<<(rts::efield &ef, rts::halfspace hs){ 55 + 56 + //std::cout<<"---------RENDER HALFSPACE--------------"< <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], hs.S, hs.w0[w], ef.pos); 74 + } 75 + 76 + //plane waves at the surface back 77 + for(unsigned int w = 0; w < hs.w1.size(); w++){ 78 + //std::cout<<"w1 "< <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], -hs.S, hs.w1[w], ef.pos, true); 80 + } 81 + //rts::gpu_halfspace_pw2ef <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], hs.S, hs.pi, ef.pos); 82 + //rts::gpu_halfspace_pw2ef <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], hs.S, hs.pr, ef.pos); 83 + //rts::gpu_halfspace_pw2ef <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], -hs.S, hs.pt, ef.pos, true); 84 + 85 + 86 + //return ef; 87 +} 88 + 89 + 90 + 91 +#endif 0 92 \ No newline at end of file ... ...
optics/halfspace.h 0 โ 100644

 1 +#ifndef RTS_HALFSPACE_H 2 +#define RTS_HALFSPACE_H 3 + 4 +namespace rts{ 5 +template class halfspace; 6 + 7 +template class efield; 8 +} 9 + 10 +template 11 +void operator<<(rts::efield &ef, rts::halfspace hs); 12 + 13 +namespace rts{ 14 + 15 +template 16 +class halfspace 17 +{ 18 +private: 19 + rts::plane S; //surface plane splitting the half space 20 + rts::complex n0; //refractive index at the front of the plane 21 + rts::complex n1; //refractive index at the back of the plane 22 + 23 + //lists of waves in front (pw0) and behind (pw1) the plane 24 + std::vector< rts::planewave > w0; 25 + std::vector< rts::planewave > w1; 26 + 27 + //rts::planewave pi; //incident plane wave 28 + //rts::planewave pr; //plane wave reflected from the surface 29 + //rts::planewave pt; //plane wave transmitted through the surface 30 + 31 + void init(){ 32 + n0 = 1.0; 33 + n1 = 1.5; 34 + } 35 + 36 + //compute which side of the interface is hit by the incoming plane wave (0 = front, 1 = back) 37 + bool facing(planewave p){ 38 + if(p.kvec().dot(S.norm()) > 0) 39 + return 1; 40 + else 41 + return 0; 42 + } 43 + 44 + T calc_theta_i(vec v){ 45 + 46 + vec v_hat = v.norm(); 47 + 48 + //compute the cosine of the angle between k_hat and the plane normal 49 + T cos_theta_i = v_hat.dot(S.norm()); 50 + 51 + return acos(abs(cos_theta_i)); 52 + } 53 + 54 + T calc_theta_t(T ni_nt, T theta_i){ 55 + 56 + T sin_theta_t = ni_nt * sin(theta_i); 57 + return asin(sin_theta_t); 58 + } 59 + 60 + 61 +public: 62 + 63 + //constructors 64 + halfspace(){ 65 + init(); 66 + } 67 + 68 + halfspace(T na, T nb){ 69 + init(); 70 + n0 = na; 71 + n1 = nb; 72 + } 73 + 74 + halfspace(T na, T nb, plane p){ 75 + n0 = na; 76 + n1 = nb; 77 + S = p; 78 + } 79 + 80 + //compute the transmitted and reflective waves given the incident (vacuum) plane wave p 81 + void incident(rts::planewave p){ 82 + 83 + planewave r, t; 84 + p.scatter(S, n1.real()/n0.real(), r, t); 85 + 86 + //std::cout<<"i+r: "< b, unsigned int N = 10000){ 108 + 109 + //generate a plane wave decomposition for the beam 110 + std::vector< planewave > pw_list = b.mc(N); 111 + 112 + //calculate the reflected and refracted waves for each incident wave 113 + for(unsigned int w = 0; w < pw_list.size(); w++){ 114 + incident(pw_list[w]); 115 + } 116 + } 117 + 118 + std::string str(){ 119 + std::stringstream ss; 120 + ss<<"Half Space-------------"< (rts::efield &ef, rts::halfspace hs); 140 + 141 +}; 142 + 143 + 144 + 145 + 146 +} 147 + 148 + 149 +#endif 0 150 \ No newline at end of file ... ...
optics/planewave.h

 ... ... @@ -7,6 +7,8 @@ 7 7 #include "../math/vector.h" 8 8 #include "../math/quaternion.h" 9 9 #include "../math/constants.h" 10 +#include "../math/plane.h" 11 +#include "rts/cuda/callable.h" 10 12 11 13 /*Basic conversions used here (assuming a vacuum) 12 14 lambda = ... ... @@ -14,160 +16,299 @@ 14 16 15 17 namespace rts{ 16 18 17 -template 19 +template 18 20 class planewave{ 19 21 22 +protected: 23 + 24 + vec k; //k = tau / lambda 25 + vec E0; //amplitude 26 + T phi; 27 + 28 + planewave bend(rts::vec kn) const{ 29 + 30 + vec kn_hat = kn.norm(); //normalize the new k 31 + vec k_hat = k.norm(); //normalize the current k 32 + 33 + //std::cout<<"PLANE WAVE BENDING------------------"< new_p; //create a new plane wave 37 + 38 + //if kn is equal to k or -k, handle the degenerate case 39 + T k_dot_kn = k_hat.dot(kn_hat); 40 + 41 + //if k . n < 0, then the bend is a reflection 42 + //flip k_hat 43 + if(k_dot_kn < 0) k_hat = -k_hat; 44 + 45 + //std::cout<<"k dot kn: "< r = k_hat.cross(kn_hat); //compute the rotation vector 60 + 61 + //std::cout<<"r: "< q; 76 + q.CreateRotation(theta, r.norm()); 77 + 78 + //apply the rotation to E0 79 + vec E0n = q.toMatrix3() * E0; 80 + 81 + new_p.k = kn_hat * kmag(); 82 + new_p.E0 = E0n; 83 + 84 + return new_p; 85 + } 86 + 20 87 public: 21 - vec

k; //k = tau / lambda 22 - vec

E0; //amplitude 23 88 24 89 25 90 ///constructor: create a plane wave propagating along z, polarized along x 26 - /*planewave(P lambda = (P)1) 91 + /*planewave(T lambda = (T)1) 27 92 { 28 - k = rts::vec

(0, 0, 1) * (TAU/lambda); 29 - E0 = rts::vec

(1, 0, 0); 93 + k = rts::vec(0, 0, 1) * (TAU/lambda); 94 + E0 = rts::vec(1, 0, 0); 30 95 }*/ 31 - ///constructor: create a plane wave propagating along _k, polarized along _E0, at frequency _omega 32 - planewave(vec

_k = rts::vec

(0, 0, TAU), vec

_E0 = rts::vec

(1, 0, 0)) 96 + ///constructor: create a plane wave propagating along k, polarized along _E0, at frequency _omega 97 + CUDA_CALLABLE planewave(vec kvec = rts::vec(0, 0, rtsTAU), 98 + vec E = rts::vec(1, 0, 0), 99 + T phase = 0) 33 100 { 34 - k = _k; 35 - vec

k_hat = _k.norm(); 36 - 37 - vec

s = (k.cross(_E0)).norm(); //compute an orthogonal side vector 38 - vec

E0_hat = (s.cross(k)).norm(); //compute a normalized E0 direction vector 39 - E0 = E0_hat * E0_hat.dot(_E0); //compute the projection of _E0 onto E0_hat 101 + phi = phase; 102 + k = kvec; 103 + vec k_hat = k.norm(); 104 + 105 + if(E.len() == 0) //if the plane wave has an amplitude of 0 106 + E0 = vec(0); //just return it 107 + else{ 108 + vec s = (k.cross(E)).norm(); //compute an orthogonal side vector 109 + vec E_hat = (s.cross(k)).norm(); //compute a normalized E0 direction vector 110 + E0 = E_hat * E_hat.dot(E); //compute the projection of _E0 onto E0_hat 111 + } 40 112 } 41 113 42 114 ///multiplication operator: scale E0 43 - planewave

& operator* (const P & rhs) 115 + CUDA_CALLABLE planewave & operator* (const T & rhs) 44 116 { 45 117 46 118 E0 = E0 * rhs; 47 119 return *this; 48 120 } 49 121 50 - P lambda() const 122 + CUDA_CALLABLE T lambda() const 51 123 { 52 - return TAU / k.len(); 124 + return rtsTAU / k.len(); 53 125 } 54 126 55 - P kmag() const 127 + CUDA_CALLABLE T kmag() const 56 128 { 57 129 return k.len(); 58 130 } 59 131 132 + CUDA_CALLABLE vec E(){ 133 + return E0; 134 + } 135 + 136 + CUDA_CALLABLE vec kvec(){ 137 + return k; 138 + } 139 + 140 + CUDA_CALLABLE T phase(){ 141 + return phi; 142 + } 143 + 144 + CUDA_CALLABLE void phase(T p){ 145 + phi = p; 146 + } 147 + 148 + CUDA_CALLABLE vec< complex > pos(vec p = vec(0, 0, 0)){ 149 + vec< complex > result; 150 + 151 + T kdp = k.dot(p); 152 + complex x = complex(0, kdp); 153 + complex expx = exp(x); 154 + 155 + result[0] = E0[0] * expx; 156 + result[1] = E0[1] * expx; 157 + result[2] = E0[2] * expx; 158 + 159 + return result; 160 + } 161 + 162 + //scales k based on a transition from material ni to material nt 163 + CUDA_CALLABLE planewave n(T ni, T nt){ 164 + return planewave(k * (nt / ni), E0); 165 + } 60 166 61 - planewave

refract(rts::vec

kn) const 167 + CUDA_CALLABLE planewave refract(rts::vec kn) const 62 168 { 63 - vec

kn_hat = kn.norm(); //normalize the new k 64 - vec

k_hat = k.norm(); //normalize the current k 169 + return bend(kn); 170 + } 65 171 66 - vec

r = k_hat.cross(kn_hat); //compute the rotation vector 172 + void scatter(rts::plane P, T nr, planewave &r, planewave &t){ 67 173 68 - P theta = asin(r.len()); //compute the angle of the rotation about r 174 + int facing = P.face(k); //determine which direction the plane wave is coming in 69 175 70 - planewave

new_p; //create a new plane wave 176 + //if(facing == 0) //if the wave is tangent to the plane, return an identical wave 177 + // return *this; 178 + //else 179 + if(facing == -1){ //if the wave hits the back of the plane, invert the plane and nr 180 + P = P.flip(); //flip the plane 181 + nr = 1/nr; //invert the refractive index (now nr = n0/n1) 182 + } 71 183 72 - //deal with a zero vector (both k and kn point in the same direction) 73 - if(theta == (P)0) 74 - { 75 - new_p = *this; 76 - return new_p; 184 + //use Snell's Law to calculate the transmitted angle 185 + T cos_theta_i = k.norm().dot(-P.norm()); //compute the cosine of theta_i 186 + T theta_i = acos(cos_theta_i); //compute theta_i 187 + T sin_theta_t = (1/nr) * sin(theta_i); //compute the sine of theta_t using Snell's law 188 + T theta_t = asin(sin_theta_t); //compute the cosine of theta_t 189 + 190 + bool tir = false; //flag for total internal reflection 191 + if(theta_t != theta_t){ 192 + tir = true; 193 + theta_t = rtsPI / (T)2; 77 194 } 78 195 79 - //create a quaternion to capture the rotation 80 - quaternion

q; 81 - q.CreateRotation(theta, r.norm()); 196 + //handle the degenerate case where theta_i is 0 (the plane wave hits head-on) 197 + if(theta_i == 0){ 198 + T rp = (1 - nr) / (1 + nr); //compute the Fresnel coefficients 199 + T tp = 2 / (1 + nr); 200 + vec kr = -k; 201 + vec kt = k * nr; //set the k vectors for theta_i = 0 202 + vec Er = E0 * rp; //compute the E vectors 203 + vec Et = E0 * tp; 204 + T phase_t = P.p().dot(k - kt); //compute the phase offset 205 + T phase_r = P.p().dot(k - kr); 206 + //std::cout<<"Degeneracy: Head-On"<(kr, Er, phase_r); 212 + t = planewave(kt, Et, phase_t); 213 + 214 + //std::cout<<"i + r: "< E0n = q.toMatrix3() * E0; 85 220 86 - new_p.k = kn_hat * k.len(); 87 - new_p.E0 = E0n; 221 + //compute the Fresnel coefficients 222 + T rp, rs, tp, ts; 223 + rp = tan(theta_t - theta_i) / tan(theta_t + theta_i); 224 + rs = sin(theta_t - theta_i) / sin(theta_t + theta_i); 225 + 226 + if(tir){ 227 + tp = ts = 0; 228 + } 229 + else{ 230 + tp = ( 2 * sin(theta_t) * cos(theta_i) ) / ( sin(theta_t + theta_i) * cos(theta_t - theta_i) ); 231 + ts = ( 2 * sin(theta_t) * cos(theta_i) ) / sin(theta_t + theta_i); 232 + } 88 233 89 - return new_p; 234 + //compute the coordinate space for the plane of incidence 235 + vec z_hat = -P.norm(); 236 + vec y_hat = P.parallel(k).norm(); 237 + vec x_hat = y_hat.cross(z_hat).norm(); 238 + 239 + //compute the k vectors for r and t 240 + vec kr, kt; 241 + kr = ( y_hat * sin(theta_i) - z_hat * cos(theta_i) ) * kmag(); 242 + kt = ( y_hat * sin(theta_t) + z_hat * cos(theta_t) ) * kmag() * nr; 243 + 244 + //compute the magnitude of the p- and s-polarized components of the incident E vector 245 + T Ei_s = E0.dot(x_hat); 246 + int sgn = (0 < E0.dot(y_hat)) - (E0.dot(y_hat) < 0); 247 + T Ei_p = sgn * ( E0 - x_hat * Ei_s ).len(); 248 + //T Ei_p = ( E0 - x_hat * Ei_s ).len(); 249 + //compute the magnitude of the p- and s-polarized components of the reflected E vector 250 + T Er_s = Ei_s * rs; 251 + T Er_p = Ei_p * rp; 252 + //compute the magnitude of the p- and s-polarized components of the transmitted E vector 253 + T Et_s = Ei_s * ts; 254 + T Et_p = Ei_p * tp; 255 + 256 + //std::cout<<"E0: "< Er = (y_hat * cos(theta_i) + z_hat * sin(theta_i)) * Er_p + x_hat * Er_s; 266 + //compute the transmitted E vector 267 + vec Et = (y_hat * cos(theta_t) - z_hat * sin(theta_t)) * Et_p + x_hat * Et_s; 268 + 269 + T phase_t = P.p().dot(k - kt); 270 + T phase_r = P.p().dot(k - kr); 271 + 272 + //std::cout<<"phase r: "< kn_hat = kn.norm(); //normalize new_k 92 - vec

k_hat = k.norm(); 93 - 94 - //compute the side vector (around which we will be rotating) 95 - vec

E0_hat = E0.norm(); 96 - rts::vec

s = k_hat.cross(E0_hat); 97 - 98 - //compute the projection of k' onto the k-E plane 99 - rts::vec

s_prime = s * (kn_hat.dot(s)); 100 - 101 - //compute the angle between 102 - vec

kp_hat = (kn_hat - s_prime).norm(); 103 - P theta = acos(k_hat.dot( kp_hat )); 104 - if(kn_hat.dot(E0_hat) < 0) 105 - theta = -theta; 106 - 107 - //rotate E0 around s by theta 108 - quaternion

q; 109 - q.CreateRotation(theta, s); 110 - rts::vec

E0_prime = q.toMatrix3() * E0; 111 - 112 - //create the refracted plane wave 113 - planewave

new_p; 114 - new_p.E0 = E0_prime; 115 - new_p.k = kn_hat * k.len(); 116 - 117 - return new_p;*/ 118 - 119 - /*vec

kn_hat = kn.norm(); //normalize kn 120 - vec

k_hat = k.norm(); 121 - vec

E0_hat = E0.norm(); 122 - 123 - vec

B = k_hat.cross(E0_hat); 124 - planewave

newp; 125 - newp.k = kn_hat * k.len(); 126 - newp.E0 = B.cross(kn_hat).norm(); 127 - std::cout< s_hat = k_hat.cross(E0_hat); 132 - //std::cout< sp = s_hat * (kn_hat.dot(s_hat)); //project k_new onto s 136 - rts::vec

kp = (kn_hat - sp); //correct k_new so it lies on the E0-k plane 137 - rts::vec

kp_hat = kp.norm(); 138 - 139 - //compute the angle and direction between k_prime and k 140 - P theta = acos(k_hat.dot(kp_hat)); 141 - if(kp_hat.dot(E0_hat) < 0) 142 - theta = -theta; 143 - 144 - //rotate E0 around s by theta 145 - quaternion

q; 146 - q.CreateRotation(theta, s_hat); 147 - rts::vec

E0n = q.toMatrix3() * E0; 148 - rts::vec

E0n_hat = E0n.norm(); 149 - 150 - //std::cout< new_p(kn_hat * k.len(), E0n); //create the plane wave 159 - std::cout<<"|E0n|: "< 308 +std::ostream& operator<<(std::ostream& os, rts::planewave p) 309 +{ 310 + os<