From 559d0fcbc33712d4de94f257b6b2718ab9f5c729 Mon Sep 17 00:00:00 2001 From: David Mayerich Date: Fri, 25 Jul 2014 16:32:36 -0500 Subject: [PATCH] wave interactions with a planar surface --- math/bessel.h | 84 ++++++++++++++++++++++++++++++++++++++++++------------------------------------------ math/complex.h | 16 +++++++++------- math/constants.h | 7 ++----- math/plane.h | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ math/realfield.cuh | 10 +++++----- math/vector.h | 60 +++++++++++++++++++++++++++++++++--------------------------- optics/beam.h | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- optics/efield.cuh | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- optics/esphere.cuh | 2 +- optics/halfspace.cuh | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ optics/halfspace.h | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ optics/planewave.h | 359 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------- 12 files changed, 851 insertions(+), 213 deletions(-) create mode 100644 math/plane.h create mode 100644 optics/halfspace.cuh create mode 100644 optics/halfspace.h diff --git a/math/bessel.h b/math/bessel.h index 88bf4bf..9d12b8b 100644 --- a/math/bessel.h +++ b/math/bessel.h @@ -759,28 +759,28 @@ int bessjyv(P v,P x,P &vm,P *jv,P *yv, } vm = n + v0; return 0; -} - -template +} + +template int bessjyv_sph(int v, P z, P &vm, P* cjv, - P* cyv, P* cjvp, P* cyvp) -{ - //first, compute the bessel functions of fractional order - bessjyv(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); - - //iterate through each and scale - for(int n = 0; n<=v; n++) - { - - cjv[n] = cjv[n] * sqrt(PI/(z * 2.0)); - cyv[n] = cyv[n] * sqrt(PI/(z * 2.0)); - - cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(PI / (z * 2.0)); - cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(PI / (z * 2.0)); - } - - return 0; - + P* cyv, P* cjvp, P* cyvp) +{ + //first, compute the bessel functions of fractional order + bessjyv(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); + + //iterate through each and scale + for(int n = 0; n<=v; n++) + { + + cjv[n] = cjv[n] * sqrt(rtsPI/(z * 2.0)); + cyv[n] = cyv[n] * sqrt(rtsPI/(z * 2.0)); + + cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(rtsPI / (z * 2.0)); + cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(rtsPI / (z * 2.0)); + } + + return 0; + } template @@ -1485,28 +1485,28 @@ int cbessjyva(P v,complex

z,P &vm,complex

*cjv, } vm = n+v0; return 0; -} - -template +} + +template int cbessjyva_sph(int v,complex

z,P &vm,complex

*cjv, - complex

*cyv,complex

*cjvp,complex

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

(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); - - //iterate through each and scale - for(int n = 0; n<=v; n++) - { - - cjv[n] = cjv[n] * sqrt(PI/(z * 2.0)); - cyv[n] = cyv[n] * sqrt(PI/(z * 2.0)); - - cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(PI / (z * 2.0)); - cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(PI / (z * 2.0)); - } - - return 0; - + complex

*cyv,complex

*cjvp,complex

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

(v + 0.5, z, vm, cjv, cyv, cjvp, cyvp); + + //iterate through each and scale + for(int n = 0; n<=v; n++) + { + + cjv[n] = cjv[n] * sqrt(rtsPI/(z * 2.0)); + cyv[n] = cyv[n] * sqrt(rtsPI/(z * 2.0)); + + cjvp[n] = -1.0 / (z * 2.0) * cjv[n] + cjvp[n] * sqrt(rtsPI / (z * 2.0)); + cyvp[n] = -1.0 / (z * 2.0) * cyv[n] + cyvp[n] * sqrt(rtsPI / (z * 2.0)); + } + + return 0; + } } //end namespace rts diff --git a/math/complex.h b/math/complex.h index 12f7975..e5414be 100644 --- a/math/complex.h +++ b/math/complex.h @@ -23,7 +23,14 @@ struct complex CUDA_CALLABLE complex() { r = 0; - i = 0; + i = 0; + } + + //constructor when given real and imaginary values + CUDA_CALLABLE complex(T r, T i = 0) + { + this->r = r; + this->i = i; } //access methods @@ -48,12 +55,7 @@ struct complex return i_val; } - //constructor when given real and imaginary values - CUDA_CALLABLE complex(T r, T i) - { - this->r = r; - this->i = i; - } + //return the current value multiplied by i CUDA_CALLABLE complex imul() diff --git a/math/constants.h b/math/constants.h index 598c152..3dae3a5 100644 --- a/math/constants.h +++ b/math/constants.h @@ -1,10 +1,7 @@ #ifndef RTS_CONSTANTS_H #define RTS_CONSTANTS_H -namespace rts{ - - double PI = 3.14159; - double TAU = 2 * PI; -} +#define rtsPI 3.14159 +#define rtsTAU 2 * rtsPI #endif \ No newline at end of file diff --git a/math/plane.h b/math/plane.h new file mode 100644 index 0000000..f7753ac --- /dev/null +++ b/math/plane.h @@ -0,0 +1,165 @@ +#ifndef RTS_PLANE_H +#define RTS_PLANE_H + +#include +#include "../math/vector.h" +#include "rts/cuda/callable.h" + + +namespace rts{ +template class plane; +} + +template +CUDA_CALLABLE rts::plane operator-(rts::plane v); + +namespace rts{ + +template +class plane{ + + //a plane is defined by a point and a normal + +private: + + vec P; //point on the plane + vec N; //plane normal + + CUDA_CALLABLE void init(){ + P = vec(0, 0, 0); + N = vec(0, 0, 1); + } + + +public: + + //default constructor + CUDA_CALLABLE plane(){ + init(); + } + + CUDA_CALLABLE plane(vec n, vec p = vec(0, 0, 0)){ + P = p; + N = n.norm(); + } + + CUDA_CALLABLE plane(T z_pos){ + init(); + P[2] = z_pos; + } + + //create a plane from three points (a triangle) + CUDA_CALLABLE plane(vec a, vec b, vec c){ + P = c; + N = (c - a).cross(b - a); + if(N.len() == 0) //handle the degenerate case when two vectors are the same, N = 0 + N = 0; + else + N = N.norm(); + } + + CUDA_CALLABLE vec norm(){ + return N; + } + + CUDA_CALLABLE vec p(){ + return P; + } + + //flip the plane front-to-back + CUDA_CALLABLE plane flip(){ + plane result = *this; + result.N = -result.N; + return result; + } + + //determines how a vector v intersects the plane (1 = intersects front, 0 = within plane, -1 = intersects back) + CUDA_CALLABLE int face(vec v){ + + T dprod = v.dot(N); //get the dot product between v and N + + //conditional returns the appropriate value + if(dprod < 0) + return 1; + else if(dprod > 0) + return -1; + else + return 0; + } + + //determine on which side of the plane a point lies (1 = front, 0 = on the plane, -1 = back) + CUDA_CALLABLE int side(vec p){ + + vec v = p - P; //get the vector from P to the query point p + + return face(v); + } + + //compute the component of v that is perpendicular to the plane + CUDA_CALLABLE vec perpendicular(vec v){ + return N * v.dot(N); + } + + //compute the projection of v in the plane + CUDA_CALLABLE vec parallel(vec v){ + return v - perpendicular(v); + } + + //get both the parallel and perpendicular components of a vector v w.r.t. the plane + CUDA_CALLABLE void project(vec v, vec &v_par, vec &v_perp){ + + v_perp = v.dot(N); + v_par = v - v_perp; + } + + //compute the reflection of v off of the plane + CUDA_CALLABLE vec reflect(vec v){ + + //compute the reflection using N_prime as the plane normal + vec par = parallel(v); + vec r = (-v) + par * 2; + + /*std::cout<<"----------------REFLECT-----------------------------"< operator- <> (rts::plane v); + + + +}; + +} + +//arithmetic operators + +//negative operator flips the plane (front to back) +template +CUDA_CALLABLE rts::plane operator-(rts::plane p_rhs) +{ + rts::plane p = p_rhs; + + //negate the normal vector + p.N = -p.N; + + return p; +} + + + +#endif \ No newline at end of file diff --git a/math/realfield.cuh b/math/realfield.cuh index 5a1d906..8e0c459 100644 --- a/math/realfield.cuh +++ b/math/realfield.cuh @@ -84,7 +84,7 @@ public: { R[0] = R[1] = 0; init(); - std::cout<<"realfield CONSTRUCTOR"<(vec

(-1, -1, 0), vec

(-1, 1, 0), vec

(1, 1, 0)); //default geometry clear(); //zero the field - std::cout<<"realfield CONSTRUCTOR"<& other){ + for(int i=0; i operator+(vec rhs) const { - vec result; + vec result; - for(int i=0; i operator+(T rhs) const + { + vec result; + + for(int i=0; i operator-(vec rhs) const { @@ -174,15 +185,21 @@ struct vec v[i] = v[i] * rhs; return *this; } + CUDA_CALLABLE vec & operator=(T rhs){ + for(int i=0; i operator-() const{ + vec r; - //conversion from a point - /*CUDA_CALLABLE vector & operator=(point rhs) - { - for(int n=0; n rhs) const { @@ -226,18 +243,7 @@ std::ostream& operator<<(std::ostream& os, rts::vec v) return os; } -//arithmetic operators -template -CUDA_CALLABLE rts::vec operator-(rts::vec v) -{ - rts::vec r; - - //negate the vector - for(int i=0; i CUDA_CALLABLE rts::vec operator*(T lhs, rts::vec rhs) diff --git a/optics/beam.h b/optics/beam.h index 9e86f4c..eb8ac15 100644 --- a/optics/beam.h +++ b/optics/beam.h @@ -16,10 +16,10 @@ public: private: - P na[2]; //numerical aperature of the focusing optics + P _na[2]; //numerical aperature of the focusing optics vec

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

_k = rts::vec

(0, 0, TAU), + vec

k = rts::vec

(0, 0, rtsTAU), vec

_E0 = rts::vec

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

(_k, _E0) + : planewave

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

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

refract(rts::vec

kn) const{ + + beam

new_beam; + new_beam._na[0] = _na[0]; + new_beam._na[1] = _na[1]; + + + rts::planewave

pw = planewave

::bend(kn); + //std::cout<(0, 0, 1)); rts::matrix rotation; - if(cos_angle != 1.0) + + //if the cosine of the angle is -1, the rotation is just a flip across the z axis + if(cos_angle == -1){ + rotation(2, 2) = -1; + } + else if(cos_angle != 1.0) { rts::vec

r_axis = rts::vec

(0, 0, 1).cross(k_hat).norm(); //compute the axis of rotation P angle = acos(cos_angle); //compute the angle of rotation @@ -127,8 +148,8 @@ public: //find the phi values associated with the cassegrain ring P PHI[2]; - PHI[0] = (P)asin(na[0]); - PHI[1] = (P)asin(na[1]); + PHI[0] = (P)asin(_na[0]); + PHI[1] = (P)asin(_na[1]); //calculate the z-axis cylinder coordinates associated with these angles P Z[2]; @@ -152,12 +173,28 @@ public: vec

k_prime = rotation * cart; //create a sample vector //store a wave refracted along the given direction - samples.push_back(beam::refract(k_prime) * apod(phi/PHI[1])); + //std::cout<<"k prime: "<::refract(k_prime) * apod(phi/PHI[1])); } return samples; } + std::string str() + { + std::stringstream ss; + ss<<"Beam:"< class halfspace; +template class efield; +} + +template +void operator<<(rts::efield &ef, rts::halfspace hs); namespace rts{ @@ -63,6 +70,27 @@ __global__ void gpu_efield_magnitude(complex* X, complex* Y, complex* Z } template +__global__ void gpu_efield_real_magnitude(complex* X, complex* Y, complex* Z, unsigned int r0, unsigned int r1, T* M) +{ + int iu = blockIdx.x * blockDim.x + threadIdx.x; + int iv = blockIdx.y * blockDim.y + threadIdx.y; + + //make sure that the thread indices are in-bounds + if(iu >= r0 || iv >= r1) return; + + //compute the index into the field + int i = iv*r0 + iu; + + if(Y == NULL) //if this is a scalar simulation + M[i] = X[i].abs(); //compute the magnitude of the X component + else + { + M[i] = rts::vec(X[i].real(), Y[i].real(), Z[i].real()).len(); + //M[i] = Z[i].abs(); + } +} + +template __global__ void gpu_efield_polarization(complex* X, complex* Y, complex* Z, unsigned int r0, unsigned int r1, T* Px, T* Py, T* Pz) @@ -79,6 +107,7 @@ __global__ void gpu_efield_polarization(complex* X, complex* Y, complex //compute the field polarization Px[i] = X[i].abs(); Py[i] = Y[i].abs(); + Pz[i] = Z[i].abs(); } @@ -146,7 +175,6 @@ protected: if(vector) { - std::cout<<"vector:"; cudaMalloc(&Y, sizeof(rts::complex

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

) * R[0] * R[1]); @@ -280,6 +308,7 @@ public: return *this; //return this object } + //assignment operator: build an electric field from a beam efield

& operator= (const rts::beam

& rhs) { //get a vector of monte-carlo samples @@ -311,6 +340,25 @@ public: return M; } + //return a sacalar field representing the field magnitude at an infinitely small point in time + realfield real_mag() + { + int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size + int SQRT_BLOCK = (int)std::sqrt((float)maxThreads); + + //create a scalar field to store the result + realfield M(R[0], R[1]); + + //create one thread for each detector pixel + dim3 dimBlock(SQRT_BLOCK, SQRT_BLOCK); + dim3 dimGrid((R[0] + SQRT_BLOCK -1)/SQRT_BLOCK, (R[1] + SQRT_BLOCK - 1)/SQRT_BLOCK); + + //compute the magnitude and store it in a scalar field + gpu_efield_real_magnitude <<>> (X, Y, Z, R[0], R[1], M.ptr(0)); + + return M; + } + //return a vector field representing field polarization realfield polarization() { @@ -335,6 +383,8 @@ public: return Pol; //return the vector field } + ////////FRIENDSHIP + friend void operator<< <>(rts::efield

&ef, rts::halfspace

hs); }; diff --git a/optics/esphere.cuh b/optics/esphere.cuh index 066102d..5ac31c1 100644 --- a/optics/esphere.cuh +++ b/optics/esphere.cuh @@ -134,7 +134,7 @@ public: calcAB(rhs.kmag(), Nl, A, B); //compute the scattering coefficients //determine important parameters for the scattering domain - unsigned int sR = ceil(sqrt( (P)(pow(esphere::R[0],2) + pow(esphere::R[1],2))) ); + unsigned int sR = ceil(sqrt( (P)(pow((P)esphere::R[0],2) + pow((P)esphere::R[1],2))) ); unsigned int thetaR = 256; /////////////////////continue scattering code here///////////////////////// diff --git a/optics/halfspace.cuh b/optics/halfspace.cuh new file mode 100644 index 0000000..1b8e02e --- /dev/null +++ b/optics/halfspace.cuh @@ -0,0 +1,91 @@ +#ifndef RTS_HALFSPACE_CUH +#define RTS_HALFSPACE_CUH + +#include "../optics/halfspace.h" +#include "../optics/efield.cuh" + +namespace rts{ + +template +__global__ void gpu_halfspace_pw2ef(complex* X, complex* Y, complex* Z, unsigned int r0, unsigned int r1, + plane P, planewave w, rect q, bool at_surface = false) +{ + int iu = blockIdx.x * blockDim.x + threadIdx.x; + int iv = blockIdx.y * blockDim.y + threadIdx.y; + + //make sure that the thread indices are in-bounds + if(iu >= r0 || iv >= r1) return; + + //compute the index into the field + int i = iv*r0 + iu; + + //get the current position + vec p = q( (T)iu/(T)r0, (T)iv/(T)r1 ); + + if(at_surface){ + if(P.side(p) > 0) + return; + } + else{ + if(P.side(p) >= 0) + return; + } + + //if the current position is on the wrong side of the plane + + //vec r(p[0], p[1], p[2]); + + complex x( 0.0f, w.kvec().dot(p) ); + complex phase( 0.0f, w.phase()); + + if(Y == NULL) //if this is a scalar simulation + X[i] += w.E().len() * exp(x); //use the vector magnitude as the plane wave amplitude + else + { + //X[i] = Y[i] = Z[i] = 1; + X[i] += w.E()[0] * exp(x) * exp(phase); + Y[i] += w.E()[1] * exp(x) * exp(phase); + Z[i] += w.E()[2] * exp(x) * exp(phase); + } +} +} + +template +void operator<<(rts::efield &ef, rts::halfspace hs){ + + //std::cout<<"---------RENDER HALFSPACE--------------"< <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], hs.S, hs.w0[w], ef.pos); + } + + //plane waves at the surface back + for(unsigned int w = 0; w < hs.w1.size(); w++){ + //std::cout<<"w1 "< <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], -hs.S, hs.w1[w], ef.pos, true); + } + //rts::gpu_halfspace_pw2ef <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], hs.S, hs.pi, ef.pos); + //rts::gpu_halfspace_pw2ef <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], hs.S, hs.pr, ef.pos); + //rts::gpu_halfspace_pw2ef <<>> (ef.X, ef.Y, ef.Z, ef.R[0], ef.R[1], -hs.S, hs.pt, ef.pos, true); + + + //return ef; +} + + + +#endif \ No newline at end of file diff --git a/optics/halfspace.h b/optics/halfspace.h new file mode 100644 index 0000000..bb3c1e3 --- /dev/null +++ b/optics/halfspace.h @@ -0,0 +1,149 @@ +#ifndef RTS_HALFSPACE_H +#define RTS_HALFSPACE_H + +namespace rts{ +template class halfspace; + +template class efield; +} + +template +void operator<<(rts::efield &ef, rts::halfspace hs); + +namespace rts{ + +template +class halfspace +{ +private: + rts::plane S; //surface plane splitting the half space + rts::complex n0; //refractive index at the front of the plane + rts::complex n1; //refractive index at the back of the plane + + //lists of waves in front (pw0) and behind (pw1) the plane + std::vector< rts::planewave > w0; + std::vector< rts::planewave > w1; + + //rts::planewave pi; //incident plane wave + //rts::planewave pr; //plane wave reflected from the surface + //rts::planewave pt; //plane wave transmitted through the surface + + void init(){ + n0 = 1.0; + n1 = 1.5; + } + + //compute which side of the interface is hit by the incoming plane wave (0 = front, 1 = back) + bool facing(planewave p){ + if(p.kvec().dot(S.norm()) > 0) + return 1; + else + return 0; + } + + T calc_theta_i(vec v){ + + vec v_hat = v.norm(); + + //compute the cosine of the angle between k_hat and the plane normal + T cos_theta_i = v_hat.dot(S.norm()); + + return acos(abs(cos_theta_i)); + } + + T calc_theta_t(T ni_nt, T theta_i){ + + T sin_theta_t = ni_nt * sin(theta_i); + return asin(sin_theta_t); + } + + +public: + + //constructors + halfspace(){ + init(); + } + + halfspace(T na, T nb){ + init(); + n0 = na; + n1 = nb; + } + + halfspace(T na, T nb, plane p){ + n0 = na; + n1 = nb; + S = p; + } + + //compute the transmitted and reflective waves given the incident (vacuum) plane wave p + void incident(rts::planewave p){ + + planewave r, t; + p.scatter(S, n1.real()/n0.real(), r, t); + + //std::cout<<"i+r: "< b, unsigned int N = 10000){ + + //generate a plane wave decomposition for the beam + std::vector< planewave > pw_list = b.mc(N); + + //calculate the reflected and refracted waves for each incident wave + for(unsigned int w = 0; w < pw_list.size(); w++){ + incident(pw_list[w]); + } + } + + std::string str(){ + std::stringstream ss; + ss<<"Half Space-------------"< (rts::efield &ef, rts::halfspace hs); + +}; + + + + +} + + +#endif \ No newline at end of file diff --git a/optics/planewave.h b/optics/planewave.h index e852164..390a2e9 100644 --- a/optics/planewave.h +++ b/optics/planewave.h @@ -7,6 +7,8 @@ #include "../math/vector.h" #include "../math/quaternion.h" #include "../math/constants.h" +#include "../math/plane.h" +#include "rts/cuda/callable.h" /*Basic conversions used here (assuming a vacuum) lambda = @@ -14,160 +16,299 @@ namespace rts{ -template +template class planewave{ +protected: + + vec k; //k = tau / lambda + vec E0; //amplitude + T phi; + + planewave bend(rts::vec kn) const{ + + vec kn_hat = kn.norm(); //normalize the new k + vec k_hat = k.norm(); //normalize the current k + + //std::cout<<"PLANE WAVE BENDING------------------"< new_p; //create a new plane wave + + //if kn is equal to k or -k, handle the degenerate case + T k_dot_kn = k_hat.dot(kn_hat); + + //if k . n < 0, then the bend is a reflection + //flip k_hat + if(k_dot_kn < 0) k_hat = -k_hat; + + //std::cout<<"k dot kn: "< r = k_hat.cross(kn_hat); //compute the rotation vector + + //std::cout<<"r: "< q; + q.CreateRotation(theta, r.norm()); + + //apply the rotation to E0 + vec E0n = q.toMatrix3() * E0; + + new_p.k = kn_hat * kmag(); + new_p.E0 = E0n; + + return new_p; + } + public: - vec

k; //k = tau / lambda - vec

E0; //amplitude ///constructor: create a plane wave propagating along z, polarized along x - /*planewave(P lambda = (P)1) + /*planewave(T lambda = (T)1) { - k = rts::vec

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

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

_k = rts::vec

(0, 0, TAU), vec

_E0 = rts::vec

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

k_hat = _k.norm(); - - vec

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

E0_hat = (s.cross(k)).norm(); //compute a normalized E0 direction vector - E0 = E0_hat * E0_hat.dot(_E0); //compute the projection of _E0 onto E0_hat + phi = phase; + k = kvec; + vec k_hat = k.norm(); + + if(E.len() == 0) //if the plane wave has an amplitude of 0 + E0 = vec(0); //just return it + else{ + vec s = (k.cross(E)).norm(); //compute an orthogonal side vector + vec E_hat = (s.cross(k)).norm(); //compute a normalized E0 direction vector + E0 = E_hat * E_hat.dot(E); //compute the projection of _E0 onto E0_hat + } } ///multiplication operator: scale E0 - planewave

& operator* (const P & rhs) + CUDA_CALLABLE planewave & operator* (const T & rhs) { E0 = E0 * rhs; return *this; } - P lambda() const + CUDA_CALLABLE T lambda() const { - return TAU / k.len(); + return rtsTAU / k.len(); } - P kmag() const + CUDA_CALLABLE T kmag() const { return k.len(); } + CUDA_CALLABLE vec E(){ + return E0; + } + + CUDA_CALLABLE vec kvec(){ + return k; + } + + CUDA_CALLABLE T phase(){ + return phi; + } + + CUDA_CALLABLE void phase(T p){ + phi = p; + } + + CUDA_CALLABLE vec< complex > pos(vec p = vec(0, 0, 0)){ + vec< complex > result; + + T kdp = k.dot(p); + complex x = complex(0, kdp); + complex expx = exp(x); + + result[0] = E0[0] * expx; + result[1] = E0[1] * expx; + result[2] = E0[2] * expx; + + return result; + } + + //scales k based on a transition from material ni to material nt + CUDA_CALLABLE planewave n(T ni, T nt){ + return planewave(k * (nt / ni), E0); + } - planewave

refract(rts::vec

kn) const + CUDA_CALLABLE planewave refract(rts::vec kn) const { - vec

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

k_hat = k.norm(); //normalize the current k + return bend(kn); + } - vec

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

new_p; //create a new plane wave + //if(facing == 0) //if the wave is tangent to the plane, return an identical wave + // return *this; + //else + if(facing == -1){ //if the wave hits the back of the plane, invert the plane and nr + P = P.flip(); //flip the plane + nr = 1/nr; //invert the refractive index (now nr = n0/n1) + } - //deal with a zero vector (both k and kn point in the same direction) - if(theta == (P)0) - { - new_p = *this; - return new_p; + //use Snell's Law to calculate the transmitted angle + T cos_theta_i = k.norm().dot(-P.norm()); //compute the cosine of theta_i + T theta_i = acos(cos_theta_i); //compute theta_i + T sin_theta_t = (1/nr) * sin(theta_i); //compute the sine of theta_t using Snell's law + T theta_t = asin(sin_theta_t); //compute the cosine of theta_t + + bool tir = false; //flag for total internal reflection + if(theta_t != theta_t){ + tir = true; + theta_t = rtsPI / (T)2; } - //create a quaternion to capture the rotation - quaternion

q; - q.CreateRotation(theta, r.norm()); + //handle the degenerate case where theta_i is 0 (the plane wave hits head-on) + if(theta_i == 0){ + T rp = (1 - nr) / (1 + nr); //compute the Fresnel coefficients + T tp = 2 / (1 + nr); + vec kr = -k; + vec kt = k * nr; //set the k vectors for theta_i = 0 + vec Er = E0 * rp; //compute the E vectors + vec Et = E0 * tp; + T phase_t = P.p().dot(k - kt); //compute the phase offset + T phase_r = P.p().dot(k - kr); + //std::cout<<"Degeneracy: Head-On"<(kr, Er, phase_r); + t = planewave(kt, Et, phase_t); + + //std::cout<<"i + r: "< E0n = q.toMatrix3() * E0; - new_p.k = kn_hat * k.len(); - new_p.E0 = E0n; + //compute the Fresnel coefficients + T rp, rs, tp, ts; + rp = tan(theta_t - theta_i) / tan(theta_t + theta_i); + rs = sin(theta_t - theta_i) / sin(theta_t + theta_i); + + if(tir){ + tp = ts = 0; + } + else{ + tp = ( 2 * sin(theta_t) * cos(theta_i) ) / ( sin(theta_t + theta_i) * cos(theta_t - theta_i) ); + ts = ( 2 * sin(theta_t) * cos(theta_i) ) / sin(theta_t + theta_i); + } - return new_p; + //compute the coordinate space for the plane of incidence + vec z_hat = -P.norm(); + vec y_hat = P.parallel(k).norm(); + vec x_hat = y_hat.cross(z_hat).norm(); + + //compute the k vectors for r and t + vec kr, kt; + kr = ( y_hat * sin(theta_i) - z_hat * cos(theta_i) ) * kmag(); + kt = ( y_hat * sin(theta_t) + z_hat * cos(theta_t) ) * kmag() * nr; + + //compute the magnitude of the p- and s-polarized components of the incident E vector + T Ei_s = E0.dot(x_hat); + int sgn = (0 < E0.dot(y_hat)) - (E0.dot(y_hat) < 0); + T Ei_p = sgn * ( E0 - x_hat * Ei_s ).len(); + //T Ei_p = ( E0 - x_hat * Ei_s ).len(); + //compute the magnitude of the p- and s-polarized components of the reflected E vector + T Er_s = Ei_s * rs; + T Er_p = Ei_p * rp; + //compute the magnitude of the p- and s-polarized components of the transmitted E vector + T Et_s = Ei_s * ts; + T Et_p = Ei_p * tp; + + //std::cout<<"E0: "< Er = (y_hat * cos(theta_i) + z_hat * sin(theta_i)) * Er_p + x_hat * Er_s; + //compute the transmitted E vector + vec Et = (y_hat * cos(theta_t) - z_hat * sin(theta_t)) * Et_p + x_hat * Et_s; + + T phase_t = P.p().dot(k - kt); + T phase_r = P.p().dot(k - kr); + + //std::cout<<"phase r: "< kn_hat = kn.norm(); //normalize new_k - vec

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

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

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

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

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

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

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

new_p; - new_p.E0 = E0_prime; - new_p.k = kn_hat * k.len(); - - return new_p;*/ - - /*vec

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

k_hat = k.norm(); - vec

E0_hat = E0.norm(); - - vec

B = k_hat.cross(E0_hat); - planewave

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

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

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

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

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

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