main.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // This code simulates the electromagnetic wave radiation of a half-wave dipole antenna excited at 1 GHz.
  2. // The simulation is performed in 2D (i.e. the fields are constant in the z direction). The goal of this code
  3. // is to provide a lightweight example that can be used with minimal modifications to simulate actual 3D antennas.
  4. //
  5. // The radiation pattern of this dipole antenna can be obtained by calling 'interpolate' on the time-averaged power
  6. // expression for the points of a circle near the domain boundary and centered at the origin. The interpolated
  7. // values can then be saved to .csv using 'writevector' and 'polarplot' could be used in Matlab for visualization.
  8. #include "sparselizardbase.h"
  9. using namespace mathop;
  10. void sparselizard(void)
  11. {
  12. wallclock clk;
  13. // The domain regions as defined in 'dipoleantenna.geo':
  14. int air = 1, conductor = 2, feed = 3, boundary = 4;
  15. mesh mymesh("dipoleantenna.msh");
  16. // Define the whole non-conducting region for convenience:
  17. int wholedomain = regionunion({air, feed});
  18. // Edge shape functions 'hcurl' for the electric field E.
  19. // Because of the propagating EM waves the electric field has an
  20. // in-phase and quadrature component (thus harmonics 2 and 3 are used):
  21. // E = E2 * sin(2*pi*1GHz*t) + E3 * cos(2*pi*1GHz*t).
  22. field E("hcurl", {2,3});
  23. field Es = E.harmonic(2), Ec = E.harmonic(3);
  24. // Use interpolation order 2 on the whole domain:
  25. E.setorder(wholedomain, 2);
  26. // Define the speed of light [m/s] and the working frequency [Hz].
  27. // The total half-wave dipole antenna length is 15 cm. This corresponds to a 1GHz frequency:
  28. double c = 3e8, freq = 1e9;
  29. setfundamentalfrequency(freq);
  30. // The dipole is a perfect conductor. We thus force E to 0 on it:
  31. E.setconstraint(conductor);
  32. // We force an electric field of 1 V/m in the y direction on the feed port
  33. // for the sin component of E only (the cos component is forced to zero):
  34. Es.setconstraint(feed, array3x1(0,1,0));
  35. Ec.setconstraint(feed);
  36. formulation maxwell;
  37. // This is the weak formulation in time for electromagnetic waves:
  38. maxwell += integral(wholedomain, -curl(dof(E))*curl(tf(E)) - 1/(c*c)*dtdt(dof(E))*tf(E));
  39. // The OUTWARD pointing normal is required for the wave radiation condition.
  40. // Depending on the 'boundary' lines orientation the normal can be flipped.
  41. // To confirm the normal direction it is written to disk below:
  42. expression n = -normal(boundary);
  43. n.write(boundary, "normal.pos");
  44. // Silver-Mueller radiation condition to force outgoing electromagnetic waves:
  45. maxwell += integral(boundary, -1/c * crossproduct(crossproduct(n, dt(dof(E))), n) * tf(E));
  46. // Generate the algebraic matrices A and right handside b of Ax = b:
  47. maxwell.generate();
  48. // Get the solution vector x of Ax = b:
  49. vec solE = solve(maxwell.A(), maxwell.b());
  50. // Transfer the data in the solution vector to field E:
  51. E.setdata(wholedomain, solE);
  52. clk.print("Resolution time (before post-processing):");
  53. // Save the electric field E and magnetic field H with an order 2 interpolation.
  54. // Since from Maxwell -mu0*dt(H) = curl(E) we have that H = 1/(mu0*w^2) * curl(dt(E)).
  55. double mu0 = 4*getpi()*1e-7;
  56. expression H = 1/(mu0*pow(2*getpi()*freq, 2)) * curl(dt(E));
  57. H.write(wholedomain, "H.pos", 2);
  58. E.write(wholedomain, "E.pos", 2);
  59. // Write the electric field at 50 timesteps of a period for a time visualization:
  60. E.write(wholedomain, "E.pos", 2, 50);
  61. // Write the Poynting vector E x H.
  62. expression S = crossproduct(E, H);
  63. // This involves a product that makes new harmonics appear at 2x1GHz (harmonics 4 and 5) plus a
  64. // constant component (harmonic 1). An FFT is thus required (performed on 6 timesteps below):
  65. S.write(wholedomain, 6, "S.pos", 2);
  66. // Also save in time at 50 timesteps of a period:
  67. S.write(wholedomain, "S.pos", 2, 50);
  68. // Code validation line. Can be removed.
  69. std::cout << (norm(crossproduct(Es,Ec)).max(wholedomain, 5)[0] < 0.00218416 && norm(crossproduct(Es,Ec)).max(wholedomain, 5)[0] > 0.00218413);
  70. }
  71. int main(void)
  72. {
  73. SlepcInitialize(0,{},0,0);
  74. sparselizard();
  75. SlepcFinalize();
  76. return 0;
  77. }