Commit 14634fcaed80d5365b4492ba31d049b360eac1ec

Authored by David Mayerich
1 parent 4fcb3a86

edits to update scattering code

cmake/FindCNPY.cmake 0 → 100644
  1 +# finds the STIM library (downloads it if it isn't present)
  2 +# set STIMLIB_PATH to the directory containing the stim subdirectory (the stim repository)
  3 +
  4 +include(FindPackageHandleStandardArgs)
  5 +
  6 +
  7 +
  8 +IF(NOT UNIX)
  9 + set(CNPY_ROOT $ENV{PROGRAMFILES}/CNPY)
  10 + find_path(CNPY_INCLUDE_DIR PATHS ${CNPY_ROOT} NAMES cnpy.h)
  11 + find_library(CNPY_LIBRARY NAMES cnpy PATHS ${CNPY_ROOT})
  12 +ENDIF(NOT UNIX)
  13 +
  14 +
  15 +find_package_handle_standard_args(CNPY DEFAULT_MSG CNPY_LIBRARY CNPY_INCLUDE_DIR)
  16 +
  17 +set(CNPY_LIBRARIES ${CNPY_LIBRARY})
  18 +set(CNPY_INCLUDE_DIRS ${CNPY_INCLUDE_DIR})
0 \ No newline at end of file 19 \ No newline at end of file
@@ -40,12 +40,12 @@ class planewave: @@ -40,12 +40,12 @@ class planewave:
40 self.k = np.array(k) 40 self.k = np.array(k)
41 self.E = E 41 self.E = E
42 42
43 - if ( np.linalg.norm(k) > 1e-15 and np.linalg.norm(E) >1e-15):  
44 - s = np.cross(k, E) #compute an orthogonal side vector  
45 - s = s / np.linalg.norm(s) #normalize it  
46 - Edir = np.cross(s, k) #compute new E vector which is orthogonal  
47 - self.k = np.array(k)  
48 - self.E = Edir / np.linalg.norm(Edir) * np.linalg.norm(E) 43 + #if ( np.linalg.norm(k) > 1e-15 and np.linalg.norm(E) >1e-15):
  44 + # s = np.cross(k, E) #compute an orthogonal side vector
  45 + # s = s / np.linalg.norm(s) #normalize it
  46 + # Edir = np.cross(s, k) #compute new E vector which is orthogonal
  47 + # self.k = np.array(k)
  48 + # self.E = Edir / np.linalg.norm(Edir) * np.linalg.norm(E)
49 49
50 def __str__(self): 50 def __str__(self):
51 return str(self.k) + "\n" + str(self.E) #for verify field vectors use print command 51 return str(self.k) + "\n" + str(self.E) #for verify field vectors use print command
stim/math/matrix_sq.h
@@ -100,7 +100,7 @@ struct matrix_sq @@ -100,7 +100,7 @@ struct matrix_sq
100 100
101 template<typename Y> 101 template<typename Y>
102 CUDA_CALLABLE vec3<Y> operator*(vec3<Y> rhs){ 102 CUDA_CALLABLE vec3<Y> operator*(vec3<Y> rhs){
103 - vec3<Y> result = 0; 103 + vec3<Y> result;
104 for(int r=0; r<3; r++) 104 for(int r=0; r<3; r++)
105 for(int c=0; c<3; c++) 105 for(int c=0; c<3; c++)
106 result[r] += (*this)(r, c) * rhs[c]; 106 result[r] += (*this)(r, c) * rhs[c];
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 3
4 4
5 #include <stim/cuda/cudatools/callable.h> 5 #include <stim/cuda/cudatools/callable.h>
  6 +#include <complex>
6 #include <cmath> 7 #include <cmath>
7 8
8 #include <sstream> 9 #include <sstream>
@@ -43,21 +44,25 @@ public: @@ -43,21 +44,25 @@ public:
43 CUDA_CALLABLE T& operator[](size_t idx){ 44 CUDA_CALLABLE T& operator[](size_t idx){
44 return ptr[idx]; 45 return ptr[idx];
45 } 46 }
  47 + //read only accessor method
  48 + CUDA_CALLABLE T get(size_t idx) const {
  49 + return ptr[idx];
  50 + }
46 51
47 CUDA_CALLABLE T* data(){ 52 CUDA_CALLABLE T* data(){
48 return ptr; 53 return ptr;
49 } 54 }
50 55
51 /// Casting operator. Creates a new vector with a new type U. 56 /// Casting operator. Creates a new vector with a new type U.
52 - template< typename U > 57 +/* template< typename U >
53 CUDA_CALLABLE operator vec3<U>(){ 58 CUDA_CALLABLE operator vec3<U>(){
54 - vec3<U> result;  
55 - result.ptr[0] = (U)ptr[0];  
56 - result.ptr[1] = (U)ptr[1];  
57 - result.ptr[2] = (U)ptr[2]; 59 + vec3<U> result((U)ptr[0], (U)ptr[1], (U)ptr[2]);
  60 + //result.ptr[0] = (U)ptr[0];
  61 + //result.ptr[1] = (U)ptr[1];
  62 + //result.ptr[2] = (U)ptr[2];
58 63
59 return result; 64 return result;
60 - } 65 + }*/
61 66
62 // computes the squared Euclidean length (useful for several operations where only >, =, or < matter) 67 // computes the squared Euclidean length (useful for several operations where only >, =, or < matter)
63 CUDA_CALLABLE T len_sq() const{ 68 CUDA_CALLABLE T len_sq() const{
@@ -68,7 +73,22 @@ public: @@ -68,7 +73,22 @@ public:
68 CUDA_CALLABLE T len() const{ 73 CUDA_CALLABLE T len() const{
69 return sqrt(len_sq()); 74 return sqrt(len_sq());
70 } 75 }
71 - 76 +
  77 + /// Calculate the L2 norm of the vector, accounting for the possibility that it is complex
  78 + CUDA_CALLABLE T norm2() const{
  79 + T conj_dot = std::real(ptr[0] * std::conj(ptr[0]) + ptr[1] * std::conj(ptr[1]) + ptr[2] * std::conj(ptr[2]));
  80 + return sqrt(conj_dot);
  81 + }
  82 +
  83 + /// Calculate the normalized direction vector
  84 + CUDA_CALLABLE vec3<T> direction() const {
  85 + vec3<T> result;
  86 + T length = norm2();
  87 + result[0] = ptr[0] / length;
  88 + result[1] = ptr[1] / length;
  89 + result[2] = ptr[2] / length;
  90 + return result;
  91 + }
72 92
73 /// Convert the vector from cartesian to spherical coordinates (x, y, z -> r, theta, phi where theta = [-PI, PI]) 93 /// Convert the vector from cartesian to spherical coordinates (x, y, z -> r, theta, phi where theta = [-PI, PI])
74 CUDA_CALLABLE vec3<T> cart2sph() const{ 94 CUDA_CALLABLE vec3<T> cart2sph() const{
@@ -268,8 +288,36 @@ std::string str() const{ @@ -268,8 +288,36 @@ std::string str() const{
268 size_t size(){ return 3; } 288 size_t size(){ return 3; }
269 289
270 }; //end class vec3 290 }; //end class vec3
  291 +
  292 + /// Start Class cvec3 (complex vector class)
  293 + template<typename T>
  294 + class cvec3 : public vec3< std::complex<T> > {
  295 +
  296 + public:
  297 + CUDA_CALLABLE cvec3() : vec3< std::complex<T> >() {}
  298 + CUDA_CALLABLE cvec3(T x, T y, T z) : vec3< std::complex<T> >(std::complex<T>(x), std::complex<T>(y), std::complex<T>(z)) {}
  299 + CUDA_CALLABLE cvec3(std::complex<T> x, std::complex<T> y, std::complex<T> z) : vec3< std::complex<T> >(x, y, z) {}
  300 +
  301 + CUDA_CALLABLE cvec3& operator=(const vec3< std::complex<T> > rhs) {
  302 + vec3< std::complex<T> >::ptr[0] = rhs.get(0);
  303 + vec3< std::complex<T> >::ptr[1] = rhs.get(1);
  304 + vec3< std::complex<T> >::ptr[2] = rhs.get(2);
  305 + return *this;
  306 + }
  307 + CUDA_CALLABLE std::complex<T> dot(const vec3<T> rhs) {
  308 + std::complex<T> result =
  309 + vec3< std::complex<T> >::ptr[0] * rhs.get(0) +
  310 + vec3< std::complex<T> >::ptr[1] * rhs.get(1) +
  311 + vec3< std::complex<T> >::ptr[2] * rhs.get(2);
  312 +
  313 + return result;
  314 + }
  315 + }; //end class cvec3
271 } //end namespace stim 316 } //end namespace stim
272 317
  318 +
  319 +
  320 +
273 /// Multiply a vector by a constant when the vector is on the right hand side 321 /// Multiply a vector by a constant when the vector is on the right hand side
274 template <typename T> 322 template <typename T>
275 stim::vec3<T> operator*(T lhs, stim::vec3<T> rhs){ 323 stim::vec3<T> operator*(T lhs, stim::vec3<T> rhs){
stim/math/vector.h
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 #include <sstream> 6 #include <sstream>
7 #include <vector> 7 #include <vector>
8 #include <algorithm> 8 #include <algorithm>
  9 +#include <complex>
9 10
10 #include <stim/cuda/cudatools/callable.h> 11 #include <stim/cuda/cudatools/callable.h>
11 #include <stim/math/vec3.h> 12 #include <stim/math/vec3.h>
stim/optics/planewave.h
@@ -5,15 +5,38 @@ @@ -5,15 +5,38 @@
5 #include <sstream> 5 #include <sstream>
6 #include <cmath> 6 #include <cmath>
7 7
8 -#include "../math/vector.h" 8 +#include "../math/vec3.h"
9 #include "../math/quaternion.h" 9 #include "../math/quaternion.h"
10 #include "../math/constants.h" 10 #include "../math/constants.h"
11 #include "../math/plane.h" 11 #include "../math/plane.h"
12 -#include "../math/complex.h" 12 +#include <complex>
  13 +
  14 +/// Calculate whether or not a vector v intersects the front (1) or back (-1) of a plane.
  15 +/// This function returns -1 if the vector lies within the plane (is orthogonal to the surface normal)
  16 +/*template <typename T>
  17 +int plane_face(stim::vec3<T> v, stim::vec3<T> plane_normal) {
  18 + T dotprod = v.dot(plane_normal); //calculate the dot product
  19 +
  20 + if (dotprod < 0) return 1;
  21 + if (dotprod > 0) return -1;
  22 + return 0;
  23 +}
  24 +
  25 +/// Calculate the component of a vector v that is perpendicular to a plane defined by a normal.
  26 +template <typename T>
  27 +stim::vec3<T> plane_perpendicular(stim::vec3<T> v, stim::vec3<T> plane_normal) {
  28 + return plane_normal * v.dot(plane_normal);
  29 +}
  30 +
  31 +template <typename T>
  32 +stim::vec3<T> plane_parallel(stim::vec3<T> v, stim::vec3<T> plane_normal) {
  33 + return v - plane_perpendicular(v, plane_normal);
  34 +}*/
13 35
14 namespace stim{ 36 namespace stim{
15 namespace optics{ 37 namespace optics{
16 38
  39 +
17 /// evaluate the scalar field produced by a plane wave at a point (x, y, z) 40 /// evaluate the scalar field produced by a plane wave at a point (x, y, z)
18 41
19 /// @param x is the x-coordinate of the point 42 /// @param x is the x-coordinate of the point
@@ -24,9 +47,9 @@ namespace stim{ @@ -24,9 +47,9 @@ namespace stim{
24 /// @param ky is the k-vector component in the y direction 47 /// @param ky is the k-vector component in the y direction
25 /// @param kz is the k-vector component in the z direction 48 /// @param kz is the k-vector component in the z direction
26 template<typename T> 49 template<typename T>
27 - stim::complex<T> planewave_scalar(T x, T y, T z, stim::complex<T> A, T kx, T ky, T kz){ 50 + std::complex<T> planewave_scalar(T x, T y, T z, std::complex<T> A, T kx, T ky, T kz){
28 T d = x * kx + y * ky + z * kz; //calculate the dot product between k and p = (x, y, z) to find the distance p is along the propagation direction 51 T d = x * kx + y * ky + z * kz; //calculate the dot product between k and p = (x, y, z) to find the distance p is along the propagation direction
29 - stim::complex<T> di = stim::complex<T>(0, d); //calculate the phase shift that will have to be applied to propagate the wave distance d 52 + std::complex<T> di = std::complex<T>(0, d); //calculate the phase shift that will have to be applied to propagate the wave distance d
30 return A * exp(di); //multiply the phase term by the amplitude at (0, 0, 0) to propagate the wave to p 53 return A * exp(di); //multiply the phase term by the amplitude at (0, 0, 0) to propagate the wave to p
31 } 54 }
32 55
@@ -42,7 +65,7 @@ namespace stim{ @@ -42,7 +65,7 @@ namespace stim{
42 /// @param ky is the k-vector component in the y direction 65 /// @param ky is the k-vector component in the y direction
43 /// @param kz is the k-vector component in the z direction 66 /// @param kz is the k-vector component in the z direction
44 template<typename T> 67 template<typename T>
45 - void cpu_planewave_scalar(stim::complex<T>* field, size_t N, T* x, T* y = NULL, T* z = NULL, stim::complex<T> A = 1.0, T kx = 0.0, T ky = 0.0, T kz = 0.0){ 68 + void cpu_planewave_scalar(std::complex<T>* field, size_t N, T* x, T* y = NULL, T* z = NULL, std::complex<T> A = 1.0, T kx = 0.0, T ky = 0.0, T kz = 0.0){
46 T px, py, pz; 69 T px, py, pz;
47 for(size_t i = 0; i < N; i++){ // for each element in the array 70 for(size_t i = 0; i < N; i++){ // for each element in the array
48 (x == NULL) ? px = 0 : px = x[i]; // test for NULL values 71 (x == NULL) ? px = 0 : px = x[i]; // test for NULL values
@@ -53,19 +76,137 @@ namespace stim{ @@ -53,19 +76,137 @@ namespace stim{
53 } 76 }
54 } 77 }
55 78
  79 +
  80 +/*template<typename T>
  81 +class cvec3 {
  82 +public:
  83 + std::complex<T> x;
  84 + std::complex<T> y;
  85 + std::complex<T> z;
  86 +
  87 + cvec3(std::complex<T> _x, std::complex<T> _y, std::complex<T> _z) {
  88 + x = _x;
  89 + y = _y;
  90 + z = _z;
  91 + }
  92 +};*/
  93 +
  94 +/*template<typename T>
  95 +class cvec3 {
  96 +public:
  97 + std::complex<T> m_v[3];
  98 +
  99 + cvec3(std::complex<T> x, std::complex<T> y, std::complex<T> z) {
  100 + m_v[0] = x;
  101 + m_v[1] = y;
  102 + m_v[2] = z;
  103 + }
  104 +
  105 + cvec3() : cvec3(0, 0, 0) {}
  106 +
  107 + void operator()(std::complex<T> x, std::complex<T> y, std::complex<T> z) {
  108 + m_v[0] = x;
  109 + m_v[1] = y;
  110 + m_v[2] = z;
  111 + }
  112 +
  113 + std::complex<T> operator[](int i) const { return m_v[i]; }
  114 + std::complex<T>& operator[](int i) { return m_v[i]; }
  115 +
  116 + /// Calculate the 2-norm of the complex vector
  117 + T norm2() {
  118 + T xx = std::real(m_v[0] * std::conj(m_v[0]));
  119 + T yy = std::real(m_v[1] * std::conj(m_v[1]));
  120 + T zz = std::real(m_v[2] * std::conj(m_v[2]));
  121 + return std::sqrt(xx + yy + zz);
  122 + }
  123 +
  124 + /// Returns the normalized direction vector
  125 + cvec3 direction() {
  126 + cvec3 result;
  127 +
  128 + std::complex<T> length = norm2();
  129 + result[0] = m_v[0] / length;
  130 + result[1] = m_v[1] / length;
  131 + result[2] = m_v[2] / length;
  132 +
  133 + return result;
  134 + }
  135 +
  136 + std::string str() {
  137 + std::stringstream ss;
  138 + ss << m_v[0] << ", " << m_v[1] << ", " << m_v[2];
  139 + return ss.str();
  140 + }
  141 +
  142 + //copy constructor
  143 + cvec3(const cvec3 &other) {
  144 + m_v[0] = other.m_v[0];
  145 + m_v[1] = other.m_v[1];
  146 + m_v[2] = other.m_v[2];
  147 + }
  148 +
  149 + /// Assignment operator
  150 + cvec3& operator=(const cvec3 &rhs) {
  151 + m_v[0] = rhs.m_v[0];
  152 + m_v[1] = rhs.m_v[1];
  153 + m_v[2] = rhs.m_v[2];
  154 +
  155 + return *this;
  156 + }
  157 +
  158 + /// Calculate and return the cross product between this vector and another
  159 + cvec3 cross(cvec3 rhs) {
  160 + cvec3 result;
  161 +
  162 + //compute the cross product (only valid for 3D vectors)
  163 + result[0] = (m_v[1] * rhs[2] - m_v[2] * rhs[1]);
  164 + result[1] = (m_v[2] * rhs[0] - m_v[0] * rhs[2]);
  165 + result[2] = (m_v[1] * rhs[1] - m_v[1] * rhs[0]);
  166 +
  167 + return result;
  168 + }
  169 +
  170 + /// Calculate and return the dot product between this vector and another
  171 + std::complex<T> dot(cvec3 rhs) {
  172 + return m_v[0] * rhs[0] + m_v[1] * rhs[1] + m_v[2] * rhs[2];
  173 + }
  174 +
  175 + /// Arithmetic multiplication: returns the vector scaled by a constant value
  176 + template<typename R>
  177 + cvec3 operator*(R rhs) const
  178 + {
  179 + cvec3 result;
  180 + result[0] = m_v[0] * rhs;
  181 + result[1] = m_v[1] * rhs;
  182 + result[2] = m_v[2] * rhs;
  183 +
  184 + return result;
  185 + }
  186 +
  187 +};
  188 +template <typename T>
  189 +std::ostream& operator<<(std::ostream& os, stim::optics::cvec3<T> p) {
  190 + os << p.str();
  191 + return os;
  192 +}
  193 +*/
  194 +
56 template<typename T> 195 template<typename T>
57 class planewave{ 196 class planewave{
58 197
59 protected: 198 protected:
60 199
61 - stim::vec<T> k; //k-vector, pointed in propagation direction with magnitude |k| = tau / lambda = 2pi / lambda  
62 - stim::vec< stim::complex<T> > E0; //amplitude (for a scalar plane wave, only E0[0] is used) 200 + cvec3<T> m_k; //k-vector, pointed in propagation direction with magnitude |k| = tau / lambda = 2pi / lambda
  201 + cvec3<T> m_E; //amplitude (for a scalar plane wave, only E0[0] is used)
63 202
64 /// Bend a plane wave via refraction, given that the new propagation direction is known 203 /// Bend a plane wave via refraction, given that the new propagation direction is known
65 - CUDA_CALLABLE planewave<T> bend(stim::vec<T> kn) const{ 204 + CUDA_CALLABLE planewave<T> bend(stim::vec3<T> v) const {
66 205
67 - stim::vec<T> kn_hat = kn.norm(); //normalize the new k  
68 - stim::vec<T> k_hat = k.norm(); //normalize the current k 206 + stim::vec3<T> k_real(m_k.get(0).real(), m_k.get(1).real(), m_k.get(2).real()); //force the vector to be real (can only refract real directions)
  207 +
  208 + stim::vec3<T> kn_hat = v.direction(); //normalize the new k
  209 + stim::vec3<T> k_hat = k_real.direction(); //normalize the current k
69 210
70 planewave<T> new_p; //create a new plane wave 211 planewave<T> new_p; //create a new plane wave
71 212
@@ -75,51 +216,136 @@ protected: @@ -75,51 +216,136 @@ protected:
75 if(k_dot_kn < 0) k_hat = -k_hat; //flip k_hat 216 if(k_dot_kn < 0) k_hat = -k_hat; //flip k_hat
76 217
77 if(k_dot_kn == -1){ 218 if(k_dot_kn == -1){
78 - new_p.k = -k;  
79 - new_p.E0 = E0; 219 + new_p.m_k = -m_k;
  220 + new_p.m_E = m_E;
80 return new_p; 221 return new_p;
81 } 222 }
82 else if(k_dot_kn == 1){ 223 else if(k_dot_kn == 1){
83 - new_p.k = k;  
84 - new_p.E0 = E0; 224 + new_p.m_k = m_k;
  225 + new_p.m_E = m_E;
85 return new_p; 226 return new_p;
86 } 227 }
87 228
88 - vec<T> r = k_hat.cross(kn_hat); //compute the rotation vector 229 + vec3<T> r = k_hat.cross(kn_hat); //compute the rotation vector
89 T theta = asin(r.len()); //compute the angle of the rotation about r 230 T theta = asin(r.len()); //compute the angle of the rotation about r
90 quaternion<T> q; //create a quaternion to capture the rotation 231 quaternion<T> q; //create a quaternion to capture the rotation
91 - q.CreateRotation(theta, r.norm());  
92 - vec< complex<T> > E0n = q.toMatrix3() * E0; //apply the rotation to E0  
93 - new_p.k = kn_hat * kmag();  
94 - new_p.E0 = E0n; 232 + q.CreateRotation(theta, r.direction());
  233 + stim::matrix_sq<T, 3> R = q.toMatrix3();
  234 + vec3< std::complex<T> > E(m_E.get(0), m_E.get(1), m_E.get(2));
  235 + vec3< std::complex<T> > E0n = R * E; //apply the rotation to E0
  236 + //new_p.m_k = kn_hat * kmag();
  237 + //new_p.m_E = E0n;
  238 + new_p.m_k[0] = kn_hat[0] * kmag();
  239 + new_p.m_k[1] = kn_hat[1] * kmag();
  240 + new_p.m_k[2] = kn_hat[2] * kmag();
  241 +
  242 + new_p.m_E[0] = E0n[0];
  243 + new_p.m_E[1] = E0n[1];
  244 + new_p.m_E[2] = E0n[2];
  245 +
95 246
96 return new_p; 247 return new_p;
97 } 248 }
98 249
99 public: 250 public:
100 251
  252 +
  253 +
101 ///constructor: create a plane wave propagating along k 254 ///constructor: create a plane wave propagating along k
102 - CUDA_CALLABLE planewave(vec<T> kvec = stim::vec<T>(0, 0, stim::TAU),  
103 - vec< complex<T> > E = stim::vec<T>(1, 0, 0))  
104 - {  
105 - //phi = phase; 255 + //CUDA_CALLABLE planewave(vec<T> kvec = stim::vec<T>(0, 0, stim::TAU),
  256 + // vec< complex<T> > E = stim::vec<T>(1, 0, 0))
  257 + CUDA_CALLABLE planewave(std::complex<T> kx, std::complex<T> ky, std::complex<T> kz,
  258 + std::complex<T> Ex, std::complex<T> Ey, std::complex<T> Ez) {
  259 +
  260 + m_k = cvec3<T>(kx, ky, kz);
  261 + m_E = cvec3<T>(Ex, Ey, Ez);
  262 + force_orthogonal();
  263 + }
106 264
107 - k = kvec;  
108 - vec< complex<T> > k_hat = k.norm(); 265 + CUDA_CALLABLE planewave() : planewave(0, 0, 1, 1, 0, 0) {}
109 266
110 - if(E.len() == 0) //if the plane wave has an amplitude of 0  
111 - E0 = vec<T>(0); //just return it  
112 - else{  
113 - vec< complex<T> > s = (k_hat.cross(E)).norm(); //compute an orthogonal side vector  
114 - vec< complex<T> > E_hat = (s.cross(k)).norm(); //compute a normalized E0 direction vector  
115 - E0 = E_hat;// * E_hat.dot(E); //compute the projection of _E0 onto E0_hat  
116 - } 267 + //copy constructor
  268 + CUDA_CALLABLE planewave(const planewave& other) {
  269 + m_k = other.m_k;
  270 + m_E = other.m_E;
  271 + }
  272 +
  273 + /// Assignment operator
  274 + CUDA_CALLABLE planewave& operator=(const planewave& rhs) {
  275 + m_k = rhs.m_k;
  276 + m_E = rhs.m_E;
117 277
118 - E0 = E0 * exp( complex<T>(0, phase) ); 278 + return *this;
  279 + }
  280 +
  281 + /// Forces the k and E vectors to be orthogonal
  282 + CUDA_CALLABLE void force_orthogonal() {
  283 +
  284 + /*if (m_E.norm2() == 0) return;
  285 +
  286 + cvec3<T> k_dir = m_k.direction(); //calculate the normalized direction vectors for k and E
  287 + cvec3<T> E_dir = m_E.direction();
  288 + cvec3<T> side = k_dir.cross(E_dir); //calculate a side vector for projection
  289 + cvec3<T> side_dir = side.direction(); //normalize the side vector
  290 + E_dir = side_dir.cross(k_dir); //calculate the new E vector direction
  291 + T E_norm = m_E.norm2();
  292 + m_E = E_dir * E_norm; //apply the new direction to the existing E vector
  293 + */
  294 + }
  295 +
  296 + CUDA_CALLABLE cvec3<T> k() {
  297 + return m_k;
  298 + }
  299 +
  300 + CUDA_CALLABLE cvec3<T> E() {
  301 + return m_E;
  302 + }
  303 +
  304 + CUDA_CALLABLE cvec3<T> evaluate(T x, T y, T z) {
  305 +
  306 + std::complex<T> k_dot_r = m_k[0] * x + m_k[1] * y + m_k[2] * z;
  307 + std::complex<T> e_k_dot_r = std::exp(std::complex<T>(0, 1) * k_dot_r);
  308 +
  309 + cvec3<T> result;
  310 + result[0] = m_E[0] * e_k_dot_r;
  311 + result[1] = m_E[1] * e_k_dot_r;
  312 + result[2] = m_E[2] * e_k_dot_r;
  313 + return result;
  314 + }
  315 +
  316 + /*int scatter(vec3<T> surface_normal, vec3<T> surface_point, T ni, std::complex<T> nt,
  317 + planewave& Pi, planewave& Pr, planewave& Pt) {
  318 +
  319 +
  320 + return 0;
  321 +
  322 + }*/
  323 +
  324 + CUDA_CALLABLE T kmag() const {
  325 + return std::sqrt(std::real(m_k.get(0) * std::conj(m_k.get(0)) + m_k.get(1) * std::conj(m_k.get(1)) + m_k.get(2) * std::conj(m_k.get(2))));
  326 + }
  327 +
  328 + CUDA_CALLABLE planewave<T> refract(stim::vec3<T> kn) const {
  329 + return bend(kn);
  330 + }
  331 +
  332 + /// Return a plane wave with the origin translated by (x, y, z)
  333 + CUDA_CALLABLE planewave<T> translate(T x, T y, T z) const {
  334 + planewave<T> result;
  335 + cvec3<T> k = m_k;
  336 + result.m_k = k;
  337 + std::complex<T> k_dot_r = k[0] * (-x) + k[1] * (-y) + k[2] * (-z);
  338 + std::complex<T> exp_k_dot_r = std::exp(std::complex<T>(0.0, 1.0) * k_dot_r);
  339 +
  340 + cvec3<T> E = m_E;
  341 + result.m_E[0] = E[0] * exp_k_dot_r;
  342 + result.m_E[1] = E[1] * exp_k_dot_r;
  343 + result.m_E[2] = E[2] * exp_k_dot_r;
  344 + return result;
119 } 345 }
120 346
121 ///multiplication operator: scale E0 347 ///multiplication operator: scale E0
122 - CUDA_CALLABLE planewave<T> & operator* (const T & rhs){ 348 + /*CUDA_CALLABLE planewave<T>& operator* (const T& rhs) {
123 E0 = E0 * rhs; 349 E0 = E0 * rhs;
124 return *this; 350 return *this;
125 } 351 }
@@ -177,7 +403,7 @@ public: @@ -177,7 +403,7 @@ public:
177 /// @param t is the transmitted component of the plane wave 403 /// @param t is the transmitted component of the plane wave
178 void scatter(stim::plane<T> P, T n0, T n1, planewave<T> &r, planewave<T> &t){ 404 void scatter(stim::plane<T> P, T n0, T n1, planewave<T> &r, planewave<T> &t){
179 scatter(P, n1/n0, r, t); 405 scatter(P, n1/n0, r, t);
180 - } 406 + }*/
181 407
182 /// Calculate the scattering result when nr = n1/n0 408 /// Calculate the scattering result when nr = n1/n0
183 409
@@ -186,41 +412,63 @@ public: @@ -186,41 +412,63 @@ public:
186 /// @param n1 is the refractive index inside the surface (in the direction away from the normal) 412 /// @param n1 is the refractive index inside the surface (in the direction away from the normal)
187 /// @param r is the reflected component of the plane wave 413 /// @param r is the reflected component of the plane wave
188 /// @param t is the transmitted component of the plane wave 414 /// @param t is the transmitted component of the plane wave
189 - void scatter(stim::plane<T> P, T nr, planewave<T> &r, planewave<T> &t){ 415 +
  416 + /*void scatter(vec3<T> plane_normal, vec3<T> plane_position, std::complex<T> nr, planewave<T>& r, planewave<T>& t) {
  417 +
  418 + //TODO: Generate a real vector from the current K vector - this will not address complex k-vectors
  419 + vec3< std::complex<T> > k(3);
  420 + k[0] = m_k[0];
  421 + k[1] = m_k[1];
  422 + k[2] = m_k[2];
  423 +
  424 + vec3< std::complex<T> > E(3);
  425 + E[0] = m_E[0];// std::complex<T>(m_E[0].real(), m_E[0].imag());
  426 + E[1] = m_E[1];// std::complex<T>(m_E[1].real(), m_E[1].imag());
  427 + E[2] = m_E[2];// std::complex<T>(m_E[2].real(), m_E[2].imag());
  428 +
  429 + std::complex<T> cOne(1, 0);
  430 + std::complex<T> cTwo(2, 0);
  431 +
  432 + T kmag = m_k.norm2();
190 433
191 - int facing = P.face(k); //determine which direction the plane wave is coming in 434 + int facing = plane_face(k, plane_normal); //determine which direction the plane wave is coming in
192 435
193 - if(facing == -1){ //if the wave hits the back of the plane, invert the plane and nr  
194 - P = P.flip(); //flip the plane  
195 - nr = 1/nr; //invert the refractive index (now nr = n0/n1) 436 + if(facing == -1){ //if the wave hits the back of the plane, invert the plane and nr
  437 + plane_normal = -plane_normal; //flip the plane
  438 + nr = cOne / nr; //invert the refractive index (now nr = n0/n1)
196 } 439 }
197 440
198 //use Snell's Law to calculate the transmitted angle 441 //use Snell's Law to calculate the transmitted angle
199 - T cos_theta_i = k.norm().dot(-P.norm()); //compute the cosine of theta_i 442 + //vec3<T> plane_normal = -P.n();
  443 + T cos_theta_i = k.norm().dot(-plane_normal); //compute the cosine of theta_i
200 T theta_i = acos(cos_theta_i); //compute theta_i 444 T theta_i = acos(cos_theta_i); //compute theta_i
201 - T sin_theta_t = (1/nr) * sin(theta_i); //compute the sine of theta_t using Snell's law  
202 - T theta_t = asin(sin_theta_t); //compute the cosine of theta_t 445 + std::complex<T> sin_theta_t = (cOne / nr) * sin(theta_i); //compute the sine of theta_t using Snell's law
  446 + std::complex<T> theta_t = asin(sin_theta_t); //compute the cosine of theta_t
203 447
204 - bool tir = false; //flag for total internal reflection  
205 - if(theta_t != theta_t){  
206 - tir = true;  
207 - theta_t = stim::PI / (T)2;  
208 - } 448 + //bool tir = false; //flag for total internal reflection
  449 + //if(theta_t != theta_t){
  450 + // tir = true;
  451 + // theta_t = stim::PI / (T)2;
  452 + //}
209 453
210 //handle the degenerate case where theta_i is 0 (the plane wave hits head-on) 454 //handle the degenerate case where theta_i is 0 (the plane wave hits head-on)
211 if(theta_i == 0){ 455 if(theta_i == 0){
212 - T rp = (1 - nr) / (1 + nr); //compute the Fresnel coefficients  
213 - T tp = 2 / (1 + nr);  
214 - vec<T> kr = -k;  
215 - vec<T> kt = k * nr; //set the k vectors for theta_i = 0  
216 - vec< complex<T> > Er = E0 * rp; //compute the E vectors  
217 - vec< complex<T> > Et = E0 * tp;  
218 - T phase_t = P.p().dot(k - kt); //compute the phase offset  
219 - T phase_r = P.p().dot(k - kr); 456 + std::complex<T> rp = (cOne - nr) / (cOne + nr); //compute the Fresnel coefficients
  457 + std::complex<T> tp = (cOne * cTwo) / (cOne + nr);
  458 + vec3<T> kr = -k;
  459 + vec3<T> kt = k * nr; //set the k vectors for theta_i = 0
  460 + vec3< std::complex<T> > Er = E * rp; //compute the E vectors
  461 + vec3< std::complex<T> > Et = E * tp;
  462 + T phase_t = plane_position.dot(k - kt); //compute the phase offset
  463 + T phase_r = plane_position.dot(k - kr);
220 464
221 //create the plane waves 465 //create the plane waves
222 - r = planewave<T>(kr, Er, phase_r);  
223 - t = planewave<T>(kt, Et, phase_t); 466 + //r = planewave<T>(kr, Er, phase_r);
  467 + //t = planewave<T>(kt, Et, phase_t);
  468 +
  469 + r = planewave(kr[0], kr[1], kr[2], Er[0], Er[1], Er[2]);
  470 + t = planewave(kt[0], kt[1], kt[2], Et[0], Et[1], Et[2]);
  471 +
224 return; 472 return;
225 } 473 }
226 474
@@ -230,57 +478,61 @@ public: @@ -230,57 +478,61 @@ public:
230 rp = tan(theta_t - theta_i) / tan(theta_t + theta_i); 478 rp = tan(theta_t - theta_i) / tan(theta_t + theta_i);
231 rs = sin(theta_t - theta_i) / sin(theta_t + theta_i); 479 rs = sin(theta_t - theta_i) / sin(theta_t + theta_i);
232 480
233 - if(tir){  
234 - tp = ts = 0;  
235 - }  
236 - else{ 481 + //if (tir) {
  482 + // tp = ts = 0;
  483 + //}
  484 + //else
  485 + {
237 tp = ( 2 * sin(theta_t) * cos(theta_i) ) / ( sin(theta_t + theta_i) * cos(theta_t - theta_i) ); 486 tp = ( 2 * sin(theta_t) * cos(theta_i) ) / ( sin(theta_t + theta_i) * cos(theta_t - theta_i) );
238 ts = ( 2 * sin(theta_t) * cos(theta_i) ) / sin(theta_t + theta_i); 487 ts = ( 2 * sin(theta_t) * cos(theta_i) ) / sin(theta_t + theta_i);
239 } 488 }
240 489
241 //compute the coordinate space for the plane of incidence 490 //compute the coordinate space for the plane of incidence
242 - vec<T> z_hat = -P.norm();  
243 - vec<T> y_hat = P.parallel(k).norm();  
244 - vec<T> x_hat = y_hat.cross(z_hat).norm(); 491 + vec3<T> z_hat = -plane_normal;
  492 + vec3<T> y_hat = plane_parallel(k, plane_normal).norm();
  493 + vec3<T> x_hat = y_hat.cross(z_hat).norm();
245 494
246 //compute the k vectors for r and t 495 //compute the k vectors for r and t
247 - vec<T> kr, kt;  
248 - kr = ( y_hat * sin(theta_i) - z_hat * cos(theta_i) ) * kmag();  
249 - kt = ( y_hat * sin(theta_t) + z_hat * cos(theta_t) ) * kmag() * nr; 496 + vec3<T> kr, kt;
  497 + kr = ( y_hat * sin(theta_i) - z_hat * cos(theta_i) ) * kmag;
  498 + kt = ( y_hat * sin(theta_t) + z_hat * cos(theta_t) ) * kmag * nr;
250 499
251 //compute the magnitude of the p- and s-polarized components of the incident E vector 500 //compute the magnitude of the p- and s-polarized components of the incident E vector
252 - complex<T> Ei_s = E0.dot(x_hat);  
253 - int sgn = E0.dot(y_hat).sgn();  
254 - vec< complex<T> > cx_hat = x_hat;  
255 - complex<T> Ei_p = ( E0 - cx_hat * Ei_s ).len() * sgn; 501 + std::complex<T> Ei_s = E.dot(x_hat);
  502 + //int sign = sgn(E0.dot(y_hat));
  503 + vec3< std::complex<T> > cx_hat = x_hat;
  504 + std::complex<T> Ei_p = (E - cx_hat * Ei_s).len();// *(T)sign;
256 //compute the magnitude of the p- and s-polarized components of the reflected E vector 505 //compute the magnitude of the p- and s-polarized components of the reflected E vector
257 - complex<T> Er_s = Ei_s * rs;  
258 - complex<T> Er_p = Ei_p * rp; 506 + std::complex<T> Er_s = Ei_s * rs;
  507 + std::complex<T> Er_p = Ei_p * rp;
259 //compute the magnitude of the p- and s-polarized components of the transmitted E vector 508 //compute the magnitude of the p- and s-polarized components of the transmitted E vector
260 - complex<T> Et_s = Ei_s * ts;  
261 - complex<T> Et_p = Ei_p * tp; 509 + std::complex<T> Et_s = Ei_s * ts;
  510 + std::complex<T> Et_p = Ei_p * tp;
262 511
263 //compute the reflected E vector 512 //compute the reflected E vector
264 - vec< complex<T> > Er = vec< complex<T> >(y_hat * cos(theta_i) + z_hat * sin(theta_i)) * Er_p + cx_hat * Er_s; 513 + vec3< std::complex<T> > Er = vec3< std::complex<T> >(y_hat * cos(theta_i) + z_hat * sin(theta_i)) * Er_p + cx_hat * Er_s;
265 //compute the transmitted E vector 514 //compute the transmitted E vector
266 - vec< complex<T> > Et = vec< complex<T> >(y_hat * cos(theta_t) - z_hat * sin(theta_t)) * Et_p + cx_hat * Et_s; 515 + vec3< std::complex<T> > Et = vec3< std::complex<T> >(y_hat * cos(theta_t) - z_hat * sin(theta_t)) * Et_p + cx_hat * Et_s;
267 516
268 - T phase_t = P.p().dot(k - kt);  
269 - T phase_r = P.p().dot(k - kr); 517 + T phase_t = plane_position.dot(k - kt);
  518 + T phase_r = plane_position.dot(k - kr);
270 519
271 //create the plane waves 520 //create the plane waves
272 - r.k = kr;  
273 - r.E0 = Er * exp( complex<T>(0, phase_r) ); 521 + //r.m_k = kr;
  522 + //r.m_E = Er * exp( complex<T>(0, phase_r) );
274 523
275 - t.k = kt;  
276 - t.E0 = Et * exp( complex<T>(0, phase_t) );  
277 - } 524 + //t.m_k = kt;
  525 + //t.m_E = Et * exp( complex<T>(0, phase_t) );
  526 +
  527 + r = planewave(kr[0], kr[1], kr[2], Er[0], Er[1], Er[2]);
  528 + t = planewave(kt[0], kt[1], kt[2], Et[0], Et[1], Et[2]);
  529 + }*/
278 530
279 std::string str() 531 std::string str()
280 { 532 {
281 std::stringstream ss; 533 std::stringstream ss;
282 - ss<<"Plane Wave:"<<std::endl;  
283 - ss<<" "<<E0<<" e^i ( "<<k<<" . r )"; 534 + ss << "k: " << m_k << std::endl;
  535 + ss << "E: " << m_E << std::endl;
284 return ss.str(); 536 return ss.str();
285 } 537 }
286 }; //end planewave class 538 }; //end planewave class