#ifndef RTS_HALFSPACE_H #define RTS_HALFSPACE_H #include "../math/plane.h" namespace stim{ //GPU kernel to compute the electric field 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); } } //GPU kernel to compute the electric displacement field template __global__ void gpu_halfspace_pw2df(complex* X, complex* Y, complex* Z, unsigned int r0, unsigned int r1, plane P, planewave w, rect q, T n, 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()); //vec< complex > testE(1, 0, 0); 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 { plane< complex > cplane = plane< complex, 3>(P); vec< complex > E_para;// = cplane.parallel(w.E()); vec< complex > E_perp;// = cplane.perpendicular(w.E()) * (n*n); cplane.decompose(w.E(), E_para, E_perp); T epsilon = n*n; X[i] += (E_para[0] + E_perp[0] * epsilon) * exp(x); Y[i] += (E_para[1] + E_perp[1] * epsilon) * exp(x); Z[i] += (E_para[2] + E_perp[2] * epsilon) * exp(x); } } //computes a scalar field containing the refractive index of the half-space at each point template __global__ void gpu_halfspace_n(T* n, unsigned int r0, unsigned int r1, rect q, plane P, T n0, T n1){ 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 ); //set the appropriate refractive index if(P.side(p) < 0) n[i] = n0; else n[i] = n1; } 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]); } } //return the electric field at the specified resolution and position rts::efield E(unsigned int r0, unsigned int r1, rect R){ int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size int SQRT_BLOCK = (int)std::sqrt((float)maxThreads); //create one thread for each detector pixel dim3 dimBlock(SQRT_BLOCK, SQRT_BLOCK); dim3 dimGrid((r0 + SQRT_BLOCK -1)/SQRT_BLOCK, (r1 + SQRT_BLOCK - 1)/SQRT_BLOCK); //create an electric field rts::efield ef(r0, r1); ef.position(R); //render each plane wave //plane waves at the surface front for(unsigned int w = 0; w < w0.size(); w++){ //std::cout<<"w0 "< <<>> (ef.x(), ef.y(), ef.z(), r0, r1, S, w0[w], ef.p()); } //plane waves at the surface back for(unsigned int w = 0; w < w1.size(); w++){ //std::cout<<"w1 "< <<>> (ef.x(), ef.y(), ef.z(), r0, r1, -S, w1[w], ef.p(), true); } return ef; } //return the electric displacement at the specified resolution and position rts::efield D(unsigned int r0, unsigned int r1, rect R){ int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size int SQRT_BLOCK = (int)std::sqrt((float)maxThreads); //create one thread for each detector pixel dim3 dimBlock(SQRT_BLOCK, SQRT_BLOCK); dim3 dimGrid((r0 + SQRT_BLOCK -1)/SQRT_BLOCK, (r1 + SQRT_BLOCK - 1)/SQRT_BLOCK); //create a complex vector field rts::efield df(r0, r1); df.position(R); //render each plane wave //plane waves at the surface front for(unsigned int w = 0; w < w0.size(); w++){ //std::cout<<"w0 "< <<>> (df.x(), df.y(), df.z(), r0, r1, S, w0[w], df.p(), n0.real()); } //plane waves at the surface back for(unsigned int w = 0; w < w1.size(); w++){ //std::cout<<"w1 "< <<>> (df.x(), df.y(), df.z(), r0, r1, -S, w1[w], df.p(), n1.real(), true); } return df; } realfield nfield(unsigned int Ru, unsigned int Rv, rect p){ int maxThreads = rts::maxThreadsPerBlock(); //compute the optimal block size int SQRT_BLOCK = (int)std::sqrt((float)maxThreads); //create one thread for each detector pixel dim3 dimBlock(SQRT_BLOCK, SQRT_BLOCK); dim3 dimGrid((Ru + SQRT_BLOCK -1)/SQRT_BLOCK, (Rv + SQRT_BLOCK - 1)/SQRT_BLOCK); realfield n(Ru, Rv); //create a scalar field to store the result of n rts::gpu_halfspace_n <<>> (n.ptr(), Ru, Rv, p, S, n0.real(), n1.real()); return n; } std::string str(){ std::stringstream ss; ss<<"Half Space-------------"< (rts::efield &ef, rts::halfspace hs); }; } #endif