Commit 14634fcaed80d5365b4492ba31d049b360eac1ec
1 parent
4fcb3a86
edits to update scattering code
Showing
6 changed files
with
420 additions
and
101 deletions
Show diff stats
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 |
python/optics.py
@@ -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]; |
stim/math/vec3.h
@@ -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 |