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