PyPO User Manual
 
Loading...
Searching...
No Matches
Propagation.h
Go to the documentation of this file.
1#include <iostream>
2#include <vector>
3#include <complex>
4#include <array>
5#include <cmath>
6#include <thread>
7#include <iomanip>
8#include <algorithm>
9#include <new>
10
11#include "Utils.h"
12#include "Structs.h"
13#include "InterfaceReflector.h"
14
15#ifndef __Propagation_h
16#define __Propagation_h
17
18/*! \file Propagation.h
19 \brief Functions for PO calculations on CPU.
20
21 Provides functions for performing PO calculations on the CPU.
22*/
23
24/**
25 * Main class for running PO calculations.
26 *
27 * Contains functions that run PO calculations. All calculations can be performed in a parallel way.
28 *
29 * @see Utils
30 * @see Structs
31 * @see InterfaceReflector
32 */
33template <class T, class U, class V, class W>
35{
36 T k; /**<Wavenumber of radiation, double/float.*/
37 int numThreads; /**<Number of computing threads to employ.*/
38 int gs; /**<Number of cells on source surface.*/
39 int gt; /**<Number of cells on target surface.*/
40
41 int step; /**<Number of threads per block.*/
42
43 T t_direction; /**<Time direction (experimental!).*/
44
45 T EPS; /**<Relative electric permittivity of source medium, double/float.*/
46 T prefactor;
47 T C_L; /**<Speed of light in vacuum, in mm / s.*/
48 T MU_0; /**<Magnetic permeability.*/
49 T EPS_VAC; /**<Vacuum electric permittivity.*/
50 T ZETA; /**<Impedance of surrounding medium.*/
51 T ZETA_INV; /**<Conductance of surrounding medium.*/
52 T PIf; /**<Template pi (redundant?).*/
53 T Three; /**<Template 3*/
54
55
56 std::complex<T> j; /**<Complex unit.*/
57 std::complex<T> z0; /**<Complex zero.*/
58
59 std::array<std::array<T, 3>, 3> eye; /**<Real-valued 3x3 unit matrix.*/
60
61 void joinThreads();
62
63 void _debugArray(T *arr, int idx);
64 void _debugArray(std::array<T, 3> arr);
65 void _debugArray(std::array<std::complex<T>, 3> arr);
66
67public:
68
69 std::vector<std::thread> threadPool; /**<Vector of thread objects.*/
70
71 Propagation(T omega, int numThreads, int gs, int gt, T epsilon, T t_direction, bool verbose = false);
72
73 // Make T precision utility kit
74 Utils<T> ut; /**<Utils object for vector operations.*/
75
76 // Functions for propagating fields between two surfaces
77 void propagateBeam_JM_PEC(int start, int stop,
78 V *cs, V *ct,
79 W *currents,
80 int gmode, int ncx, int ncy,
81 U *res);
82
83 void propagateBeam_JM(int start, int stop,
84 V *cs, V *ct,
85 W *currents,
86 int gmode, int ncx, int ncy,
87 U *res);
88
89 void propagateBeam_EH(int start, int stop,
90 V *cs, V *ct,
91 W *currents,
92 int gmode, int ncx, int ncy,
93 U *res);
94
95 void propagateBeam_JMEH_PEC(int start, int stop,
96 V *cs, V *ct,
97 W *currents,
98 int gmode, int ncx, int ncy,
99 U *res);
100
101 void propagateBeam_JMEH(int start, int stop,
102 V *cs, V *ct,
103 W *currents,
104 int gmode, int ncx, int ncy,
105 U *res);
106
107 void propagateBeam_EHP(int start, int stop,
108 V *cs, V *ct,
109 W *currents,
110 int gmode, int ncx, int ncy,
111 U *res);
112
113 std::array<std::array<std::complex<T>, 3>, 2> fieldAtPoint(V *cs, W *currents,
114 int gmode, int ncx, int ncy,
115 const std::array<T, 3> &point_target);
116
117 std::array<std::array<std::complex<T>, 3>, 2> fieldAtPoint_Old(V *cs, W *currents,
118 const std::array<T, 3> &point_target);
119
120
121 void parallelProp_JM(V *cs, V *ct,
122 W *currents,
123 int gmode, int ncx, int ncy,
124 U *res);
125
126 void parallelProp_EH(V *cs, V *ct,
127 W *currents,
128 int gmode, int ncx, int ncy,
129 U *res);
130
131 void parallelProp_JMEH(V *cs, V *ct,
132 W *currents,
133 int gmode, int ncx, int ncy,
134 U *res);
135
136 void parallelProp_EHP(V *cs, V *ct,
137 W *currents,
138 int gmode, int ncx, int ncy,
139 U *res);
140
141 // Functions for calculating angular far-field from reflector directly - no phase term
142 void propagateToFarField(int start, int stop,
143 V *cs, V *ct,
144 W *currents,
145 int gmode, int ncx, int ncy,
146 U *res);
147
148 std::array<std::array<std::complex<T>, 3>, 2> farfieldAtPoint(V *cs, W *currents,
149 int gmode, int ncx, int ncy,
150 const std::array<T, 3> &point_target);
151
152 std::array<std::array<std::complex<T>, 3>, 2> farfieldAtPoint_Old(V *cs, W *currents,
153 const std::array<T, 3> &point_target);
154
155 void parallelFarField(V *cs, V *ct,
156 W *currents,
157 int gmode, int ncx, int ncy,
158 U *res);
159
160 // Scalar propagation
161 void propagateScalarBeam(int start, int stop,
162 V *cs, V *ct,
163 W *field,
164 int gmode, int ncx, int ncy,
165 U *res);
166
167
168 std::complex<T> fieldScalarAtPoint(V *cs, W *field,
169 int gmode, int ncx, int ncy,
170 const std::array<T, 3> &point_target);
171
172 void parallelPropScalar(V *cs, V *ct,
173 W *field,
174 int gmode, int ncx, int ncy,
175 U *res);
176
177};
178
179/**
180 * Constructor.
181 *
182 * Set important parameters internally, given input.
183 *
184 * @param omega Angular frequency of radiation, double/float.
185 * @param numThreads Number of computing threads to employ.
186 * @param gs Number of cells on source surface.
187 * @param gt Number of cells on target grid.
188 * @param epsilon Relative electric permittivity of source surface.
189 * @param t_direction Time direction. This changes the sign in the Green's function used to propagate the field.
190 * t_direction is -1 for forward propagation, +1 for backward
191 * @param verbose Whether to print internal state info.
192 */
193template <class T, class U, class V, class W>
194Propagation<T, U, V, W>::Propagation(T k, int numThreads, int gs, int gt, T epsilon, T t_direction, bool verbose)
195{
196 this->Three = 3.0f;
197 this->PIf = 3.14159265359f;
198 this->C_L = 2.99792458e8f; // m s^-1
199 this->MU_0 = 1.2566370614e-6f; // kg m s^-2 A^-2
200 this->EPS_VAC = 1 / (MU_0 * C_L*C_L);
201 this->EPS = epsilon * EPS_VAC; // epsilon is relative permeability
202 this->ZETA = sqrt(MU_0 / EPS);
203 this->ZETA_INV = 1 / ZETA;
204
205 //printf("EPS %.16g\n", ZETA); // %s is format specifier
206 //printf("MU_0 %.16g\n", ZETA); // %s is format specifier
207 //printf("ZETA %.16g\n", ZETA); // %s is format specifier
208
209 std::complex<T> j(0., 1.);
210 std::complex<T> z0(0., 0.);
211 this->j = j;
212 this->z0 = z0;
213
214 this->k = k;
215 //printf("k %.16g\n", k); // %s is format specifier
216
217 this->prefactor = k*k / (4.*PIf);
218 //printf("prefactor %.16g\n", prefactor); // %s is format specifier
219
220 this->numThreads = numThreads;
221 this->gs = gs;
222 this->gt = gt;
223
224 this->step = ceil(gt / numThreads);
225
226 threadPool.resize(numThreads);
227
228 this->t_direction = t_direction;
229
230 this->eye[0].fill(0);
231 this->eye[1].fill(0);
232 this->eye[2].fill(0);
233
234 this->eye[0][0] = 1;
235 this->eye[1][1] = 1;
236 this->eye[2][2] = 1;
237
238 if (verbose)
239 {
240 printf("***--------- PO info ---------***\n");
241 printf("--- Source : %d cells\n", gs);
242 printf("--- Target : %d cells\n", gt);
243 printf("--- Wavenumber : %.3f / mm\n", k);
244 printf("--- Threads : %d\n", numThreads);
245 printf("--- Device : CPU\n");
246 printf("***--------- PO info ---------***\n");
247 printf("\n");
248 }
249}
250
251
252/**
253 * Calculate JM on target - PEC version.
254 *
255 * Calculate the J, M currents on a perfectly conducting target surface.
256 *
257 * @param start Index of first loop iteration in parallel block.
258 * @param stop Index of last loop iteration in parallel block.
259 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
260 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
261 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
262 * @param res Pointer to c2Bundle or c2Bundlef object, to be filled with calculation results.
263 *
264 * @see reflcontainer
265 * @see reflcontainerf
266 * @see c2Bundle
267 * @see c2Bundlef
268 */
269template <class T, class U, class V, class W>
271 V *cs, V *ct,
272 W *currents,
273 int gmode, int ncx, int ncy,
274 U *res)
275{
276 // Arrays of Ts
277 std::array<T, 3> point; // Point on target
278 std::array<T, 3> norms; // Normal vector at point
279
280 // Arrays of complex Ts to hold return values
281 std::array<std::complex<T>, 3> jt;
282 std::array<std::complex<T>, 3> mt;
283
284 // Return containers
285 std::array<std::array<std::complex<T>, 3>, 2> beam_e_h; // Container for storing fieldAtPoint return
286
287 int jc = 0; // Counter
288
289 for(int i=start; i<stop; i++)
290 {
291
292 point[0] = ct->x[i];
293 point[1] = ct->y[i];
294 point[2] = ct->z[i];
295
296 norms[0] = ct->nx[i];
297 norms[1] = ct->ny[i];
298 norms[2] = ct->nz[i];
299
300 // Calculate total incoming E and H field at point on target
301 beam_e_h = fieldAtPoint(cs, currents,
302 gmode, ncx, ncy,
303 point);
304
305 ut.ext(norms, beam_e_h[1], jt);
306
307 res->r1x[i] = 2*jt[0].real();
308 res->r1y[i] = 2*jt[1].real();
309 res->r1z[i] = 2*jt[2].real();
310
311 res->i1x[i] = 2*jt[0].imag();
312 res->i1y[i] = 2*jt[1].imag();
313 res->i1z[i] = 2*jt[2].imag();
314
315 res->r2x[i] = 0;
316 res->r2y[i] = 0;
317 res->r2z[i] = 0;
318
319 res->i2x[i] = 0;
320 res->i2y[i] = 0;
321 res->i2z[i] = 0;
322 }
323}
324
325/**
326 * Calculate JM on target.
327 *
328 * Calculate the J, M currents on a target surface.
329 *
330 * @param start Index of first loop iteration in parallel block.
331 * @param stop Index of last loop iteration in parallel block.
332 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
333 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
334 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
335 * @param res Pointer to c2Bundle or c2Bundlef object, to be filled with calculation results.
336 *
337 * @see reflcontainer
338 * @see reflcontainerf
339 * @see c2Bundle
340 * @see c2Bundlef
341 */
342template <class T, class U, class V, class W>
344 V *cs, V *ct,
345 W *currents,
346 int gmode, int ncx, int ncy,
347 U *res)
348{
349 // Scalars (T & complex T)
350 std::complex<T> e_dot_p_r_perp; // E-field - perpendicular reflected POI polarization vector dot product
351 std::complex<T> e_dot_p_r_parr; // E-field - parallel reflected POI polarization vector dot product
352
353 // Arrays of Ts
354 std::array<T, 3> S_i_norm; // Normalized incoming Poynting vector
355 std::array<T, 3> p_i_perp; // Perpendicular incoming POI polarization vector
356 std::array<T, 3> p_i_parr; // Parallel incoming POI polarization vector
357 std::array<T, 3> S_r_norm; // Normalized reflected Poynting vector
358 std::array<T, 3> p_r_perp; // Perpendicular reflected POI polarization vector
359 std::array<T, 3> p_r_parr; // Parallel reflected POI polarization vector
360 std::array<T, 3> S_out_n; // Container for Poynting-normal ext products
361 std::array<T, 3> point; // Point on target
362 std::array<T, 3> norms; // Normal vector at point
363 std::array<T, 3> e_out_h_r; // Real part of E-field - H-field ext product
364
365 // Arrays of complex Ts
366 std::array<std::complex<T>, 3> e_r; // Reflected E-field
367 std::array<std::complex<T>, 3> h_r; // Reflected H-field
368 std::array<std::complex<T>, 3> n_out_e_i_r; // Electric current
369 std::array<std::complex<T>, 3> temp1; // Temporary container 1 for intermediate irrelevant values
370 std::array<std::complex<T>, 3> temp2; // Temporary container 2
371
372 std::array<std::complex<T>, 3> jt;
373 std::array<std::complex<T>, 3> mt;
374
375 // Return containers
376 std::array<std::array<std::complex<T>, 3>, 2> beam_e_h; // Container for storing fieldAtPoint return
377
378 int jc = 0; // Counter
379
380 for(int i=start; i<stop; i++)
381 {
382
383 point[0] = ct->x[i];
384 point[1] = ct->y[i];
385 point[2] = ct->z[i];
386
387 norms[0] = ct->nx[i];
388 norms[1] = ct->ny[i];
389 norms[2] = ct->nz[i];
390
391 // Calculate total incoming E and H field at point on target
392 beam_e_h = fieldAtPoint(cs, currents,
393 gmode, ncx, ncy,
394 point);
395
396 // Calculate normalized incoming poynting vector.
397 ut.conj(beam_e_h[1], temp1); // h_conj
398 ut.ext(beam_e_h[0], temp1, temp2); // e_out_h
399
400 for (int n=0; n<3; n++)
401 {
402 e_out_h_r[n] = temp2[n].real(); // e_out_h_r
403 }
404
405 //std::cout << this->Et_container.size() << std::endl;
406
407 ut.normalize(e_out_h_r, S_i_norm); // S_i_norm
408
409 // Calculate incoming polarization vectors
410 ut.ext(S_i_norm, norms, S_out_n); // S_i_out_n
411 ut.normalize(S_out_n, p_i_perp); // p_i_perp
412 ut.ext(p_i_perp, S_i_norm, p_i_parr); // p_i_parr
413
414 // Now calculate reflected poynting vector.
415 ut.snell(S_i_norm, norms, S_r_norm); // S_r_norm
416
417 // Calculate normalised reflected polarization vectors
418 ut.ext(S_r_norm, norms, S_out_n); // S_r_out_n
419 ut.normalize(S_out_n, p_r_perp); // p_r_perp
420 ut.ext(S_r_norm, p_r_perp, p_r_parr); // p_r_parr
421
422 // Now, calculate reflected field from target
423 ut.dot(beam_e_h[0], p_r_perp, e_dot_p_r_perp); // e_dot_p_r_perp
424 ut.dot(beam_e_h[0], p_r_parr, e_dot_p_r_parr); // e_dot_p_r_parr
425
426 // Calculate reflected field from reflection matrix
427 for(int n=0; n<3; n++)
428 {
429 e_r[n] = -e_dot_p_r_perp * p_i_perp[n] - e_dot_p_r_parr * p_i_parr[n];
430
431 //this->Et_container[k][i] = e_r[k];
432 }
433
434 ut.ext(S_r_norm, e_r, temp1); // h_r_temp
435 ut.s_mult(temp1, ZETA_INV, h_r); // h_r
436
437 for(int n=0; n<3; n++)
438 {
439 temp1[n] = e_r[n] + beam_e_h[0][n]; // e_i_r
440 temp2[n] = h_r[n] + beam_e_h[1][n]; // h_i_r
441 }
442
443 ut.ext(norms, temp2, jt);
444 ut.ext(norms, temp1, n_out_e_i_r);
445 ut.s_mult(n_out_e_i_r, -1., mt);
446
447 res->r1x[i] = jt[0].real();
448 res->r1y[i] = jt[1].real();
449 res->r1z[i] = jt[2].real();
450
451 res->i1x[i] = jt[0].imag();
452 res->i1y[i] = jt[1].imag();
453 res->i1z[i] = jt[2].imag();
454
455 res->r2x[i] = mt[0].real();
456 res->r2y[i] = mt[1].real();
457 res->r2z[i] = mt[2].real();
458
459 res->i2x[i] = mt[0].imag();
460 res->i2y[i] = mt[1].imag();
461 res->i2z[i] = mt[2].imag();
462 }
463}
464
465/**
466 * Calculate JMEH on target - PEC version.
467 *
468 * Calculate the J, M currents and E, H fields on a perfectly conducting target surface.
469 *
470 * @param start Index of first loop iteration in parallel block.
471 * @param stop Index of last loop iteration in parallel block.
472 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
473 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
474 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
475 * @param res Pointer to c2Bundle or c2Bundlef object, to be filled with calculation results.
476 *
477 * @see reflcontainer
478 * @see reflcontainerf
479 * @see c2Bundle
480 * @see c2Bundlef
481 */
482template <class T, class U, class V, class W>
484 V *cs, V *ct,
485 W *currents,
486 int gmode, int ncx, int ncy,
487 U *res)
488{
489 // Arrays of Ts
490 std::array<T, 3> point; // Point on target
491 std::array<T, 3> norms; // Normal vector at point
492
493 // Arrays of complex Ts to hold return values
494 std::array<std::complex<T>, 3> jt;
495 std::array<std::complex<T>, 3> mt;
496
497 // Return containers
498 std::array<std::array<std::complex<T>, 3>, 2> beam_e_h; // Container for storing fieldAtPoint return
499
500 int jc = 0; // Counter
501
502 for(int i=start; i<stop; i++)
503 {
504
505 point[0] = ct->x[i];
506 point[1] = ct->y[i];
507 point[2] = ct->z[i];
508
509 norms[0] = ct->nx[i];
510 norms[1] = ct->ny[i];
511 norms[2] = ct->nz[i];
512
513 // Calculate total incoming E and H field at point on target
514 beam_e_h = fieldAtPoint(cs, currents,
515 gmode, ncx, ncy,
516 point);
517
518 res->r3x[i] = beam_e_h[0][0].real();
519 res->r3y[i] = beam_e_h[0][1].real();
520 res->r3z[i] = beam_e_h[0][2].real();
521
522 res->i3x[i] = beam_e_h[0][0].imag();
523 res->i3y[i] = beam_e_h[0][1].imag();
524 res->i3z[i] = beam_e_h[0][2].imag();
525
526 res->r4x[i] = beam_e_h[1][0].real();
527 res->r4y[i] = beam_e_h[1][1].real();
528 res->r4z[i] = beam_e_h[1][2].real();
529
530 res->i4x[i] = beam_e_h[1][0].imag();
531 res->i4y[i] = beam_e_h[1][1].imag();
532 res->i4z[i] = beam_e_h[1][2].imag();
533
534 // J_e = 2 n ^ H_inc
535 ut.ext(norms, beam_e_h[1], jt);
536
537 res->r1x[i] = 2*jt[0].real();
538 res->r1y[i] = 2*jt[1].real();
539 res->r1z[i] = 2*jt[2].real();
540
541 res->i1x[i] = 2*jt[0].imag();
542 res->i1y[i] = 2*jt[1].imag();
543 res->i1z[i] = 2*jt[2].imag();
544
545 // J_m = 0
546
547 res->r2x[i] = 0;
548 res->r2y[i] = 0;
549 res->r2z[i] = 0;
550
551 res->i2x[i] = 0;
552 res->i2y[i] = 0;
553 res->i2z[i] = 0;
554 }
555}
556
557/**
558 * Calculate JMEH on target.
559 *
560 * Calculate the E, H fields and J, M currents on a target surface.
561 *
562 * @param start Index of first loop iteration in parallel block.
563 * @param stop Index of last loop iteration in parallel block.
564 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
565 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
566 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
567 * @param res Pointer to c2Bundle or c2Bundlef object, to be filled with calculation results.
568 *
569 * @see reflcontainer
570 * @see reflcontainerf
571 * @see c2Bundle
572 * @see c2Bundlef
573 */
574template <class T, class U, class V, class W>
576 V *cs, V *ct,
577 W *currents,
578 int gmode, int ncx, int ncy,
579 U *res)
580{
581 // Arrays of Ts
582 std::array<T, 3> point; // Point on target
583
584 // Return containers
585 std::array<std::array<std::complex<T>, 3>, 2> beam_e_h; // Container for storing fieldAtPoint return
586
587 int jc = 0; // Counter
588
589 for(int i=start; i<stop; i++)
590 {
591
592 point[0] = ct->x[i];
593 point[1] = ct->y[i];
594 point[2] = ct->z[i];
595
596 // Calculate total incoming E and H field at point on target
597 beam_e_h = fieldAtPoint(cs, currents,
598 gmode, ncx, ncy,
599 point);
600
601 res->r1x[i] = beam_e_h[0][0].real();
602 res->r1y[i] = beam_e_h[0][1].real();
603 res->r1z[i] = beam_e_h[0][2].real();
604
605 res->i1x[i] = beam_e_h[0][0].imag();
606 res->i1y[i] = beam_e_h[0][1].imag();
607 res->i1z[i] = beam_e_h[0][2].imag();
608
609 res->r2x[i] = beam_e_h[1][0].real();
610 res->r2y[i] = beam_e_h[1][1].real();
611 res->r2z[i] = beam_e_h[1][2].real();
612
613 res->i2x[i] = beam_e_h[1][0].imag();
614 res->i2y[i] = beam_e_h[1][1].imag();
615 res->i2z[i] = beam_e_h[1][2].imag();
616 }
617}
618
619/**
620 * Calculate JM and EH on target.
621 *
622 * Calculate the J, M currents and E, H fields on a target surface.
623 *
624 * @param start Index of first loop iteration in parallel block.
625 * @param stop Index of last loop iteration in parallel block.
626 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
627 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
628 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
629 * @param res Pointer to c4Bundle or c4Bundlef object, to be filled with calculation results.
630 *
631 * @see reflcontainer
632 * @see reflcontainerf
633 * @see c2Bundle
634 * @see c2Bundlef
635 * @see c4Bundle
636 * @see c4Bundlef
637 */
638template <class T, class U, class V, class W>
640 V *cs, V *ct,
641 W *currents,
642 int gmode, int ncx, int ncy,
643 U *res)
644{
645 // Scalars (T & complex T)
646 std::complex<T> e_dot_p_r_perp; // E-field - perpendicular reflected POI polarization vector dot product
647 std::complex<T> e_dot_p_r_parr; // E-field - parallel reflected POI polarization vector dot product
648
649 // Arrays of Ts
650 std::array<T, 3> S_i_norm; // Normalized incoming Poynting vector
651 std::array<T, 3> p_i_perp; // Perpendicular incoming POI polarization vector
652 std::array<T, 3> p_i_parr; // Parallel incoming POI polarization vector
653 std::array<T, 3> S_r_norm; // Normalized reflected Poynting vector
654 std::array<T, 3> p_r_perp; // Perpendicular reflected POI polarization vector
655 std::array<T, 3> p_r_parr; // Parallel reflected POI polarization vector
656 std::array<T, 3> S_out_n; // Container for Poynting-normal ext products
657 std::array<T, 3> point; // Point on target
658 std::array<T, 3> norms; // Normal vector at point
659 std::array<T, 3> e_out_h_r; // Real part of E-field - H-field ext product
660
661 // Arrays of complex Ts
662 std::array<std::complex<T>, 3> e_r; // Reflected E-field
663 std::array<std::complex<T>, 3> h_r; // Reflected H-field
664 std::array<std::complex<T>, 3> n_out_e_i_r; // Electric current
665 std::array<std::complex<T>, 3> temp1; // Temporary container 1 for intermediate irrelevant values
666 std::array<std::complex<T>, 3> temp2; // Temporary container 2
667
668 std::array<std::complex<T>, 3> jt;
669 std::array<std::complex<T>, 3> mt;
670
671 // Return containers
672 std::array<std::array<std::complex<T>, 3>, 2> beam_e_h; // Container for storing fieldAtPoint return
673
674 int jc = 0; // Counter
675
676 for(int i=start; i<stop; i++)
677 {
678
679 point[0] = ct->x[i];
680 point[1] = ct->y[i];
681 point[2] = ct->z[i];
682
683 norms[0] = ct->nx[i];
684 norms[1] = ct->ny[i];
685 norms[2] = ct->nz[i];
686
687 // Calculate total incoming E and H field at point on target
688 beam_e_h = fieldAtPoint(cs, currents,
689 gmode, ncx, ncy,
690 point);
691
692 //res->r1x[i] = 0.;//beam_e_h[0][0].real();
693
694 res->r3x[i] = beam_e_h[0][0].real();
695 res->r3y[i] = beam_e_h[0][1].real();
696 res->r3z[i] = beam_e_h[0][2].real();
697
698 res->i3x[i] = beam_e_h[0][0].imag();
699 res->i3y[i] = beam_e_h[0][1].imag();
700 res->i3z[i] = beam_e_h[0][2].imag();
701
702 res->r4x[i] = beam_e_h[1][0].real();
703 res->r4y[i] = beam_e_h[1][1].real();
704 res->r4z[i] = beam_e_h[1][2].real();
705
706 res->i4x[i] = beam_e_h[1][0].imag();
707 res->i4y[i] = beam_e_h[1][1].imag();
708 res->i4z[i] = beam_e_h[1][2].imag();
709
710 // Calculate normalised incoming poynting vector.
711 ut.conj(beam_e_h[1], temp1); // h_conj
712
713 ut.ext(beam_e_h[0], temp1, temp2); // e_out_h
714
715 for (int n=0; n<3; n++)
716 {
717 e_out_h_r[n] = temp2[n].real(); // e_out_h_r
718 }
719
720 //std::cout << this->Et_container.size() << std::endl;
721
722 ut.normalize(e_out_h_r, S_i_norm); // S_i_norm
723
724 // Calculate incoming polarization vectors
725 ut.ext(S_i_norm, norms, S_out_n); // S_i_out_n
726
727 ut.normalize(S_out_n, p_i_perp); // p_i_perp
728 ut.ext(p_i_perp, S_i_norm, p_i_parr); // p_i_parr
729
730 // Now calculate reflected poynting vector.
731 ut.snell(S_i_norm, norms, S_r_norm); // S_r_norm
732
733 // Calculate normalised reflected polarization vectors
734 ut.ext(S_r_norm, norms, S_out_n); // S_r_out_n
735
736 ut.normalize(S_out_n, p_r_perp); // p_r_perp
737 ut.ext(S_r_norm, p_r_perp, p_r_parr); // p_r_parr
738
739 // Now, calculate reflected field from target
740 ut.dot(beam_e_h[0], p_r_perp, e_dot_p_r_perp); // e_dot_p_r_perp
741 ut.dot(beam_e_h[0], p_r_parr, e_dot_p_r_parr); // e_dot_p_r_parr
742
743 //res->r1x[i] = beam_e_h[0][0].real();
744
745 // Calculate reflected field from reflection matrix
746 for(int n=0; n<3; n++)
747 {
748 e_r[n] = -e_dot_p_r_perp * p_i_perp[n] - e_dot_p_r_parr * p_i_parr[n];
749
750 //this->Et_container[k][i] = e_r[k];
751 }
752
753 ut.ext(S_r_norm, e_r, temp1); // h_r_temp
754 ut.s_mult(temp1, ZETA_INV, h_r); // h_r
755
756 for(int n=0; n<3; n++)
757 {
758 temp1[n] = e_r[n] + beam_e_h[0][n]; // e_i_r
759 temp2[n] = h_r[n] + beam_e_h[1][n]; // h_i_r
760 }
761
762 ut.ext(norms, temp2, jt);
763 ut.ext(norms, temp1, n_out_e_i_r);
764 ut.s_mult(n_out_e_i_r, -1., mt);
765
766
767
768 res->r1x[i] = jt[0].real();
769 res->r1y[i] = jt[1].real();
770 res->r1z[i] = jt[2].real();
771
772 res->i1x[i] = jt[0].imag();
773 res->i1y[i] = jt[1].imag();
774 res->i1z[i] = jt[2].imag();
775
776 res->r2x[i] = mt[0].real();
777 res->r2y[i] = mt[1].real();
778 res->r2z[i] = mt[2].real();
779
780 res->i2x[i] = mt[0].imag();
781 res->i2y[i] = mt[1].imag();
782 res->i2z[i] = mt[2].imag();
783 }
784}
785
786/**
787 * Calculate reflected EH and P on target.
788 *
789 * Calculate the reflected E, H fields and P, the reflected Poynting vector field, on a target surface.
790 *
791 * @param start Index of first loop iteration in parallel block.
792 * @param stop Index of last loop iteration in parallel block.
793 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
794 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
795 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
796 * @param res Pointer to c2rBundle or c2rBundlef object, to be filled with calculation results.
797 *
798 * @see reflcontainer
799 * @see reflcontainerf
800 * @see c2Bundle
801 * @see c2Bundlef
802 * @see c2rBundle
803 * @see c2rBundlef
804 */
805template <class T, class U, class V, class W>
807 V *cs, V *ct,
808 W *currents,
809 int gmode, int ncx, int ncy,
810 U *res)
811{
812 // Scalars (T & complex T)
813 std::complex<T> e_dot_p_r_perp; // E-field - perpendicular reflected POI polarization vector dot product
814 std::complex<T> e_dot_p_r_parr; // E-field - parallel reflected POI polarization vector dot product
815
816 // Arrays of Ts
817 std::array<T, 3> S_i_norm; // Normalized incoming Poynting vector
818 std::array<T, 3> p_i_perp; // Perpendicular incoming POI polarization vector
819 std::array<T, 3> p_i_parr; // Parallel incoming POI polarization vector
820 std::array<T, 3> S_r_norm; // Normalized reflected Poynting vector
821 std::array<T, 3> p_r_perp; // Perpendicular reflected POI polarization vector
822 std::array<T, 3> p_r_parr; // Parallel reflected POI polarization vector
823 std::array<T, 3> S_out_n; // Container for Poynting-normal ext products
824 std::array<T, 3> point; // Point on target
825 std::array<T, 3> norms; // Normal vector at point
826 std::array<T, 3> e_out_h_r; // Real part of E-field - H-field ext product
827
828 // Arrays of complex Ts
829 std::array<std::complex<T>, 3> e_r; // Reflected E-field
830 std::array<std::complex<T>, 3> h_r; // Reflected H-field
831 std::array<std::complex<T>, 3> n_out_e_i_r; // Electric current
832 std::array<std::complex<T>, 3> temp1; // Temporary container 1 for intermediate irrelevant values
833 std::array<std::complex<T>, 3> temp2; // Temporary container 2
834
835 // Return containers
836 std::array<std::array<std::complex<T>, 3>, 2> beam_e_h; // Container for storing fieldAtPoint return
837
838 int jc = 0; // Counter
839
840 for(int i=start; i<stop; i++)
841 {
842
843 point[0] = ct->x[i];
844 point[1] = ct->y[i];
845 point[2] = ct->z[i];
846
847 norms[0] = ct->nx[i];
848 norms[1] = ct->ny[i];
849 norms[2] = ct->nz[i];
850
851 // Calculate total incoming E and H field at point on target
852 beam_e_h = fieldAtPoint(cs, currents, gmode, ncx, ncy,
853 point);
854
855 // Calculate normalised incoming poynting vector.
856 ut.conj(beam_e_h[1], temp1); // h_conj
857 ut.ext(beam_e_h[0], temp1, temp2); // e_out_h
858
859 for (int n=0; n<3; n++)
860 {
861 e_out_h_r[n] = temp2[n].real(); // e_out_h_r
862 }
863
864 //std::cout << this->Et_container.size() << std::endl;
865
866 ut.normalize(e_out_h_r, S_i_norm); // S_i_norm
867
868 // Calculate incoming polarization vectors
869 ut.ext(S_i_norm, norms, S_out_n); // S_i_out_n
870 ut.normalize(S_out_n, p_i_perp); // p_i_perp
871 ut.ext(p_i_perp, S_i_norm, p_i_parr); // p_i_parr
872
873 // Now calculate reflected poynting vector.
874 ut.snell(S_i_norm, norms, S_r_norm); // S_r_norm
875
876 // Calculate normalised reflected polarization vectors
877 ut.ext(S_r_norm, norms, S_out_n); // S_r_out_n
878 ut.normalize(S_out_n, p_r_perp); // p_r_perp
879 ut.ext(S_r_norm, p_r_perp, p_r_parr); // p_r_parr
880
881 // Now, calculate reflected field from target
882 ut.dot(beam_e_h[0], p_r_perp, e_dot_p_r_perp); // e_dot_p_r_perp
883 ut.dot(beam_e_h[0], p_r_parr, e_dot_p_r_parr); // e_dot_p_r_parr
884
885 // Calculate reflected field from reflection matrix
886 for(int n=0; n<3; n++)
887 {
888 e_r[n] = -e_dot_p_r_perp * p_i_perp[n] - e_dot_p_r_parr * p_i_parr[n];
889 }
890
891 ut.ext(S_r_norm, e_r, temp1); // h_r_temp
892 ut.s_mult(temp1, ZETA_INV, h_r); // h_r
893
894 res->r1x[i] = e_r[0].real();
895 res->r1y[i] = e_r[1].real();
896 res->r1z[i] = e_r[2].real();
897
898 res->i1x[i] = e_r[0].imag();
899 res->i1y[i] = e_r[1].imag();
900 res->i1z[i] = e_r[2].imag();
901
902 res->r2x[i] = h_r[0].real();
903 res->r2y[i] = h_r[1].real();
904 res->r2z[i] = h_r[2].real();
905
906 res->i2x[i] = h_r[0].imag();
907 res->i2y[i] = h_r[1].imag();
908 res->i2z[i] = h_r[2].imag();
909
910 res->r3x[i] = S_r_norm[0];
911 res->r3y[i] = S_r_norm[1];
912 res->r3z[i] = S_r_norm[2];
913 }
914}
915
916/**
917 * Calculate scalar field on target.
918 *
919 * Calculate the scalar fields on a target surface.
920 *
921 * @param start Index of first loop iteration in parallel block.
922 * @param stop Index of last loop iteration in parallel block.
923 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
924 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
925 * @param field Pointer to arrC1 or arrC1f object containing field on source.
926 * @param res Pointer to arrC1 or arrC1f object, to be filled with calculation results.
927 *
928 * @see reflcontainer
929 * @see reflcontainerf
930 * @see c2Bundle
931 * @see c2Bundlef
932 */
933template <class T, class U, class V, class W>
935 V *cs, V *ct,
936 W *field,
937 int gmode, int ncx, int ncy,
938 U *res)
939{
940 std::array<T, 3> point_target;
941 std::complex<T> ets;
942
943 for(int i=start; i<stop; i++)
944 {
945 point_target[0] = ct->x[i];
946 point_target[1] = ct->y[i];
947 point_target[2] = ct->z[i];
948
949 ets = fieldScalarAtPoint(cs, field,
950 gmode, ncx, ncy,
951 point_target);
952
953 res->x[i] = ets.real();
954 res->y[i] = ets.imag();
955 }
956}
957
958/**
959 * Calculate field on target.
960 *
961 * Calculate integrated E and H fields on a target point.
962 *
963 * We use the GRASP formulae for the E and H fields in sqrt{Watts}, calculated
964 * from electric and magnetic currents in sqrt{Watts}.
965 *
966 * The GRASP manual cites Collin "Antenna Theory" (1969) for the derivation.
967 *
968 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
969 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
970 * @param point_target Array of 3 double/float containing target point co-ordinate.
971 *
972 * @see reflcontainer
973 * @see reflcontainerf
974 * @see c2Bundle
975 * @see c2Bundlef
976 */
977template <class T, class U, class V, class W>
978std::array<std::array<std::complex<T>, 3>, 2> Propagation<T, U, V, W>::fieldAtPoint(V *cs,
979 W *currents,
980 int gmode, int ncx, int ncy,
981 const std::array<T, 3> &point_target)
982{
983 int i;
984 // Scalars (T & complex T)
985 T R; // Distance between source and target points
986 T R_inv; // 1 / R
987 T kR; // The product of the wavevector and the the distance
988 T kR_inv; // The inverse of the product of the wavevector and the the distance
989 T norm_dot_R_hat; // Source normal dotted with wavevector direction
990 T half = 0.5;
991
992 std::complex<T> Green; // Container for Green's function
993 std::complex<T> js_dot_R; // Magnitude of electric currents on to R_hat
994 std::complex<T> ms_dot_R; // Magnitude of magnetic currents on to R_hat
995 std::complex<T> kR_inv_sum1; // Container for the first complex sum of 1/kR powers
996 std::complex<T> kR_inv_sum2; // Container for the second complex sum of 1/kR powers
997 std::complex<T> kR_inv_sum3; // Container for the third complex sum of 1/kR powers
998
999
1000 // Arrays of Ts
1001 std::array<T, 3> source_point; // Container for xyz co-ordinates
1002 std::array<T, 3> source_norm; // Container for xyz normals.
1003 std::array<T, 3> R_vec; // Distance vector between source and target points
1004 std::array<T, 3> R_hat; // Unit vector between source and target points
1005 std::array<T, 3> k_arr; // Wavevector
1006
1007 // Arrays of complex Ts
1008 std::array<std::complex<T>, 3> e_field; // Electric field surface integral at point
1009 std::array<std::complex<T>, 3> h_field; // Magnetic field surface integral at point
1010 std::array<std::complex<T>, 3> ye_field; // Electric field surface integral at point
1011 std::array<std::complex<T>, 3> yh_field; // Magnetic field surface integral at point
1012 std::array<std::complex<T>, 3> js; // Electric current at source point
1013 std::array<std::complex<T>, 3> ms; // Magnetic current at source point
1014 std::array<std::complex<T>, 3> k_out_ms; // Outer product between k and ms
1015 std::array<std::complex<T>, 3> k_out_js; // Outer product between k and js
1016 std::array<std::complex<T>, 3> js_dot_R_R; // Electric currents projected on to R_hat
1017 std::array<std::complex<T>, 3> ms_cross_R; // Cross product of magnetic currents and R_hat
1018 std::array<std::complex<T>, 3> ms_dot_R_R; // Magnetic currents projected on to R_hat
1019 std::array<std::complex<T>, 3> js_cross_R; // Cross product of electric currents and R_hat
1020
1021
1022 // Return container
1023 std::array<std::array<std::complex<T>, 3>, 2> e_h_field; // Return container containing e and h-fields
1024
1025 e_field.fill(z0);
1026 h_field.fill(z0);
1027
1028 for(int xu=0; xu<ncx; xu++)
1029 {
1030 for (int n=0; n<3; n++)
1031 {
1032 ye_field[n] = z0; // Intermediate electric field due to integral over y/v
1033 yh_field[n] = z0; // Intermediate magnetic field due to integral over y/v
1034 }
1035
1036 for(int yv=0; yv<ncy; yv++)
1037 {
1038 i = xu*ncy + yv;
1039
1040 source_point[0] = cs->x[i];
1041 source_point[1] = cs->y[i];
1042 source_point[2] = cs->z[i];
1043
1044 source_norm[0] = cs->nx[i];
1045 source_norm[1] = cs->ny[i];
1046 source_norm[2] = cs->nz[i];
1047
1048 js[0] = {currents->r1x[i], currents->i1x[i]};
1049 js[1] = {currents->r1y[i], currents->i1y[i]};
1050 js[2] = {currents->r1z[i], currents->i1z[i]};
1051
1052 ms[0] = {currents->r2x[i], currents->i2x[i]};
1053 ms[1] = {currents->r2y[i], currents->i2y[i]};
1054 ms[2] = {currents->r2z[i], currents->i2z[i]};
1055
1056 ut.diff(point_target, source_point, R_vec);
1057 ut.abs(R_vec, R);
1058
1059 //printf("R %.16g\n", R); // %s is format specifier
1060
1061 R_inv = 1 / R;
1062
1063 //printf("1/R %.16g\n", R_inv); // %s is format specifier
1064
1065 kR = k*R;
1066
1067 //printf("kR %.16g\n", kR); // %s is format specifier
1068
1069 kR_inv = 1/kR;
1070
1071 //printf("1/kR %.16g\n", kR_inv); // %s is format specifier
1072
1073 ut.s_mult(R_vec, R_inv, R_hat);
1074
1075 //printf("R_hat: (%.16g, %.16g, %.16g)\n", R_hat[0], R_hat[1], R_hat[2]); // %s is format specifier
1076
1077 // Check if source point illuminates target point or not.
1078 ut.dot(source_norm, R_hat, norm_dot_R_hat);
1079 //printf("source_norm: (%.16g, %.16g, %.16g)\n", source_norm[0], source_norm[1], source_norm[2]); // %s is format specifier
1080 //printf("n . R_hat: %.16g\n", norm_dot_R_hat); // %s is format specifier
1081 if (norm_dot_R_hat < 0) {continue;}
1082
1083 // Calculate the complex sums that appear in the integral
1084 kR_inv_sum1 = kR_inv * (-j + t_direction*kR_inv + j*kR_inv*kR_inv);
1085 //printf("kR_inv_sum1: %.16g+%16gi\n", kR_inv_sum1.real(), kR_inv_sum1.imag()); // %s is format specifier
1086
1087 kR_inv_sum2 = kR_inv * (j - t_direction*Three*kR_inv - Three*j * kR_inv*kR_inv);
1088 //printf("kR_inv_sum2: %.16g+%16gi\n", kR_inv_sum2.real(), kR_inv_sum2.imag()); // %s is format specifier
1089
1090 kR_inv_sum3 = t_direction * (j*kR_inv - t_direction*kR_inv*kR_inv);
1091 //printf("kR_inv_sum3: %.16g+%16gi\n", kR_inv_sum3.real(), kR_inv_sum3.imag()); // %s is format specifier
1092
1093
1094 // e-field
1095 ut.dot(js, R_hat, js_dot_R);
1096 ut.s_mult(R_hat, js_dot_R, js_dot_R_R);
1097 ut.ext(ms, R_hat, ms_cross_R);
1098
1099 // h-field
1100 ut.dot(ms, R_hat, ms_dot_R);
1101 ut.s_mult(R_hat, ms_dot_R, ms_dot_R_R);
1102 ut.ext(js, R_hat, js_cross_R);
1103
1104 Green = prefactor * exp(t_direction * j * k * R) * cs->area[i];
1105 //printf("%.16g, %.16g\n", Green.real(), Green.imag()); // %s is format specifier
1106
1107 for( int n=0; n<3; n++)
1108 {
1109 if ((gmode != 1) && ((yv==0) || (yv==ncy-1)))
1110 {
1111 ye_field[n] += half*(js[n] * kR_inv_sum1 + js_dot_R_R[n] * kR_inv_sum2 + ms_cross_R[n] * kR_inv_sum3) * Green;
1112 yh_field[n] += half*(ms[n] * kR_inv_sum1 + ms_dot_R_R[n] * kR_inv_sum2 - js_cross_R[n] * kR_inv_sum3) * Green;
1113 }
1114 else
1115 {
1116 ye_field[n] += (js[n] * kR_inv_sum1 + js_dot_R_R[n] * kR_inv_sum2 + ms_cross_R[n] * kR_inv_sum3) * Green;
1117 yh_field[n] += (ms[n] * kR_inv_sum1 + ms_dot_R_R[n] * kR_inv_sum2 - js_cross_R[n] * kR_inv_sum3) * Green;
1118 }
1119 }
1120 } // End of yv loop
1121 for (int n=0; n<3; n++)
1122 {
1123 if ((xu==0) || (xu==ncx-1)) // Only add half the point value
1124 {
1125 e_field[n] += half*ye_field[n];
1126 h_field[n] += half*yh_field[n];
1127 }
1128 else
1129 {
1130 e_field[n] += ye_field[n];
1131 h_field[n] += yh_field[n];
1132 }
1133 }
1134
1135 } // End of xu loop
1136
1137 // Pack e and h together in single container
1138 e_h_field[0] = e_field;
1139 e_h_field[1] = h_field;
1140
1141 //std::cout << ut.abs(e_field) << std::endl;
1142
1143 return e_h_field;
1144}
1145
1146
1147/**
1148 * Calculate field on target.
1149 *
1150 * Calculate integrated E and H fields on a target point.
1151 *
1152 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1153 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
1154 * @param point_target Array of 3 double/float containing target point co-ordinate.
1155 *
1156 * @see reflcontainer
1157 * @see reflcontainerf
1158 * @see c2Bundle
1159 * @see c2Bundlef
1160 */
1161template <class T, class U, class V, class W>
1162std::array<std::array<std::complex<T>, 3>, 2> Propagation<T, U, V, W>::fieldAtPoint_Old(V *cs,
1163 W *currents, const std::array<T, 3> &point_target)
1164{
1165 // Scalars (T & complex T)
1166 T r; // Distance between source and target points
1167 T r_inv; // 1 / r
1168 T omega; // Angular frequency of field
1169 T norm_dot_k_hat; // Source normal dotted with wavevector direction
1170 std::complex<T> Green; // Container for Green's function
1171 std::complex<T> r_in_s; // Container for inner products between wavevctor and currents
1172
1173 // Arrays of Ts
1174 std::array<T, 3> source_point; // Container for xyz co-ordinates
1175 std::array<T, 3> source_norm; // Container for xyz normals.
1176 std::array<T, 3> r_vec; // Distance vector between source and target points
1177 std::array<T, 3> k_hat; // Unit wavevctor
1178 std::array<T, 3> k_arr; // Wavevector
1179
1180 // Arrays of complex Ts
1181 std::array<std::complex<T>, 3> e_field; // Electric field on target
1182 std::array<std::complex<T>, 3> h_field; // Magnetic field on target
1183 std::array<std::complex<T>, 3> js; // Electric current at source point
1184 std::array<std::complex<T>, 3> ms; // Magnetic current at source point
1185 std::array<std::complex<T>, 3> e_vec_thing; // Electric current contribution to e-field
1186 std::array<std::complex<T>, 3> h_vec_thing; // Magnetic current contribution to h-field
1187 std::array<std::complex<T>, 3> k_out_ms; // Outer product between k and ms
1188 std::array<std::complex<T>, 3> k_out_js; // Outer product between k and js
1189 std::array<std::complex<T>, 3> temp; // Temporary container for intermediate values
1190
1191 // Return container
1192 std::array<std::array<std::complex<T>, 3>, 2> e_h_field; // Return container containing e and h-fields
1193
1194 e_field.fill(z0);
1195 h_field.fill(z0);
1196
1197 omega = C_L * k;
1198
1199 for(int i=0; i<gs; i++)
1200 {
1201 source_point[0] = cs->x[i];
1202 source_point[1] = cs->y[i];
1203 source_point[2] = cs->z[i];
1204
1205 source_norm[0] = cs->nx[i];
1206 source_norm[1] = cs->ny[i];
1207 source_norm[2] = cs->nz[i];
1208
1209 js[0] = {currents->r1x[i], currents->i1x[i]};
1210 js[1] = {currents->r1y[i], currents->i1y[i]};
1211 js[2] = {currents->r1z[i], currents->i1z[i]};
1212
1213 ms[0] = {currents->r2x[i], currents->i2x[i]};
1214 ms[1] = {currents->r2y[i], currents->i2y[i]};
1215 ms[2] = {currents->r2z[i], currents->i2z[i]};
1216
1217 ut.diff(point_target, source_point, r_vec);
1218 ut.abs(r_vec, r);
1219
1220 r_inv = 1 / r;
1221
1222 ut.s_mult(r_vec, r_inv, k_hat);
1223
1224 // Check if source point illuminates target point or not.
1225 ut.dot(source_norm, k_hat, norm_dot_k_hat);
1226 if (norm_dot_k_hat < 0) {continue;}
1227
1228 ut.s_mult(k_hat, k, k_arr);
1229
1230 // e-field
1231 ut.dot(k_hat, js, r_in_s);
1232 ut.s_mult(k_hat, r_in_s, temp);
1233 ut.diff(js, temp, e_vec_thing);
1234
1235 ut.ext(k_arr, ms, k_out_ms);
1236
1237 // h-field
1238 ut.dot(k_hat, ms, r_in_s);
1239 ut.s_mult(k_hat, r_in_s, temp);
1240 ut.diff(ms, temp, h_vec_thing);
1241
1242 ut.ext(k_arr, js, k_out_js);
1243
1244 //printf("%.16g\n", r);
1245
1246 Green = exp(this->t_direction * j * k * r) / (4 * PIf * r) * cs->area[i] * j;
1247
1248 for( int n=0; n<3; n++)
1249 {
1250 e_field[n] += (-omega * MU_0 * e_vec_thing[n] + k_out_ms[n]) * Green;
1251 h_field[n] += (-omega * EPS * h_vec_thing[n] - k_out_js[n]) * Green;
1252 }
1253 //printf("%.16g, %.16g\n", Green.real(), Green.imag()); // %s is format specifier
1254 }
1255
1256 // Pack e and h together in single container
1257 e_h_field[0] = e_field;
1258 e_h_field[1] = h_field;
1259
1260 //std::cout << ut.abs(e_field) << std::endl;
1261
1262 return e_h_field;
1263}
1264
1265/**
1266 * Calculate scalar field on target.
1267 *
1268 * Calculate integrated scalar field on a target point.
1269 *
1270 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1271 * @param field Pointer to arrC1 or arrC1f object containing currents on source.
1272 * @param point_target Array of 3 double/float containing target point co-ordinate.
1273 *
1274 * @see reflcontainer
1275 * @see reflcontainerf
1276 * @see arrC1
1277 * @see arrC1f
1278 */
1279template <class T, class U, class V, class W>
1281 W *field,
1282 int gmode, int ncx, int ncy,
1283 const std::array<T, 3> &point_target)
1284{
1285 int i;
1286 std::complex<T> out(0., 0.);
1287 std::complex<T> j(0., 1.);
1288 std::complex<T> _field;
1289 std::complex<T> _yfield;
1290 T half = 0.5;
1291
1292 T r;
1293 std::array<T, 3> r_vec;
1294 std::array<T, 3> source_point;
1295
1296 for(int xu=0; xu<ncx; xu++)
1297 {
1298 _yfield = z0; // Intermediate electric field due to integral over y/v
1299
1300 for(int yv=0; yv<ncy; yv++)
1301 {
1302 i = xu*ncy + yv;
1303 source_point[0] = cs->x[i];
1304 source_point[1] = cs->y[i];
1305 source_point[2] = cs->z[i];
1306
1307 _field = {field->x[i], field->y[i]};
1308
1309 ut.diff(point_target, source_point, r_vec);
1310 ut.abs(r_vec, r);
1311
1312 if ((gmode != 1) && ((yv==0) || (yv==ncy-1)))
1313 {
1314 _yfield += - half * k * k * _field * exp(this->t_direction * -j * k * r) / (4 * PIf * r) * cs->area[i];
1315 }
1316 else
1317 {
1318 _yfield += - k * k * _field * exp(this->t_direction * -j * k * r) / (4 * PIf * r) * cs->area[i];
1319 }
1320 } // End of yv loop
1321 if ((xu==0) || (xu==ncx-1)) // Only add half the point value
1322 {
1323 out += half*_yfield;
1324 }
1325 else
1326 {
1327 out += _yfield;
1328 }
1329 }
1330 return out;
1331}
1332
1333/**
1334 * Calculate JM parallel.
1335 *
1336 * Run the propagateBeam_JM function in parallel blocks.
1337 *
1338 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1339 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
1340 * @param currents Pointer to c2Bundle or c2Bundlef object containing source currents.
1341 * @param res Pointer to c2Bundle or c2Bundlef object to be filled with calculation results.
1342 *
1343 * @see reflcontainer
1344 * @see reflcontainerf
1345 * @see c2Bundle
1346 * @see c2Bundlef
1347 */
1348template <class T, class U, class V, class W>
1350 W *currents,
1351 int gmode, int ncx, int ncy,
1352 U *res)
1353{
1354 int final_step;
1355
1356 for(int n=0; n<numThreads; n++)
1357 {
1358 //std::cout << n << std::endl;
1359 if(n == (numThreads-1))
1360 {
1361 final_step = gt;
1362 }
1363
1364 else
1365 {
1366 final_step = (n+1) * step;
1367 }
1368
1369 //std::cout << final_step << std::endl;
1370
1371 threadPool[n] = std::thread(&Propagation::propagateBeam_JM_PEC,
1372 this, n * step, final_step,
1373 cs, ct, currents,
1374 gmode, ncx, ncy,
1375 res);
1376 }
1377 joinThreads();
1378}
1379
1380/**
1381 * Calculate EH parallel.
1382 *
1383 * Run the propagateBeam_EH function in parallel blocks.
1384 *
1385 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1386 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
1387 * @param currents Pointer to c2Bundle or c2Bundlef object containing source currents.
1388 * @param res Pointer to c2Bundle or c2Bundlef object to be filled with calculation results.
1389 *
1390 * @see reflcontainer
1391 * @see reflcontainerf
1392 * @see c2Bundle
1393 * @see c2Bundlef
1394 */
1395template <class T, class U, class V, class W>
1397 W *currents,
1398 int gmode, int ncx, int ncy,
1399 U *res)
1400{
1401 int final_step;
1402
1403 for(int n=0; n<numThreads; n++)
1404 {
1405 //std::cout << n << std::endl;
1406 if(n == (numThreads-1))
1407 {
1408 final_step = gt;
1409 }
1410
1411 else
1412 {
1413 final_step = (n+1) * step;
1414 }
1415
1416 //std::cout << final_step << std::endl;
1417
1418 threadPool[n] = std::thread(&Propagation::propagateBeam_EH,
1419 this, n * step, final_step,
1420 cs, ct, currents,
1421 gmode, ncx, ncy,
1422 res);
1423 }
1424 joinThreads();
1425}
1426
1427/**
1428 * Calculate JM and EH parallel.
1429 *
1430 * Run the propagateBeam_JMEH function in parallel blocks.
1431 *
1432 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1433 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
1434 * @param currents Pointer to c2Bundle or c2Bundlef object containing source currents.
1435 * @param res Pointer to c4Bundle or c4Bundlef object to be filled with calculation results.
1436 *
1437 * @see reflcontainer
1438 * @see reflcontainerf
1439 * @see c2Bundle
1440 * @see c2Bundlef
1441 * @see c4Bundle
1442 * @see c4Bundlef
1443 */
1444template <class T, class U, class V, class W>
1446 W *currents,
1447 int gmode, int ncx, int ncy,
1448 U *res)
1449{
1450 int final_step;
1451
1452 for(int n=0; n<numThreads; n++)
1453 {
1454 if(n == (numThreads-1))
1455 {
1456 final_step = gt;
1457 }
1458
1459 else
1460 {
1461 final_step = (n+1) * step;
1462 }
1463
1464 threadPool[n] = std::thread(&Propagation::propagateBeam_JMEH_PEC,
1465 this, n * step, final_step,
1466 cs, ct, currents,
1467 gmode, ncx, ncy,
1468 res);
1469 }
1470 joinThreads();
1471}
1472
1473/**
1474 * Calculate reflected EH and P parallel.
1475 *
1476 * Run the propagateBeam_EHP function in parallel blocks.
1477 *
1478 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1479 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
1480 * @param currents Pointer to c2Bundle or c2Bundlef object containing source currents.
1481 * @param res Pointer to c2rBundle or c2rBundlef object to be filled with calculation results.
1482 *
1483 * @see reflcontainer
1484 * @see reflcontainerf
1485 * @see c2Bundle
1486 * @see c2Bundlef
1487 * @see c2rBundle
1488 * @see c2rBundlef
1489 */
1490template <class T, class U, class V, class W>
1492 W *currents,
1493 int gmode, int ncx, int ncy,
1494 U *res)
1495{
1496 int final_step;
1497
1498 for(int n=0; n<numThreads; n++)
1499 {
1500 //std::cout << n << std::endl;
1501 if(n == (numThreads-1))
1502 {
1503 final_step = gt;
1504 }
1505
1506 else
1507 {
1508 final_step = (n+1) * step;
1509 }
1510
1511 threadPool[n] = std::thread(&Propagation::propagateBeam_EHP,
1512 this, n * step, final_step,
1513 cs, ct, currents,
1514 gmode, ncx, ncy,
1515 res);
1516 }
1517 joinThreads();
1518}
1519
1520/**
1521 * Calculate scalar field parallel.
1522 *
1523 * Run the propagateScalarBeam function in parallel blocks.
1524 *
1525 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1526 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
1527 * @param field Pointer to arrC1 or arrC1f object containing source currents.
1528 * @param res Pointer to arrC1 or arrC1f object to be filled with calculation results.
1529 *
1530 * @see reflcontainer
1531 * @see reflcontainerf
1532 * @see arrC1
1533 * @see arrC1f
1534 */
1535template <class T, class U, class V, class W>
1537 W *field,
1538 int gmode, int ncx, int ncy,
1539 U *res)
1540{
1541 int final_step;
1542
1543 for(int n=0; n<numThreads; n++)
1544 {
1545 if(n == (numThreads-1))
1546 {
1547 final_step = gt;
1548 }
1549
1550 else
1551 {
1552 final_step = (n+1) * step;
1553 }
1554
1555 threadPool[n] = std::thread(&Propagation::propagateScalarBeam,
1556 this, n * step, final_step,
1557 cs, ct, field,
1558 gmode, ncx, ncy,
1559 res);
1560 }
1561 joinThreads();
1562}
1563
1564/**
1565 * Calculate far-field on target.
1566 *
1567 * Calculate integrated E and H fields on a far-field target point.
1568 *
1569 * @param start Index of first loop iteration in parallel block.
1570 * @param stop Index of last loop iteration in parallel block.
1571 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1572 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
1573 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
1574 * @param res Pointer to c2Bundle or c2Bundlef object, to be filled with calculation results.
1575 *
1576 * @see reflcontainer
1577 * @see reflcontainerf
1578 * @see c2Bundle
1579 * @see c2Bundlef
1580 */
1581template <class T, class U, class V, class W>
1583 V *cs, V *ct,
1584 W *currents,
1585 int gmode, int ncx, int ncy,
1586 U *res)
1587{
1588 // Scalars (T & complex T)
1589 T theta;
1590 T phi;
1591 T cosEl;
1592
1593 std::complex<T> e_th;
1594 std::complex<T> e_ph;
1595
1596 std::complex<T> e_Az;
1597 std::complex<T> e_El;
1598
1599 // Arrays of Ts
1600 std::array<T, 2> point_ff; // Angular point on far-field
1601 std::array<T, 3> r_hat; // Unit vector in far-field point direction
1602
1603 // Arrays of complex Ts
1604 std::array<std::array<std::complex<T>, 3>, 2> eh; // far-field EH-field
1605
1606 int jc = 0;
1607 for(int i=start; i<stop; i++)
1608 {
1609 phi = ct->x[i];
1610 theta = ct->y[i];
1611 cosEl = std::sqrt(1 - sin(theta) * sin(phi) * sin(theta) * sin(phi));
1612
1613 r_hat[0] = cos(theta) * sin(phi);
1614 r_hat[1] = sin(theta) * sin(phi);
1615 r_hat[2] = cos(phi);
1616
1617 // Calculate total incoming E and H field at point on target
1618 eh = farfieldAtPoint(cs, currents,
1619 gmode, ncx, ncy,
1620 r_hat);
1621
1622 res->r1x[i] = eh[0][0].real();
1623 res->r1y[i] = eh[0][1].real();
1624 res->r1z[i] = eh[0][2].real();
1625
1626 res->i1x[i] = eh[0][0].imag();
1627 res->i1y[i] = eh[0][1].imag();
1628 res->i1z[i] = eh[0][2].imag();
1629
1630 // TODO: Calculate H far fields
1631 res->r2x[i] = eh[1][0].real();
1632 res->r2y[i] = eh[1][1].real();
1633 res->r2z[i] = eh[1][2].real();
1634
1635 res->i2x[i] = eh[1][0].imag();
1636 res->i2y[i] = eh[1][1].imag();
1637 res->i2z[i] = eh[1][2].imag();
1638 }
1639}
1640
1641
1642/**
1643 * Calculate far-field on target.
1644 *
1645 * Calculate integrated E and H fields on a far-field target point.
1646 *
1647 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1648 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
1649 * @param r_hat Array of 3 double/float containing target direction angles.
1650 *
1651 * @see reflcontainer
1652 * @see reflcontainerf
1653 * @see c2Bundle
1654 * @see c2Bundlef
1655 */
1656template <class T, class U, class V, class W>
1657std::array<std::array<std::complex<T>, 3>, 2> Propagation<T, U, V, W>::farfieldAtPoint(V *cs,
1658 W *currents,
1659 int gmode, int ncx, int ncy,
1660 const std::array<T, 3> &r_hat)
1661{
1662 int i;
1663 // Scalars (T & complex T)
1664 T norm_dot_R_hat; // Source normal dotted with wavevector direction
1665 T half = 0.5;
1666
1667 std::complex<T> Green; // Container for Green's function
1668 std::complex<T> js_dot_R; // Magnitude of electric currents on to R_hat
1669 std::complex<T> ms_dot_R; // Magnitude of magnetic currents on to R_hat
1670 T Rprime_dot_R_hat; // Magnitude of source point projected onto R_hat
1671
1672 // Arrays of Ts
1673 std::array<T, 3> source_point; // Container for xyz co-ordinates
1674 std::array<T, 3> source_norm; // Container for xyz normals.
1675
1676 // Arrays of complex Ts
1677 std::array<std::complex<T>, 3> e_field; // Electric field surface integral at point
1678 std::array<std::complex<T>, 3> h_field; // Magnetic field surface integral at point
1679 std::array<std::complex<T>, 3> ye_field; // Electric field surface integral at point
1680 std::array<std::complex<T>, 3> yh_field; // Magnetic field surface integral at point
1681 std::array<std::complex<T>, 3> js; // Electric current at source point
1682 std::array<std::complex<T>, 3> ms; // Magnetic current at source point
1683 std::array<std::complex<T>, 3> js_dot_R_R; // Electric currents projected on to R_hat
1684 std::array<std::complex<T>, 3> R_cross_ms; // Cross product of magnetic currents and R_hat
1685 std::array<std::complex<T>, 3> ms_dot_R_R; // Magnetic currents projected on to R_hat
1686 std::array<std::complex<T>, 3> R_cross_js; // Cross product of electric currents and R_hat
1687
1688
1689 // Return container
1690 std::array<std::array<std::complex<T>, 3>, 2> e_h_field; // Return container containing e and h-fields
1691
1692 e_field.fill(z0);
1693 h_field.fill(z0);
1694
1695 for(int xu=0; xu<ncx; xu++)
1696 {
1697 for (int n=0; n<3; n++)
1698 {
1699 ye_field[n] = z0; // Intermediate electric field due to integral over y/v
1700 yh_field[n] = z0; // Intermediate magnetic field due to integral over y/v
1701 }
1702
1703 for(int yv=0; yv<ncy; yv++)
1704 {
1705 i = xu*ncy + yv;
1706 source_point[0] = cs->x[i];
1707 source_point[1] = cs->y[i];
1708 source_point[2] = cs->z[i];
1709
1710 source_norm[0] = cs->nx[i];
1711 source_norm[1] = cs->ny[i];
1712 source_norm[2] = cs->nz[i];
1713
1714 js[0] = {currents->r1x[i], currents->i1x[i]};
1715 js[1] = {currents->r1y[i], currents->i1y[i]};
1716 js[2] = {currents->r1z[i], currents->i1z[i]};
1717
1718 ms[0] = {currents->r2x[i], currents->i2x[i]};
1719 ms[1] = {currents->r2y[i], currents->i2y[i]};
1720 ms[2] = {currents->r2z[i], currents->i2z[i]};
1721
1722 // Check if source point illuminates target point or not.
1723 ut.dot(source_norm, r_hat, norm_dot_R_hat);
1724 //printf("norm_dot_R_hat: %.16g\n", norm_dot_R_hat); // %s is format specifier
1725 if ((norm_dot_R_hat < 0)) {continue;}
1726
1727 // e-field
1728 ut.dot(js, r_hat, js_dot_R);
1729 ut.s_mult(r_hat, js_dot_R, js_dot_R_R);
1730 ut.ext(r_hat, ms, R_cross_ms);
1731
1732 // h-field
1733 ut.dot(ms, r_hat, ms_dot_R);
1734 ut.s_mult(r_hat, ms_dot_R, ms_dot_R_R);
1735 ut.ext(r_hat, js, R_cross_js);
1736
1737 ut.dot(source_point, r_hat, Rprime_dot_R_hat);
1738
1739 Green = -prefactor * j * exp(-t_direction * j * k * Rprime_dot_R_hat) * cs->area[i];
1740 //printf("%.16g, %.16g\n", Green.real(), Green.imag()); // %s is format specifier
1741
1742 for( int n=0; n<3; n++)
1743 {
1744 if ((gmode != 1) && ((yv==0) || (yv==ncy-1)))
1745 {
1746 ye_field[n] += half*(js[n] - js_dot_R_R[n] + t_direction * R_cross_ms[n]) * Green;
1747 yh_field[n] += half*(ms[n] - ms_dot_R_R[n] - t_direction * R_cross_js[n]) * Green;
1748 }
1749 else
1750 {
1751 ye_field[n] += (js[n] - js_dot_R_R[n] + t_direction * R_cross_ms[n]) * Green;
1752 yh_field[n] += (ms[n] - ms_dot_R_R[n] - t_direction * R_cross_js[n]) * Green;
1753 }
1754 }
1755
1756 } // End of yv loop
1757 for (int n=0; n<3; n++)
1758 {
1759 if ((xu==0) || (xu==ncx-1)) // Only add half the point value
1760 {
1761 e_field[n] += half*ye_field[n];
1762 h_field[n] += half*yh_field[n];
1763 }
1764 else
1765 {
1766 e_field[n] += ye_field[n];
1767 h_field[n] += yh_field[n];
1768 }
1769 }
1770
1771 } // End of xu loop
1772
1773
1774 // Pack e and h together in single container
1775 e_h_field[0] = e_field;
1776 e_h_field[1] = h_field;
1777
1778 //std::cout << ut.abs(e_field) << std::endl;
1779
1780 return e_h_field;
1781}
1782
1783/**
1784 * Calculate far-field on target.
1785 *
1786 * Calculate integrated E and H fields on a far-field target point.
1787 *
1788 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1789 * @param currents Pointer to c2Bundle or c2Bundlef object containing currents on source.
1790 * @param r_hat Array of 3 double/float containing target direction angles.
1791 *
1792 * @see reflcontainer
1793 * @see reflcontainerf
1794 * @see c2Bundle
1795 * @see c2Bundlef
1796 */
1797template <class T, class U, class V, class W>
1798std::array<std::array<std::complex<T>, 3>, 2> Propagation<T, U, V, W>::farfieldAtPoint_Old(V *cs,
1799 W *currents,
1800 const std::array<T, 3> &r_hat)
1801{
1802 // Scalars (T & complex T)
1803 T omega_mu; // Angular frequency of field times mu
1804 T omega_eps; // Angular frequency of field times eps
1805 T r_hat_in_rp; // r_hat dot product r_prime
1806 std::complex<T> r_in_s; // Container for inner products between wavevctor and currents
1807 std::complex<T> expo;
1808 T area;
1809
1810 // Arrays of Ts
1811 std::array<T, 3> source_point; // Container for xyz co-ordinates
1812
1813 // Arrays of complex Ts
1814 std::array<std::complex<T>, 3> e; // Electric field on far-field point
1815 std::array<std::complex<T>, 3> h; // Magnetic field on far-field point
1816 std::array<std::complex<T>, 3> _js; // Temporary Electric current at source point
1817 std::array<std::complex<T>, 3> _ms; // Temporary Magnetic current at source point
1818
1819 std::array<std::complex<T>, 3> js; // Build radiation integral
1820 std::array<std::complex<T>, 3> ms; // Build radiation integral
1821
1822 std::array<std::complex<T>, 3> _ctemp;
1823 std::array<std::complex<T>, 3> js_tot_factor;
1824 std::array<std::complex<T>, 3> ms_tot_factor;
1825 std::array<std::complex<T>, 3> js_tot_factor_h;
1826 std::array<std::complex<T>, 3> ms_tot_factor_h;
1827
1828 // Output array
1829 std::array<std::array<std::complex<T>, 3>, 2> out;
1830
1831 // Matrices
1832 std::array<std::array<T, 3>, 3> rr_dyad; // Dyadic product between r_hat - r_hat
1833 std::array<std::array<T, 3>, 3> eye_min_rr; // I - rr
1834
1835 e.fill(z0);
1836 h.fill(z0);
1837 js.fill(z0);
1838 ms.fill(z0);
1839
1840 omega_mu = C_L * k * MU_0;
1841
1842 ut.dyad(r_hat, r_hat, rr_dyad);
1843 ut.matDiff(this->eye, rr_dyad, eye_min_rr);
1844
1845 for(int i=0; i<gs; i++)
1846 {
1847 source_point[0] = cs->x[i];
1848 source_point[1] = cs->y[i];
1849 source_point[2] = cs->z[i];
1850
1851 ut.dot(r_hat, source_point, r_hat_in_rp);
1852
1853 expo = exp(j * k * r_hat_in_rp);
1854 area = cs->area[i];
1855
1856 _js[0] = {currents->r1x[i], currents->i1x[i]};
1857 _js[1] = {currents->r1y[i], currents->i1y[i]};
1858 _js[2] = {currents->r1z[i], currents->i1z[i]};
1859
1860 _ms[0] = {currents->r2x[i], currents->i2x[i]};
1861 _ms[1] = {currents->r2y[i], currents->i2y[i]};
1862 _ms[2] = {currents->r2z[i], currents->i2z[i]};
1863
1864 for (int n=0; n<3; n++)
1865 {
1866 js[n] += _js[n] * expo * area;
1867 ms[n] += _ms[n] * expo * area;
1868 }
1869 }
1870
1871 ut.matVec(eye_min_rr, js, _ctemp);
1872 ut.s_mult(_ctemp, omega_mu, js_tot_factor);
1873
1874 ut.ext(r_hat, ms, _ctemp);
1875 ut.s_mult(_ctemp, k, ms_tot_factor);
1876
1877 omega_eps = C_L * k * EPS;
1878
1879 ut.matVec(eye_min_rr, ms, _ctemp);
1880 ut.s_mult(_ctemp, omega_eps, ms_tot_factor_h);
1881
1882 ut.ext(r_hat, js, _ctemp);
1883 ut.s_mult(_ctemp, k, js_tot_factor_h);
1884
1885 for (int n=0; n<3; n++)
1886 {
1887 e[n] = -js_tot_factor[n] + ms_tot_factor[n];
1888 h[n] = -ms_tot_factor[n] - js_tot_factor[n];
1889 }
1890
1891 out[0] = e;
1892 out[1] = h;
1893 return out;
1894}
1895
1896/**
1897 * Calculate far-field parallel.
1898 *
1899 * Run the propagateToFarField function in parallel blocks.
1900 *
1901 * @param cs Pointer to reflcontainer or reflcontainerf object containing source grids.
1902 * @param ct Pointer to reflcontainer or reflcontainerf object containing target grids.
1903 * @param currents Pointer to c2Bundle or c2Bundlef object containing source currents.
1904 * @param res Pointer to c2Bundle or c2Bundlef object to be filled with calculation results.
1905 *
1906 * @see reflcontainer
1907 * @see reflcontainerf
1908 * @see c2Bundle
1909 * @see c2Bundlef
1910 */
1911template <class T, class U, class V, class W>
1913 W *currents,
1914 int gmode, int ncx, int ncy,
1915 U *res)
1916{
1917 int final_step;
1918
1919 for(int n=0; n<numThreads; n++)
1920 {
1921 if(n == (numThreads-1))
1922 {
1923 final_step = gt;
1924 }
1925
1926 else
1927 {
1928 final_step = (n+1) * step;
1929 }
1930
1931 threadPool[n] = std::thread(&Propagation::propagateToFarField,
1932 this, n * step, final_step,
1933 cs, ct, currents,
1934 gmode, ncx, ncy,
1935 res);
1936 }
1937 joinThreads();
1938}
1939
1940template <class T, class U, class V, class W>
1942{
1943 for (std::thread &t : threadPool)
1944 {
1945 if (t.joinable())
1946 {
1947 t.join();
1948 }
1949 }
1950}
1951
1952template <class T, class U, class V, class W>
1953void Propagation<T, U, V, W>::_debugArray(T *arr, int idx)
1954{
1955 T toPrint = arr[idx];
1956 std::cout << "Value of c-style array, element " << idx << ", is : " << toPrint << std::endl;
1957}
1958
1959template <class T, class U, class V, class W>
1960void Propagation<T, U, V, W>::_debugArray(std::array<T, 3> arr)
1961{
1962 std::cout << arr[0] << ", " << arr[1] << ", " << arr[2] << std::endl;
1963}
1964
1965template <class T, class U, class V, class W>
1966void Propagation<T, U, V, W>::_debugArray(std::array<std::complex<T>, 3> arr)
1967{
1968 std::cout << arr[0].real() << " + " << arr[0].imag() << "j"
1969 << ", " << arr[1].real() << " + " << arr[1].imag() << "j"
1970 << ", " << arr[2].real() << " + " << arr[2].imag() << "j"
1971 << std::endl;
1972}
1973
1974
1975#endif
__host__ __device__ void _debugArray(cuFloatComplex arr[3])
Definition Debug.h:23
Header for reflector generation interface.
__device__ void farfieldAtPoint(float *d_xs, float *d_ys, float *d_zs, float *d_nxs, float *d_nys, float *d_nzs, cuFloatComplex *d_Jx, cuFloatComplex *d_Jy, cuFloatComplex *d_Jz, cuFloatComplex *d_Mx, cuFloatComplex *d_My, cuFloatComplex *d_Mz, float(&r_hat)[3], float *d_A, int gmode, int ncx, int ncy, cuFloatComplex(&e)[3], cuFloatComplex(&h)[3])
Definition Kernelsf.cu:1115
__device__ void fieldAtPoint(float *d_xs, float *d_ys, float *d_zs, float *d_nxs, float *d_nys, float *d_nzs, cuFloatComplex *d_Jx, cuFloatComplex *d_Jy, cuFloatComplex *d_Jz, cuFloatComplex *d_Mx, cuFloatComplex *d_My, cuFloatComplex *d_Mz, float(&point)[3], float *d_A, int gmode, int ncx, int ncy, cuFloatComplex(&d_ei)[3], cuFloatComplex(&d_hi)[3])
Definition Kernelsf.cu:116
Structs used within PyPO.
Linear algebra functions for the CPU version of PyPO.
Definition Propagation.h:35
Utils< T > ut
Definition Propagation.h:74
std::array< std::array< std::complex< T >, 3 >, 2 > farfieldAtPoint_Old(V *cs, W *currents, const std::array< T, 3 > &point_target)
Definition Propagation.h:1798
void parallelProp_EHP(V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:1491
void propagateBeam_EHP(int start, int stop, V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:806
std::vector< std::thread > threadPool
Definition Propagation.h:69
void propagateBeam_JM(int start, int stop, V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:343
void parallelProp_JM(V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:1349
void propagateToFarField(int start, int stop, V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:1582
void propagateBeam_JMEH_PEC(int start, int stop, V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:483
void parallelProp_EH(V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:1396
void propagateBeam_JMEH(int start, int stop, V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:639
void propagateScalarBeam(int start, int stop, V *cs, V *ct, W *field, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:934
void parallelPropScalar(V *cs, V *ct, W *field, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:1536
std::array< std::array< std::complex< T >, 3 >, 2 > farfieldAtPoint(V *cs, W *currents, int gmode, int ncx, int ncy, const std::array< T, 3 > &point_target)
Definition Propagation.h:1657
std::array< std::array< std::complex< T >, 3 >, 2 > fieldAtPoint(V *cs, W *currents, int gmode, int ncx, int ncy, const std::array< T, 3 > &point_target)
Definition Propagation.h:978
void parallelFarField(V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:1912
std::array< std::array< std::complex< T >, 3 >, 2 > fieldAtPoint_Old(V *cs, W *currents, const std::array< T, 3 > &point_target)
Definition Propagation.h:1162
Propagation(T omega, int numThreads, int gs, int gt, T epsilon, T t_direction, bool verbose=false)
Definition Propagation.h:194
void propagateBeam_EH(int start, int stop, V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:575
std::complex< T > fieldScalarAtPoint(V *cs, W *field, int gmode, int ncx, int ncy, const std::array< T, 3 > &point_target)
Definition Propagation.h:1280
void parallelProp_JMEH(V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:1445
void propagateBeam_JM_PEC(int start, int stop, V *cs, V *ct, W *currents, int gmode, int ncx, int ncy, U *res)
Definition Propagation.h:270
Definition Utils.h:23