31 {
GMSH_FULLRC,
"MatlabOutputFile",
nullptr,
"farfield.m"},
43 return "Plugin(NearToFarField) computes the far field pattern "
44 "from the near electric E and magnetic H fields on a surface "
45 "enclosing the radiating device (antenna).\n\n"
46 "Parameters: the wavenumber, the "
47 "angular discretisation (phi in [0, 2*Pi] and theta in [0, Pi]) "
48 "of the far field sphere and the indices of the views containing the "
49 "complex-valued E and H fields. If `Normalize' is set, the far field "
50 "is normalized to 1. If `dB' is set, the far field is computed in dB. "
51 "If `NegativeTime' is set, E and H are assumed to have exp(-iwt) time "
52 "dependency; otherwise they are assume to have exp(+iwt) time "
53 "dependency. If `MatlabOutputFile' is given the raw far field data is "
54 "also exported in Matlab format.\n\n"
55 "Plugin(NearToFarField) creates one new view.";
82 std::vector<element *> &allElems, std::vector<std::vector<double> > &js,
83 std::vector<std::vector<double> > &ms,
double k0,
double rFar,
double theta,
89 double sTheta = sin(theta);
90 double cTheta = cos(theta);
91 double sPhi = sin(phi);
92 double cPhi = cos(phi);
93 double r[3] = {sTheta * cPhi, sTheta * sPhi, cTheta};
95 double Z0 = 120 * M_PI;
97 int numComps = 3, numSteps = 2;
98 std::vector<std::vector<double> > N;
99 std::vector<std::vector<double> > Ns;
100 std::vector<std::vector<double> > L;
101 std::vector<std::vector<double> > Ls;
107 for(
int step = 0; step < numSteps; step++) {
108 N[step].resize(numComps, 0.);
109 Ns[step].resize(numComps);
110 L[step].resize(numComps, 0.);
111 Ls[step].resize(numComps);
115 for(std::size_t ele = 0; ele < allElems.size(); ele++) {
119 std::vector<double> valN0(numNodes * numComps), valN1(numNodes * numComps);
120 std::vector<double> valL0(numNodes * numComps), valL1(numNodes * numComps);
122 for(
int nod = 0; nod < numNodes; nod++) {
125 double r_nod[3] = {x, y,
z};
126 double rr =
prosca(r_nod, r);
127 double e_jk0rr[2] = {cos(k0 * rr), sin(k0 * rr)};
129 for(
int comp = 0; comp < numComps; comp++) {
130 if(i < (
int)js[0].size()) {
131 valN0[numComps * nod + comp] =
132 js[0][i] * e_jk0rr[0] - js[1][i] * e_jk0rr[1];
133 valN1[numComps * nod + comp] =
134 js[0][i] * e_jk0rr[1] + js[1][i] * e_jk0rr[0];
135 valL0[numComps * nod + comp] =
136 ms[0][i] * e_jk0rr[0] - ms[1][i] * e_jk0rr[1];
137 valL1[numComps * nod + comp] =
138 ms[0][i] * e_jk0rr[1] + ms[1][i] * e_jk0rr[0];
160 for(
int step = 0; step < 2; step++) {
161 Ns[step][0] = N[step][0] * sTheta * cPhi + N[step][1] * sTheta * sPhi +
163 Ns[step][1] = N[step][0] * cTheta * cPhi + N[step][1] * cTheta * sPhi -
165 Ns[step][2] = -N[step][0] * sPhi + N[step][1] * cPhi;
167 Ls[step][0] = L[step][0] * sTheta * cPhi + L[step][1] * sTheta * sPhi +
169 Ls[step][1] = L[step][0] * cTheta * cPhi + L[step][1] * cTheta * sPhi -
171 Ls[step][2] = -L[step][0] * sPhi + L[step][1] * cPhi;
177 double k0_over_4pir = k0 / (4 * M_PI * rFar);
178 double cos_k0r = cos(k0 * rFar);
179 double sin_k0r = sin(k0 * rFar);
182 E_theta[0] = -k0_over_4pir * ((Ls[0][2] + Z0 * Ns[0][1]) * sin_k0r -
183 (Ls[1][2] + Z0 * Ns[1][1]) * cos_k0r);
184 E_theta[1] = -k0_over_4pir * ((Ls[0][2] + Z0 * Ns[0][1]) * cos_k0r +
185 (Ls[1][2] + Z0 * Ns[1][1]) * sin_k0r);
187 E_phi[0] = k0_over_4pir * ((Ls[0][1] - Z0 * Ns[0][2]) * sin_k0r -
188 (Ls[1][1] - Z0 * Ns[1][2]) * cos_k0r);
189 E_phi[1] = k0_over_4pir * ((Ls[0][1] - Z0 * Ns[0][2]) * cos_k0r +
190 (Ls[1][1] - Z0 * Ns[1][2]) * sin_k0r);
192 double farF = 1. / 2. / Z0 *
193 ((E_theta[0] * E_theta[0] + E_theta[1] * E_theta[1]) +
194 (E_phi[0] * E_phi[0] + E_phi[1] * E_phi[1]));
202 std::vector<element *> &allElems, std::vector<std::vector<double> > &ffvec,
203 std::vector<std::vector<double> > &js, std::vector<std::vector<double> > &ms,
204 double k0,
double theta,
double phi)
206 double sTheta = sin(theta);
207 double cTheta = cos(theta);
208 double sPhi = sin(phi);
209 double cPhi = cos(phi);
210 double xHat[3] = {sTheta * cPhi, sTheta * sPhi, cTheta};
211 std::complex<double> I(0., 1.);
212 double Z0 = 120 * M_PI;
214 double integral_r[3] = {0., 0., 0.}, integral_i[3] = {0., 0., 0.};
216 for(std::size_t ele = 0; ele < allElems.size(); ele++) {
219 std::vector<double> integrand_r(numNodes * 3), integrand_i(numNodes * 3);
220 for(
int nod = 0; nod < numNodes; nod++) {
222 e->
getXYZ(nod, y[0], y[1], y[2]);
223 double const xHat_dot_y =
prosca(xHat, y);
224 double n_x_e_r[3] = {-ms[0][i], -ms[0][i + 1], -ms[0][i + 2]};
225 double n_x_e_i[3] = {-ms[1][i], -ms[1][i + 1], -ms[1][i + 2]};
226 double n_x_h_r[3] = {js[0][i], js[0][i + 1], js[0][i + 2]};
227 double n_x_h_i[3] = {js[1][i], js[1][i + 1], js[1][i + 2]};
228 double n_x_h_x_xHat_r[3], n_x_h_x_xHat_i[3];
229 prodve(n_x_h_r, xHat, n_x_h_x_xHat_r);
230 prodve(n_x_h_i, xHat, n_x_h_x_xHat_i);
231 for(
int comp = 0; comp < 3; comp++) {
232 std::complex<double> n_x_e(n_x_e_r[comp], n_x_e_i[comp]);
233 std::complex<double> n_x_h_x_xHat(n_x_h_x_xHat_r[comp],
234 n_x_h_x_xHat_i[comp]);
236 std::complex<double> integrand =
237 (n_x_e + Z0 * n_x_h_x_xHat) *
238 (cos(-k0 * xHat_dot_y) + I * sin(-k0 * xHat_dot_y));
239 integrand_r[3 * nod + comp] = integrand.real();
240 integrand_i[3 * nod + comp] = integrand.imag();
244 for(
int comp = 0; comp < 3; comp++) {
245 integral_r[comp] += e->
integrate(&integrand_r[comp], 3);
246 integral_i[comp] += e->
integrate(&integrand_i[comp], 3);
250 double xHat_x_integral_r[3], xHat_x_integral_i[3];
251 prodve(xHat, integral_r, xHat_x_integral_r);
252 prodve(xHat, integral_i, xHat_x_integral_i);
253 std::complex<double> coef = I * k0 / 4. / M_PI;
254 std::complex<double> einf[3] = {
255 coef * (xHat_x_integral_r[0] + I * xHat_x_integral_i[0]),
256 coef * (xHat_x_integral_r[1] + I * xHat_x_integral_i[1]),
257 coef * (xHat_x_integral_r[2] + I * xHat_x_integral_i[2])};
259 double coef1 = k0 / 4. / M_PI;
260 for(
int comp = 0; comp < 3; comp++) {
261 ffvec[comp][0] = -coef1 * xHat_x_integral_i[comp];
262 ffvec[comp][1] = coef1 * xHat_x_integral_r[comp];
269 std::vector<std::vector<double> > &vec)
271 fprintf(fp,
"%s = [", name.c_str());
272 for(std::size_t i = 0; i < vec.size(); i++)
273 for(std::size_t j = 0; j < vec[i].size(); j++)
274 fprintf(fp,
"%.16g ", vec[i][j]);
298 Msg::Error(
"NearToFarField plugin could not find EView %i", _eView);
303 Msg::Error(
"NearToFarField plugin could not find HView %i", _hView);
312 Msg::Error(
"Incompatible views for E field and H field");
317 Msg::Error(
"Invalid number of steps for E or H fields (must be complex)");
327 double r_sph = lc ? lc / 2. : 1;
332 Msg::Error(
"E and H fields must be given on the same grid");
337 std::vector<element *> allElems;
338 std::vector<std::vector<double> > js(2);
339 std::vector<std::vector<double> > ms(2);
346 if(numComp != 3)
continue;
348 if(dim != 1 && dim != 2)
continue;
350 std::vector<double> x(numNodes), y(numNodes),
z(numNodes);
351 for(
int nod = 0; nod < numNodes; nod++)
352 eData->
getNode(0, ent, ele, nod, x[nod], y[nod],
z[nod]);
356 factory.
create(numNodes, dim, &x[0], &y[0], &
z[0],
true));
358 double n[3] = {0., 0., 0.};
364 for(
int step = 0; step < 2; step++) {
365 for(
int nod = 0; nod < numNodes; nod++) {
367 for(
int comp = 0; comp < numComp; comp++) {
368 eData->
getValue(step, ent, ele, nod, comp, e[comp]);
369 hData->
getValue(step, ent, ele, nod, comp, h[comp]);
374 js[step].push_back(j[0]);
375 js[step].push_back(j[1]);
376 js[step].push_back(j[2]);
377 ms[step].push_back(m[0]);
378 ms[step].push_back(m[1]);
379 ms[step].push_back(m[2]);
385 if(allElems.empty()) {
386 Msg::Error(
"No valid elements found to compute far field");
394 std::vector<std::vector<double> > phi(_nbPhi + 1), theta(_nbPhi + 1);
395 std::vector<std::vector<double> > x(_nbPhi + 1), y(_nbPhi + 1),
z(_nbPhi + 1);
396 std::vector<std::vector<double> > farField(_nbPhi + 1);
397 std::vector<std::vector<double> > farField1r(_nbPhi + 1);
398 std::vector<std::vector<double> > farField2r(_nbPhi + 1);
399 std::vector<std::vector<double> > farField3r(_nbPhi + 1);
400 std::vector<std::vector<double> > farField1i(_nbPhi + 1);
401 std::vector<std::vector<double> > farField2i(_nbPhi + 1);
402 std::vector<std::vector<double> > farField3i(_nbPhi + 1);
403 std::vector<std::vector<double> > farFieldVec(3);
404 for(
int comp = 0; comp < 3; comp++) { farFieldVec[comp].resize(2, 0.); }
406 for(
int i = 0; i <= _nbPhi; i++) {
407 phi[i].resize(_nbThe + 1);
408 theta[i].resize(_nbThe + 1);
409 x[i].resize(_nbThe + 1);
410 y[i].resize(_nbThe + 1);
411 z[i].resize(_nbThe + 1);
412 farField[i].resize(_nbThe + 1);
414 farField1r[i].resize(_nbThe + 1);
415 farField2r[i].resize(_nbThe + 1);
416 farField3r[i].resize(_nbThe + 1);
417 farField1i[i].resize(_nbThe + 1);
418 farField2i[i].resize(_nbThe + 1);
419 farField3i[i].resize(_nbThe + 1);
422 double dPhi = (_phiEnd - _phiStart) / _nbPhi;
423 double dTheta = (_thetaEnd - _thetaStart) / _nbThe;
424 double ffmin = 1e200, ffmax = -1e200;
426 for(
int i = 0; i <= _nbPhi; i++) {
427 for(
int j = 0; j <= _nbThe; j++) {
428 phi[i][j] = _phiStart + i * dPhi;
429 theta[i][j] = _thetaStart + j * dTheta;
432 theta[i][j], phi[i][j]);
433 farField1r[i][j] = farFieldVec[0][0];
434 farField2r[i][j] = farFieldVec[1][0];
435 farField3r[i][j] = farFieldVec[2][0];
436 farField1i[i][j] = farFieldVec[0][1];
437 farField2i[i][j] = farFieldVec[1][1];
438 farField3i[i][j] = farFieldVec[2][1];
441 double rfar = (_rfar ? _rfar : 10 * lc);
443 getFarFieldJin(allElems, js, ms, _k0, rfar, theta[i][j], phi[i][j]);
445 ffmin = std::min(ffmin, farField[i][j]);
446 ffmax = std::max(ffmax, farField[i][j]);
451 for(std::size_t i = 0; i < allElems.size(); i++)
delete allElems[i];
457 for(
int i = 0; i <= _nbPhi; i++)
458 for(
int j = 0; j <= _nbThe; j++) farField[i][j] /= ffmax;
464 for(
int i = 0; i <= _nbPhi; i++) {
465 for(
int j = 0; j <= _nbThe; j++) {
466 farField[i][j] = 10 * log10(farField[i][j]);
467 ffmin = std::min(ffmin, farField[i][j]);
468 ffmax = std::max(ffmax, farField[i][j]);
473 for(
int i = 0; i <= _nbPhi; i++) {
474 for(
int j = 0; j <= _nbThe; j++) {
475 double df = (ffmax - ffmin);
480 double f = (farField[i][j] - ffmin) /
df;
481 x[i][j] = x0 + r_sph *
f * sin(theta[i][j]) * cos(phi[i][j]);
482 y[i][j] = y0 + r_sph *
f * sin(theta[i][j]) * sin(phi[i][j]);
483 z[i][j] = z0 + r_sph *
f * cos(theta[i][j]);
487 if(_outFile.size()) {
488 FILE *fp =
Fopen(_outFile.c_str(),
"w");
509 Msg::Error(
"Could not open file '%s'", _outFile.c_str());
512 for(
int i = 0; i < _nbPhi; i++) {
513 for(
int j = 0; j < _nbThe; j++) {
514 if(_nbPhi == 1 || _nbThe == 1) {
516 dataFar->
SP.push_back(x[i][j]);
517 dataFar->
SP.push_back(y[i][j]);
518 dataFar->
SP.push_back(
z[i][j]);
519 dataFar->
SP.push_back(farField[i][j]);
522 double P1[3] = {x[i][j], y[i][j],
z[i][j]};
523 double P2[3] = {x[i + 1][j], y[i + 1][j],
z[i + 1][j]};
524 double P3[3] = {x[i + 1][j + 1], y[i + 1][j + 1],
z[i + 1][j + 1]};
525 double P4[3] = {x[i][j + 1], y[i][j + 1],
z[i][j + 1]};
527 dataFar->
SQ.push_back(P1[0]);
528 dataFar->
SQ.push_back(P2[0]);
529 dataFar->
SQ.push_back(P3[0]);
530 dataFar->
SQ.push_back(P4[0]);
531 dataFar->
SQ.push_back(P1[1]);
532 dataFar->
SQ.push_back(P2[1]);
533 dataFar->
SQ.push_back(P3[1]);
534 dataFar->
SQ.push_back(P4[1]);
535 dataFar->
SQ.push_back(P1[2]);
536 dataFar->
SQ.push_back(P2[2]);
537 dataFar->
SQ.push_back(P3[2]);
538 dataFar->
SQ.push_back(P4[2]);
539 dataFar->
SQ.push_back(farField[i][j]);
540 dataFar->
SQ.push_back(farField[i + 1][j]);
541 dataFar->
SQ.push_back(farField[i + 1][j + 1]);
542 dataFar->
SQ.push_back(farField[i][j + 1]);
547 dataFar->
setName(
"_NearToFarField");