Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ComputeProperties.c
Go to the documentation of this file.
1/*
2(c) 2005, Supratik Mukhopadhayay, Nayana Majumdar
3*/
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <time.h>
8#include <unistd.h>
9
10#ifdef _OPENMP
11#include <omp.h>
12#endif
13
14#include "neBEMInterface.h"
15#include "Isles.h"
16#include "NR.h"
17#include "Vector.h"
18#include "neBEM.h"
19
20#ifdef __cplusplus
21namespace {
22 static constexpr double InvFourPiEps0 = 1. / MyFACTOR;
23}
24
25namespace neBEM {
26#endif
27
28// Weighting field function (WtPFAtPoint) has not been modified!
29// Should be merged with PFAtPoint function.
30// Check the notes written ahead of the weighting field function.
31
32// Potential per unit charge density on an element
33double GetPotential(int ele, Point3D *localP) {
34 double value;
35
36 switch ((EleArr + ele - 1)->G.Type) {
37 case 4: // rectangular element
38 value = RecPot(ele, localP);
39 break;
40 case 3: // triangular element
41 value = TriPot(ele, localP);
42 break;
43 case 2: // linear (wire) element
44 value = WirePot(ele, localP);
45 break;
46 default:
47 printf("Geometrical type out of range! ... exiting ...\n");
48 exit(-1);
49 break; // never comes here
50 } // switch over gtsrc ends
51
52 return (value);
53} // end of GetPotential
54
55// Potential due to unit charge density on this element
56double RecPot(int ele, Point3D *localP) {
57 if (DebugLevel == 301) {
58 printf("In RecPot ...\n");
59 }
60
61 double Pot;
62 Vector3D Field;
63 double xpt = localP->X;
64 double ypt = localP->Y;
65 double zpt = localP->Z;
66
67 double a = (EleArr + ele - 1)->G.LX;
68 double b = (EleArr + ele - 1)->G.LZ;
69 double diag = sqrt(a * a + b * b); // diagonal of the element
70
71 // distance of field point from element centroid
72 double dist = sqrt(xpt * xpt + ypt * ypt + zpt * zpt);
73
74 if (dist >= FarField * diag) // all are distances and, hence, +ve
75 {
76 double dA = a * b;
77 Pot = dA / dist;
78 } else {
79 // normalize distances by `a' while sending - likely to improve accuracy
80 int fstatus =
81 ExactRecSurf(xpt / a, ypt / a, zpt / a, -0.5, -(b / a) / 2.0,
82 0.5, (b / a) / 2.0, &Pot, &Field);
83 if (fstatus) // non-zero
84 {
85 printf("problem in computing Potential of rectangular element ... \n");
86 printf("a: %lg, b: %lg, X: %lg, Y: %lg, Z: %lg\n", a, b, xpt, ypt, zpt);
87 // printf("returning ...\n");
88 // return -1; void function at present
89 }
90 Pot *= a; // rescale Potential - cannot be done outside because of the `if'
91 }
92
93#ifdef __cplusplus
94 return Pot * InvFourPiEps0;
95#else
96 return (Pot / MyFACTOR);
97#endif
98} // end of RecPot
99
100// Potential due to unit charge density on a triangular element
101double TriPot(int ele, Point3D *localP) {
102 if (DebugLevel == 301) {
103 printf("In TriPot ...\n");
104 }
105
106 double Pot;
107 Vector3D Field;
108 double xpt = localP->X;
109 double ypt = localP->Y;
110 double zpt = localP->Z;
111
112 // distance of field point from element centroid
113 double a = (EleArr + ele - 1)->G.LX;
114 double b = (EleArr + ele - 1)->G.LZ;
115 // largest side (hypotenuse) of the element
116 double diag = sqrt(a * a + b * b);
117
118 const double xm = xpt - a / 3.;
119 const double zm = zpt - b / 3.;
120 double dist = sqrt(xm * xm + ypt * ypt + zm * zm);
121
122 if (dist >= FarField * diag) {
123 double dA = 0.5 * a * b; // area of the triangular element
124 Pot = dA / dist;
125 } else {
126 int fstatus = ExactTriSurf(b / a, xpt / a, ypt / a, zpt / a, &Pot, &Field);
127 if (fstatus) { // non-zero
128 printf("problem in computing Potential of triangular element ... \n");
129 printf("a: %lg, b: %lg, X: %lg, Y: %lg, Z: %lg\n", a, b, xpt, ypt, zpt);
130 // printf("returning ...\n");
131 // return -1; void function at present
132 }
133 Pot *= a; // rescale Potential
134 }
135
136#ifdef __cplusplus
137 return Pot * InvFourPiEps0;
138#else
139 return (Pot / MyFACTOR);
140#endif
141} // end of TriPot
142
143// Potential due to unit charge density on this element
144// arguments not normalized yet
145double WirePot(int ele, Point3D *localP) {
146 if (DebugLevel == 301) {
147 printf("In WirePot ...\n");
148 }
149
150 double Pot;
151 double xpt = localP->X;
152 double ypt = localP->Y;
153 double zpt = localP->Z;
154
155 double rW = (EleArr + ele - 1)->G.LX;
156 double lW = (EleArr + ele - 1)->G.LZ;
157
158 // field point from element centroid
159 double dist = sqrt(xpt * xpt + ypt * ypt + zpt * zpt);
160
161 if (dist >= FarField * lW) // all are distances and, hence, +ve
162 {
163 double dA = 2.0 * ST_PI * rW * lW;
164 // Pot = ApproxP_W(rW, lW, X, Y, Z, 1);
165 Pot = dA / dist;
166 } else if ((fabs(xpt) < MINDIST) && (fabs(ypt) < MINDIST) &&
167 (fabs(zpt) < MINDIST)) {
168 Pot = ExactCentroidalP_W(rW, lW);
169 } else if ((fabs(xpt) < MINDIST) && (fabs(ypt) < MINDIST)) {
170 Pot = ExactAxialP_W(rW, lW, localP->Z);
171 } else {
172 Pot = ExactThinP_W(rW, lW, xpt, ypt, zpt);
173 }
174
175#ifdef __cplusplus
176 return Pot * InvFourPiEps0;
177#else
178 return (Pot / MyFACTOR);
179#endif
180} // end of WirePot
181
182// Flux per unit charge density on an element returned as globalF
183// in the global coordiante system
184void GetFluxGCS(int ele, Point3D *localP, Vector3D *globalF) {
185 Vector3D localF;
186
187 switch ((EleArr + ele - 1)->G.Type) {
188 case 4: // rectangular element
189 RecFlux(ele, localP, &localF);
190 break;
191 case 3: // triangular element
192 TriFlux(ele, localP, &localF);
193 break;
194 case 2: // linear (wire) element
195 WireFlux(ele, localP, &localF);
196 break;
197 default:
198 printf("Geometrical type out of range! ... exiting ...\n");
199 exit(-1);
200 break; // never comes here
201 } // switch over gtsrc ends
202
203 (*globalF) = RotateVector3D(&localF, &(EleArr + ele - 1)->G.DC, local2global);
204} // end of GetFluxGCS
205
206// Flux per unit charge density on an element returned as localF
207// in the local coordiante system
208void GetFlux(int ele, Point3D *localP, Vector3D *localF) {
209 switch ((EleArr + ele - 1)->G.Type) {
210 case 4: // rectangular element
211 RecFlux(ele, localP, localF);
212 break;
213 case 3: // triangular element
214 TriFlux(ele, localP, localF);
215 break;
216 case 2: // linear (wire) element
217 WireFlux(ele, localP, localF);
218 break;
219 default:
220 printf("Geometrical type out of range! ... exiting ...\n");
221 exit(-1);
222 break; // never comes here
223 } // switch over gtsrc ends
224} // end of GetFlux
225
226// local coord flux localF per unit charge density on one rectangular element
227void RecFlux(int ele, Point3D *localP, Vector3D *localF) {
228 if (DebugLevel == 301) {
229 printf("In RecFlux ...\n");
230 }
231
232 double xpt = localP->X;
233 double ypt = localP->Y;
234 double zpt = localP->Z;
235
236 double a = (EleArr + ele - 1)->G.LX;
237 double b = (EleArr + ele - 1)->G.LZ;
238 double diag = sqrt(a * a + b * b); // diagonal of the element
239
240 // distance of field point from element centroid
241 double dist = sqrt(xpt * xpt + ypt * ypt + zpt * zpt);
242
243 // no re-scaling necessary for `E'
244 if (dist >= FarField * diag) {
245 const double f = a * b / (dist * dist * dist);
246 localF->X = xpt * f;
247 localF->Y = ypt * f;
248 localF->Z = zpt * f;
249 } else {
250 double Pot;
251 int fstatus =
252 ExactRecSurf(xpt / a, ypt / a, zpt / a, -0.5, -(b / a) / 2.0,
253 0.5, (b / a) / 2.0, &Pot, localF);
254 if (fstatus) { // non-zero
255 printf("problem in computing flux of rectangular element ... \n");
256 // printf("returning ...\n");
257 // return -1; void function at present
258 }
259 }
260
261#ifdef __cplusplus
262 localF->X *= InvFourPiEps0;
263 localF->Y *= InvFourPiEps0;
264 localF->Z *= InvFourPiEps0;
265#else
266 localF->X /= MyFACTOR;
267 localF->Y /= MyFACTOR;
268 localF->Z /= MyFACTOR;
269#endif
270} // end of RecFlux
271
272// local coord flux per unit charge density on a triangluar element
273void TriFlux(int ele, Point3D *localP, Vector3D *localF) {
274 if (DebugLevel == 301) {
275 printf("In TriFlux ...\n");
276 }
277
278 double xpt = localP->X;
279 double ypt = localP->Y;
280 double zpt = localP->Z;
281
282 double a = (EleArr + ele - 1)->G.LX;
283 double b = (EleArr + ele - 1)->G.LZ;
284 double diag = sqrt(a * a + b * b); // diagonal of the element
285
286 // printf("In TriFlux\n");
287 // printf("a: %lg, b: %lg, X: %lg, Y: %lg, Z: %lg\n", a, b, X, Y, Z);
288
289 // distance of field point from element centroid
290 const double xm = xpt - a / 3.;
291 const double zm = zpt - b / 3.;
292 double dist = sqrt(xm * xm + ypt * ypt + zm * zm);
293
294 if (dist >= FarField * diag) {
295 const double f = 0.5 * a * b / (dist * dist * dist);
296 localF->X = xpt * f;
297 localF->Y = ypt * f;
298 localF->Z = zpt * f;
299 } else {
300 double Pot;
301 int fstatus = ExactTriSurf(b / a, xpt / a, ypt / a, zpt / a, &Pot, localF);
302 // fstatus = ApproxTriSurf(b/a, X/a, Y/a, Z/a, 5000, 5000, &Pot, &Flux);
303 if (fstatus) { // non-zero
304 printf("problem in computing flux of triangular element ... \n");
305 // printf("returning ...\n");
306 // return -1; void function at present
307 }
308 }
309
310#ifdef __cplusplus
311 localF->X *= InvFourPiEps0;
312 localF->Y *= InvFourPiEps0;
313 localF->Z *= InvFourPiEps0;
314#else
315 localF->X /= MyFACTOR;
316 localF->Y /= MyFACTOR;
317 localF->Z /= MyFACTOR;
318#endif
319 // printf("Pot: %lg, Ex: %lg, Ey: %lg, Ez: %lg\n",
320 // Pot, localF.X, localF.Y, localF.Z);
321 // printf("Out of TriFlux\n");
322} // end of TriFlux
323
324// local coord flux per unit charge density on a wire element
325void WireFlux(int ele, Point3D *localP, Vector3D *localF) {
326 if (DebugLevel == 301) {
327 printf("In WireFlux ...\n");
328 }
329
330 double xpt = localP->X;
331 double ypt = localP->Y;
332 double zpt = localP->Z;
333 double rW = (EleArr + ele - 1)->G.LX;
334 double lW = (EleArr + ele - 1)->G.LZ;
335
336 // field point from element centroid
337 double dist = sqrt(xpt * xpt + ypt * ypt + zpt * zpt);
338
339 if (dist >= FarField * lW) {
340 const double f = 2.0 * ST_PI * rW * lW / (dist * dist * dist);
341 localF->X = xpt * f;
342 localF->Y = ypt * f;
343 localF->Z = zpt * f;
344 } else {
345 if ((fabs(xpt) < MINDIST) && (fabs(ypt) < MINDIST)) {
346 localF->X = localF->Y = 0.0;
347 } else {
348 localF->X = ExactThinFX_W(rW, lW, xpt, ypt, zpt);
349
350 localF->Y = ExactThinFY_W(rW, lW, xpt, ypt, zpt);
351 }
352
353 // Ez
354 localF->Z = ExactThinFZ_W(rW, lW, xpt, ypt, zpt);
355 }
356
357#ifdef __cplusplus
358 localF->X *= InvFourPiEps0;
359 localF->Y *= InvFourPiEps0;
360 localF->Z *= InvFourPiEps0;
361#else
362 localF->X /= MyFACTOR;
363 localF->Y /= MyFACTOR;
364 localF->Z /= MyFACTOR;
365#endif
366} // end of WireFlux
367
368/* PFAtPoint without multi-threading (borrowed from 1.8.15)
369// do not erase this redundant function - the multi-threaded version is quite
370// complex and this may work as a fall-back option.
371// Gives three components of the total Potential and flux in the global
372// coordinate system due to all the elements
373int PFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF) {
374 double xfld = globalP->X;
375 double yfld = globalP->Y;
376 double zfld = globalP->Z;
377 Point3D fldpt;
378 fldpt.X = xfld; fldpt.Y = yfld; fldpt.Z = zfld;
379 double TransformationMatrix[3][3] = {{0.0, 0.0, 0.0},
380 {0.0, 0.0, 0.0},
381 {0.0, 0.0, 0.0}};
382
383 // Compute Potential and field at different locations
384 *Potential = globalF->X = globalF->Y = globalF->Z = 0.0;
385
386 // Effects due to base primitives and their repetitions are considered in the
387 // local coordinate system of the primitive (or element), while effects due to
388 // mirror elements and their repetitions are considered in the global
389 // coordinate system (GCS). This works because the direction cosines of a
390 // primitive (and its elements) and those of its repetitions are the same.
391 // As a result, we can do just one transformation from local to global at the
392 // end of calculations related to a primitive. This can save substantial
393 // computation if a discretized version of the primitive is being used since
394 // we avoid one unnecessary transformation for each element that comprises a
395 // primitive.
396 // Begin with primitive description of the device
397 double tmpPot;
398 Vector3D tmpF;
399
400 for(unsigned int primsrc = 1; primsrc <= NbPrimitives; ++primsrc) {
401 double xpsrc = PrimOriginX[primsrc];
402 double ypsrc = PrimOriginY[primsrc];
403 double zpsrc = PrimOriginZ[primsrc];
404
405 Vector3D localF;
406 localF.X = localF.Y = localF.Z = 0.0;
407
408 // Set up transform matrix for this primitive, which is also the same for
409 // all the elements belonging to this primitive
410 TransformationMatrix[0][0] = PrimDC[primsrc].XUnit.X;
411 TransformationMatrix[0][1] = PrimDC[primsrc].XUnit.Y;
412 TransformationMatrix[0][2] = PrimDC[primsrc].XUnit.Z;
413 TransformationMatrix[1][0] = PrimDC[primsrc].YUnit.X;
414 TransformationMatrix[1][1] = PrimDC[primsrc].YUnit.Y;
415 TransformationMatrix[1][2] = PrimDC[primsrc].YUnit.Z;
416 TransformationMatrix[2][0] = PrimDC[primsrc].ZUnit.X;
417 TransformationMatrix[2][1] = PrimDC[primsrc].ZUnit.Y;
418 TransformationMatrix[2][2] = PrimDC[primsrc].ZUnit.Z;
419
420 // The total influence is due to primitives on the basic device and due to
421 // virtual primitives arising out of repetition, reflection etc and not
422 // residing on the basic device
423
424 { // basic device
425 Point3D localPP; // point primitive
426 // point translated to the ECS origin, but axes direction global
427 { // Rotate point from global to local system
428 double InitialVector[3] = {xfld - xpsrc, yfld - ypsrc, zfld - zpsrc};
429 double FinalVector[3] = {0., 0., 0.};
430 for (int i = 0; i < 3; ++i) {
431 for (int j = 0 ; j < 3; ++j) {
432 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
433 }
434 }
435 localPP.X = FinalVector[0];
436 localPP.Y = FinalVector[1];
437 localPP.Z = FinalVector[2];
438 } // Point3D rotated
439
440 // evaluate possibility whether primitive influence is accurate enough
441 // This could be based on localPP and the subtended solid angle
442 int PrimOK = 0;
443
444 if (PrimOK) { // if 1, then only primitive influence will be considered
445 // Potential and flux (local system) due to base primitive
446 GetPrimPF(primsrc, &localPP, &tmpPot, &tmpF);
447 const double qpr = AvChDen[primsrc] + AvAsgndChDen[primsrc];
448 *Potential += qpr * tmpPot;
449 localF.X += qpr * tmpF.X;
450 localF.Y += qpr * tmpF.Y;
451 localF.Z += qpr * tmpF.Z;
452 if (DebugLevel == 301) {
453 printf("PFAtPoint base primitive =>\n");
454 printf("primsrc: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n",
455 primsrc, localPP.X, localPP.Y, localPP.Z);
456 printf("primsrc: %d, Pot: %lg, Fx: %lg, Fx: %lg, Fz: %lg\n",
457 primsrc, tmpPot, tmpF.X, tmpF.Y, tmpF.Z);
458 printf("primsrc: %d, SumPot: %lg, SumFx: %lg, SumFy: %lg, SumFz: %lg\n",
459 primsrc, *Potential, localF.X, localF.Y, localF.Z);
460 }
461 } else {
462 // element influence
463
464 for (unsigned int ele = ElementBgn[primsrc]; ele <= ElementEnd[primsrc]; ++ele) {
465 double xsrc = (EleArr+ele-1)->G.Origin.X;
466 double ysrc = (EleArr+ele-1)->G.Origin.Y;
467 double zsrc = (EleArr+ele-1)->G.Origin.Z;
468 // Rotate point from global to local system
469 // matrix as for primitive
470 double vG[3] = {xfld - xsrc, yfld - ysrc, zfld - zsrc};
471 double vL[3] = {0., 0., 0.};
472 for (int i = 0; i < 3; ++i) {
473 for (int j = 0; j < 3; ++j) {
474 vL[i] += TransformationMatrix[i][j] * vG[j];
475 }
476 }
477 // Potential and flux (local system)
478 const int type = (EleArr + ele - 1)->G.Type;
479 const double a = (EleArr + ele - 1)->G.LX;
480 const double b = (EleArr + ele - 1)->G.LZ;
481 GetPF(type, a, b, vL[0], vL[1], vL[2], &tmpPot, &tmpF);
482 const double qel = (EleArr+ele-1)->Solution + (EleArr+ele-1)->Assigned;
483 (*Potential) += qel * tmpPot;
484 localF.X += qel * tmpF.X;
485 localF.Y += qel * tmpF.Y;
486 localF.Z += qel * tmpF.Z;
487 if (DebugLevel == 301) {
488 printf("PFAtPoint base primitive =>\n");
489 printf("ele: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n",
490 ele, vL[0], vL[1], vL[2]);
491 printf("ele: %d, Pot: %lg, Fx: %lg, Fx: %lg, Fz: %lg\n",
492 ele, tmpPot, tmpF.X, tmpF.Y, tmpF.Z);
493 printf("ele: %d, SumPot: %lg, SumFx: %lg, SumFy: %lg, SumFz: %lg\n",
494 ele, *Potential, localF.X, localF.Y, localF.Z);
495 }
496 } // for all the elements on this primsrc primitive
497 } // else elements influence
498 } // basic device ends
499
500 if (MirrorTypeX[primsrc] || MirrorTypeY[primsrc] || MirrorTypeZ[primsrc]) {
501 // Mirror effect of base primitives
502 printf("Mirror may not be correctly implemented ...\n");
503 exit(0);
504 } // Mirror effect ends
505
506 // Flux due to repeated primitives
507 if ((PeriodicTypeX[primsrc] == 1) || (PeriodicTypeY[primsrc] == 1) ||
508 (PeriodicTypeZ[primsrc] == 1)) {
509 if (PeriodicInX[primsrc] || PeriodicInY[primsrc] || PeriodicInZ[primsrc]) {
510 for (int xrpt = -PeriodicInX[primsrc]; xrpt <= PeriodicInX[primsrc]; ++xrpt) {
511 double XPOfRpt = xpsrc + XPeriod[primsrc] * (double)xrpt;
512 for (int yrpt = -PeriodicInY[primsrc]; yrpt <= PeriodicInY[primsrc]; ++yrpt) {
513 double YPOfRpt = ypsrc + YPeriod[primsrc] * (double)yrpt;
514 for (int zrpt = -PeriodicInZ[primsrc]; zrpt <= PeriodicInZ[primsrc]; ++zrpt) {
515 double ZPOfRpt = zpsrc + ZPeriod[primsrc] * (double)zrpt;
516 if ((xrpt == 0) && (yrpt == 0) && (zrpt == 0)) {
517 continue; // this is the base device
518 }
519 { // basic primitive repeated
520 Point3D localPPR;
521 {
522 double InitialVector[3] = {xfld - XPOfRpt, yfld - YPOfRpt, zfld - ZPOfRpt};
523 double FinalVector[3] = {0., 0., 0.};
524 for (int i = 0; i < 3; ++i) {
525 for (int j = 0; j < 3; ++j) {
526 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
527 }
528 }
529 localPPR.X = FinalVector[0];
530 localPPR.Y = FinalVector[1];
531 localPPR.Z = FinalVector[2];
532 } // Point3D rotated
533 int PrimOK = 0;
534 // consider primitive representation accurate enough if it is
535 // repeated and beyond PrimAfter repetitions.
536 if (PrimAfter == 0) {
537 // If PrimAfter is zero, PrimOK is always zero
538 PrimOK = 0;
539 // and the following is not evaluated at all.
540 } else if (abs(xrpt) > PrimAfter && abs(yrpt) > PrimAfter) {
541 PrimOK = 1;
542 }
543 if (PrimOK) {
544 // use primitive representation
545 // Potential and flux (local system) due to repeated primitive
546 GetPrimPF(primsrc, &localPPR, &tmpPot, &tmpF);
547 const double qpr = AvChDen[primsrc] + AvAsgndChDen[primsrc];
548 *Potential += qpr * tmpPot;
549 localF.X += qpr * tmpF.X;
550 localF.Y += qpr * tmpF.Y;
551 localF.Z += qpr * tmpF.Z;
552 if (DebugLevel == 301) {
553 printf("primsrc: %d, xlocal: %lg, ylocal: %lg, zlocal: %lg\n",
554 primsrc, localPPR.X, localPPR.Y, localPPR.Z);
555 printf("primsrc: %d, Pot: %lg, Fx: %lg, Fy: %lg, Fz: %lg\n",
556 primsrc, tmpPot * qpr,
557 tmpF.X * qpr, tmpF.Y * qpr, tmpF.Z * qpr);
558 printf("primsrc: %d, SumPot: %lg, SumFx: %lg, SumFy: %lg, SumFz: %lg\n",
559 primsrc, *Potential, localF.X, localF.Y, localF.Z);
560 }
561 } else {
562 // use discretized representation of a repeated primitive
563 Point3D localPER; // point element repeated
564 for (unsigned int ele = ElementBgn[primsrc]; ele <= ElementEnd[primsrc]; ++ele) {
565 double xsrc = (EleArr+ele-1)->G.Origin.X;
566 double ysrc = (EleArr+ele-1)->G.Origin.Y;
567 double zsrc = (EleArr+ele-1)->G.Origin.Z;
568
569 double XOfRpt = xsrc + XPeriod[primsrc] * (double)xrpt;
570 double YOfRpt = ysrc + YPeriod[primsrc] * (double)yrpt;
571 double ZOfRpt = zsrc + ZPeriod[primsrc] * (double)zrpt;
572
573 // Rotate from global to local system
574 double vG[3] = {xfld - XOfRpt, yfld - YOfRpt, zfld - ZOfRpt};
575 double vL[3] = {0., 0., 0.};
576 for (int i = 0; i < 3; ++i) {
577 for (int j = 0; j < 3; ++j) {
578 vL[i] += TransformationMatrix[i][j] * vG[j];
579 }
580 }
581 const int type = (EleArr + ele - 1)->G.Type;
582 const double a = (EleArr + ele - 1)->G.LX;
583 const double b = (EleArr + ele - 1)->G.LZ;
584 GetPF(type, a, b, vL[0], vL[1], vL[2], &tmpPot, &tmpF);
585 const double qel = (EleArr+ele-1)->Solution + (EleArr+ele-1)->Assigned;
586 *Potential += qel * tmpPot;
587 localF.X += qel * tmpF.X;
588 localF.Y += qel * tmpF.Y;
589 localF.Z += qel * tmpF.Z;
590 if (DebugLevel == 301) {
591 printf("primsrc: %d, ele: %d, xlocal: %lg, ylocal: %lg, zlocal: %lg\n",
592 primsrc, ele, vL[0], vL[1], vL[2]);
593 printf("primsrc: %d, Pot: %lg, Fx: %lg, Fy: %lg, Fz: %lg\n", primsrc
594 tmpPot * qel, tmpF.X * qel, tmpF.Y * qel, tmpF.Z * qel);
595 printf("primsrc: %d, SumPot: %lg, SumFx: %lg, SumFy: %lg, SumFz: %lg\n",
596 primsrc, *Potential, localF.X, localF.Y, localF.Z);
597 }
598 } // for all elements on this primitive
599 }
600 } // repetition of basic primitive
601 } // for zrpt
602 } // for yrpt
603 } // for xrpt
604 } // PeriodicInX || PeriodicInY || PeriodicInZ
605 } // PeriodicType == 1
606
607 tmpF = RotateVector3D(&localF, &PrimDC[primsrc], local2global);
608 globalF->X += tmpF.X;
609 globalF->Y += tmpF.Y;
610 globalF->Z += tmpF.Z;
611 } // for all primitives: basic device, mirror reflections and repetitions
612
613 (*Potential) /= MyFACTOR;
614 globalF->X /= MyFACTOR;
615 globalF->Y /= MyFACTOR;
616 globalF->Z /= MyFACTOR;
617
618 // ExactPointP and ExactPointF should also have an ExactPointPF
619 // Similarly for area and volume element related functions
620 // since there is no intermediate function that interfaces ExactPointP etc
621 // division by MyFACTOR is necessary
622 for (unsigned int point = 1; point <= NbPtsKnCh; ++point) {
623 tmpPot = ExactPointP(&(PtKnChArr+point-1)->P, globalP);
624 (*Potential) += (PtKnChArr+point-1)->Assigned * tmpPot / MyFACTOR;
625 ExactPointF(&(PtKnChArr+point-1)->P, globalP, &tmpF);
626 globalF->X += (PtKnChArr+point-1)->Assigned * tmpF.X / MyFACTOR;
627 globalF->Y += (PtKnChArr+point-1)->Assigned * tmpF.Y / MyFACTOR;
628 globalF->Z += (PtKnChArr+point-1)->Assigned * tmpF.Z / MyFACTOR;
629 }
630
631 for (unsigned int line = 1; line <= NbLinesKnCh; ++line) {
632 (*Potential) += 0.0;
633 globalF->X += 0.0;
634 globalF->Y += 0.0;
635 globalF->Z += 0.0;
636 }
637
638 for (unsigned int area = 1; area <= NbAreasKnCh; ++area) {
639 (*Potential) += 0.0;
640 globalF->X += 0.0;
641 globalF->Y += 0.0;
642 globalF->Z += 0.0;
643 }
644
645 for (unsigned int vol = 1; vol <= NbVolsKnCh; ++vol) {
646 (*Potential) += 0.0;
647 globalF->X += 0.0;
648 globalF->Y += 0.0;
649 globalF->Z += 0.0;
650 }
651
652 (*Potential) += VSystemChargeZero; // respect total system charge constraint
653 return(0);
654} // end of PFAtPoint
655// do not erase this redundant function.
656PFAtPoint borrowed from V1.8.15 ends here */
657
658// Gives three components of the total Potential and flux in the global
659// coordinate system due to all the interface elements and all known charges.
660// It may be interesting to inspect the relative influence of these two factors.
661int PFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF) {
662 double ElePot;
663 Vector3D EleglobalF;
664 int fstatus = ElePFAtPoint(globalP, &ElePot, &EleglobalF);
665 if (fstatus) {
666 printf(
667 "Problem in ElePFAtPoint being called from PFAtPoint ... returning\n");
668 return (-1);
669 }
670 *Potential = ElePot;
671 globalF->X = EleglobalF.X;
672 globalF->Y = EleglobalF.Y;
673 globalF->Z = EleglobalF.Z;
674
675 if (OptKnCh) {
676 double KnChPot;
677 Vector3D KnChglobalF;
678 fstatus = KnChPFAtPoint(globalP, &KnChPot, &KnChglobalF);
679 if (fstatus) {
680 printf(
681 "Problem in KnChPFAtPoint being called from PFAtPoint ... "
682 "returning\n");
683 return (-1);
684 }
685 *Potential += KnChPot;
686 globalF->X += KnChglobalF.X;
687 globalF->Y += KnChglobalF.Y;
688 globalF->Z += KnChglobalF.Z;
689 }
690
691 return 0;
692} // PFAtPoint ends
693
694// Gives three components of the total Potential and flux in the global
695// coordinate system only due to all the interface elements.
696// Multi-threading implemented in the following routine
697int ElePFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF) {
698 int dbgFn = 0;
699
700 const double xfld = globalP->X;
701 const double yfld = globalP->Y;
702 const double zfld = globalP->Z;
703
704 // Compute Potential and field at different locations
705 *Potential = globalF->X = globalF->Y = globalF->Z = 0.0;
706
707 // Effects due to base primitives and their repetitions are considered in the
708 // local coordinate system of the primitive (or element), while effects due to
709 // mirror elements and their repetitions are considered in the global
710 // coordinate system (GCS). This works because the direction cosines of a
711 // primitive (and its elements) and those of its repetitions are the same.
712 // As a result, we can do just one transformation from local to global at the
713 // end of calculations related to a primitive. This can save substantial
714 // computation if a discretized version of the primitive is being used since
715 // we avoid one unnecessary transformation for each element that comprises a
716 // primitive.
717 // Begin with primitive description of the device
718
719 // Scope in OpenMP: Variables in the global data space are accessible to all
720 // threads, while variables in a thread's private space is accessible to the
721 // thread only (there are several variations - copying outside region etc)
722 // Field point remains the same - kept outside private
723 // source point changes with change in primitive - private
724 // TransformationMatrix changes - kept within private (Note: matrices with
725 // fixed dimensions can be maintained, but those with dynamic allocation
726 // can not).
727 double *pPot = dvector(1, NbPrimitives);
728 // Field components in LCS for a primitive and its other incarnations.
729 double *plFx = dvector(1, NbPrimitives);
730 double *plFy = dvector(1, NbPrimitives);
731 double *plFz = dvector(1, NbPrimitives);
732
733 for (int prim = 1; prim <= NbPrimitives; ++prim) {
734 pPot[prim] = plFx[prim] = plFy[prim] = plFz[prim] = 0.0;
735 }
736
737#ifdef _OPENMP
738 int tid = 0, nthreads = 1;
739 #pragma omp parallel private(tid, nthreads)
740#endif
741 {
742
743#ifdef _OPENMP
744 if (dbgFn) {
745 tid = omp_get_thread_num();
746 if (tid == 0) {
747 nthreads = omp_get_num_threads();
748 printf("PFAtPoint computation with %d threads\n", nthreads);
749 }
750 }
751#endif
752// by default, nested parallelization is off in C
753#ifdef _OPENMP
754#pragma omp for
755#endif
756 for (int primsrc = 1; primsrc <= NbPrimitives; ++primsrc) {
757 if (dbgFn) {
758 printf("Evaluating effect of primsrc %d using on %lg, %lg, %lg\n",
759 primsrc, xfld, yfld, zfld);
760 fflush(stdout);
761 }
762
763 const double xpsrc = PrimOriginX[primsrc];
764 const double ypsrc = PrimOriginY[primsrc];
765 const double zpsrc = PrimOriginZ[primsrc];
766
767 // Field in the local frame.
768 double lFx = 0.;
769 double lFy = 0.;
770 double lFz = 0.;
771
772 // Set up transform matrix for this primitive, which is also the same
773 // for all the elements belonging to this primitive.
774 double TransformationMatrix[3][3];
775 TransformationMatrix[0][0] = PrimDC[primsrc].XUnit.X;
776 TransformationMatrix[0][1] = PrimDC[primsrc].XUnit.Y;
777 TransformationMatrix[0][2] = PrimDC[primsrc].XUnit.Z;
778 TransformationMatrix[1][0] = PrimDC[primsrc].YUnit.X;
779 TransformationMatrix[1][1] = PrimDC[primsrc].YUnit.Y;
780 TransformationMatrix[1][2] = PrimDC[primsrc].YUnit.Z;
781 TransformationMatrix[2][0] = PrimDC[primsrc].ZUnit.X;
782 TransformationMatrix[2][1] = PrimDC[primsrc].ZUnit.Y;
783 TransformationMatrix[2][2] = PrimDC[primsrc].ZUnit.Z;
784
785 // The total influence is due to primitives on the basic device and due to
786 // virtual primitives arising out of repetition, reflection etc and not
787 // residing on the basic device
788
789 // basic primitive
790
791 // Evaluate possibility whether primitive influence is accurate enough.
792 // This could be based on localPP and the subtended solid angle.
793 // If 1, then only primitive influence will be considered.
794 int PrimOK = 0;
795 if (PrimOK) {
796 // Only primitive influence will be considered
797 // Potential and flux (local system) due to base primitive
798 double tmpPot;
799 Vector3D tmpF;
800 // Rotate point from global to local system
801 double InitialVector[3] = {xfld - xpsrc, yfld - ypsrc, zfld - zpsrc};
802 double FinalVector[3] = {0., 0., 0.};
803 for (int i = 0; i < 3; ++i) {
804 for (int j = 0; j < 3; ++j) {
805 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
806 }
807 }
808 Point3D localPP;
809 localPP.X = FinalVector[0];
810 localPP.Y = FinalVector[1];
811 localPP.Z = FinalVector[2];
812 GetPrimPF(primsrc, &localPP, &tmpPot, &tmpF);
813 const double qpr = AvChDen[primsrc] + AvAsgndChDen[primsrc];
814 pPot[primsrc] += qpr * tmpPot;
815 lFx += qpr * tmpF.X;
816 lFy += qpr * tmpF.Y;
817 lFz += qpr * tmpF.Z;
818 // if(DebugLevel == 301)
819 if (dbgFn) {
820 printf("PFAtPoint base primitive =>\n");
821 printf("primsrc: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n",
822 primsrc, localPP.X, localPP.Y, localPP.Z);
823 printf("primsrc: %d, Pot: %lg, Fx: %lg, Fx: %lg, Fz: %lg\n",
824 primsrc, tmpPot, tmpF.X, tmpF.Y, tmpF.Z);
825 printf("primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: %lg\n",
826 primsrc, pPot[primsrc], lFx, lFy, lFz);
827 fflush(stdout);
828 // exit(-1);
829 }
830 } else {
831 // Need to consider element influence.
832 double tPot;
833 Vector3D tF;
834 double ePot = 0.;
835 Vector3D eF;
836 eF.X = 0.0;
837 eF.Y = 0.0;
838 eF.Z = 0.0;
839 const int eleMin = ElementBgn[primsrc];
840 const int eleMax = ElementEnd[primsrc];
841 for (int ele = eleMin; ele <= eleMax; ++ele) {
842 const double xsrc = (EleArr + ele - 1)->G.Origin.X;
843 const double ysrc = (EleArr + ele - 1)->G.Origin.Y;
844 const double zsrc = (EleArr + ele - 1)->G.Origin.Z;
845 // Rotate from global to local system; matrix as for primitive
846 double vG[3] = {xfld - xsrc, yfld - ysrc, zfld - zsrc};
847 double vL[3] = {0., 0., 0.};
848 for (int i = 0; i < 3; ++i) {
849 for (int j = 0; j < 3; ++j) {
850 vL[i] += TransformationMatrix[i][j] * vG[j];
851 }
852 }
853 // Potential and flux (local system) due to base primitive
854 const int type = (EleArr + ele - 1)->G.Type;
855 const double a = (EleArr + ele - 1)->G.LX;
856 const double b = (EleArr + ele - 1)->G.LZ;
857 GetPF(type, a, b, vL[0], vL[1], vL[2], &tPot, &tF);
858 const double qel = (EleArr + ele - 1)->Solution + (EleArr + ele - 1)->Assigned;
859 ePot += qel * tPot;
860 eF.X += qel * tF.X;
861 eF.Y += qel * tF.Y;
862 eF.Z += qel * tF.Z;
863 // if(DebugLevel == 301)
864 if (dbgFn) {
865 printf("PFAtPoint base primitive:%d\n", primsrc);
866 printf("ele: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n", ele,
867 vL[0], vL[1], vL[2]);
868 printf(
869 "ele: %d, tPot: %lg, tFx: %lg, tFy: %lg, tFz: %lg, Solution: "
870 "%g\n",
871 ele, tPot, tF.X, tF.Y, tF.Z, qel);
872 printf("ele: %d, ePot: %lg, eFx: %lg, eFy: %lg, eFz: %lg\n", ele,
873 ePot, eF.X, eF.Y, eF.Z);
874 fflush(stdout);
875 }
876 } // for all the elements on this primsrc primitive
877
878 pPot[primsrc] += ePot;
879 lFx += eF.X;
880 lFy += eF.Y;
881 lFz += eF.Z;
882 if (dbgFn) {
883 printf(
884 "prim%d, ePot: %lg, eFx: %lg, eFy: %lg, eFz: %lg\n",
885 primsrc, ePot, eF.X, eF.Y, eF.Z);
886 printf("prim%d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: %lg\n", primsrc,
887 pPot[primsrc], lFx, lFy, lFz);
888 fflush(stdout);
889 }
890 } // else elements influence
891
892 // if(DebugLevel == 301)
893 if (dbgFn) {
894 printf("basic primitive\n");
895 printf("primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: %lg\n",
896 primsrc, pPot[primsrc], lFx, lFy, lFz);
897 fflush(stdout);
898 }
899
900 if (MirrorTypeX[primsrc] || MirrorTypeY[primsrc] ||
901 MirrorTypeZ[primsrc]) { // Mirror effect of base primitives
902 printf("Mirror may not be correctly implemented ...\n");
903 exit(0);
904 } // Mirror effect ends
905
906 // Flux due to repeated primitives
907 if ((PeriodicTypeX[primsrc] == 1) || (PeriodicTypeY[primsrc] == 1) ||
908 (PeriodicTypeZ[primsrc] == 1)) {
909 const int perx = PeriodicInX[primsrc];
910 const int pery = PeriodicInY[primsrc];
911 const int perz = PeriodicInZ[primsrc];
912 if (perx || pery || perz) {
913 for (int xrpt = -perx; xrpt <= perx; ++xrpt) {
914 const double xShift = XPeriod[primsrc] * (double)xrpt;
915 const double XPOfRpt = xpsrc + xShift;
916 for (int yrpt = -pery; yrpt <= pery; ++yrpt) {
917 const double yShift = YPeriod[primsrc] * (double)yrpt;
918 const double YPOfRpt = ypsrc + yShift;
919 for (int zrpt = -perz; zrpt <= perz; ++zrpt) {
920 const double zShift = ZPeriod[primsrc] * (double)zrpt;
921 const double ZPOfRpt = zpsrc + zShift;
922 // Skip the basic primitive.
923 if ((xrpt == 0) && (yrpt == 0) && (zrpt == 0)) continue;
924
925 // Basic primitive repeated
926 int repPrimOK = 0;
927 // consider primitive representation accurate enough if it is
928 // repeated and beyond PrimAfter repetitions.
929 if (PrimAfter == 0) {
930 // If PrimAfter is zero, PrimOK is always zero
931 repPrimOK = 0;
932 } else if ((abs(xrpt) > PrimAfter) && (abs(yrpt) > PrimAfter)) {
933 repPrimOK = 1;
934 }
935 if (repPrimOK) {
936 // Use primitive representation
937 // Rotate point from global to local system
938 double InitialVector[3] = {xfld - XPOfRpt, yfld - YPOfRpt, zfld - ZPOfRpt};
939 double FinalVector[3] = {0., 0., 0.};
940 for (int i = 0; i < 3; ++i) {
941 for (int j = 0; j < 3; ++j) {
942 FinalVector[i] +=
943 TransformationMatrix[i][j] * InitialVector[j];
944 }
945 }
946 Point3D localPPR;
947 localPPR.X = FinalVector[0];
948 localPPR.Y = FinalVector[1];
949 localPPR.Z = FinalVector[2];
950 // Potential and flux (local system) due to repeated
951 // primitive
952 double tmpPot;
953 Vector3D tmpF;
954 GetPrimPF(primsrc, &localPPR, &tmpPot, &tmpF);
955 const double qpr = AvChDen[primsrc] + AvAsgndChDen[primsrc];
956 pPot[primsrc] += qpr * tmpPot;
957 lFx += qpr * tmpF.X;
958 lFy += qpr * tmpF.Y;
959 lFz += qpr * tmpF.Z;
960 // if(DebugLevel == 301)
961 if (dbgFn) {
962 printf(
963 "primsrc: %d, xlocal: %lg, ylocal: %lg, zlocal: "
964 "%lg\n",
965 primsrc, localPPR.X, localPPR.Y, localPPR.Z);
966 printf(
967 "primsrc: %d, Pot: %lg, Fx: %lg, Fy: %lg, Fz: %lg\n",
968 primsrc, tmpPot * qpr, tmpF.X * qpr, tmpF.Y * qpr,
969 tmpF.Z * qpr);
970 printf(
971 "primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: "
972 "%lg\n",
973 primsrc, pPot[primsrc], lFx, lFy, lFz);
974 fflush(stdout);
975 }
976 } else {
977 // Use discretized representation of a repeated primitive
978 double tPot;
979 Vector3D tF;
980 double erPot = 0.0;
981 Vector3D erF;
982 erF.X = 0.0;
983 erF.Y = 0.0;
984 erF.Z = 0.0;
985 const int eleMin = ElementBgn[primsrc];
986 const int eleMax = ElementEnd[primsrc];
987 for (int ele = eleMin; ele <= eleMax; ++ele) {
988 const double xrsrc = (EleArr + ele - 1)->G.Origin.X;
989 const double yrsrc = (EleArr + ele - 1)->G.Origin.Y;
990 const double zrsrc = (EleArr + ele - 1)->G.Origin.Z;
991
992 const double XEOfRpt = xrsrc + xShift;
993 const double YEOfRpt = yrsrc + yShift;
994 const double ZEOfRpt = zrsrc + zShift;
995 // Rotate from global to local system
996 double vG[3] = {xfld - XEOfRpt, yfld - YEOfRpt, zfld - ZEOfRpt};
997 double vL[3] = {0., 0., 0.};
998 for (int i = 0; i < 3; ++i) {
999 for (int j = 0; j < 3; ++j) {
1000 vL[i] += TransformationMatrix[i][j] * vG[j];
1001 }
1002 }
1003 // Allowed, because all the local coordinates have the
1004 // same orientations. Only the origins are mutually
1005 // displaced along a line.
1006 const int type = (EleArr + ele - 1)->G.Type;
1007 const double a = (EleArr + ele - 1)->G.LX;
1008 const double b = (EleArr + ele - 1)->G.LZ;
1009 GetPF(type, a, b, vL[0], vL[1], vL[2], &tPot, &tF);
1010 const double qel = (EleArr + ele - 1)->Solution + (EleArr + ele - 1)->Assigned;
1011 erPot += qel * tPot;
1012 erF.X += qel * tF.X;
1013 erF.Y += qel * tF.Y;
1014 erF.Z += qel * tF.Z;
1015 // if(DebugLevel == 301)
1016 if (dbgFn) {
1017 printf("PFAtPoint base primitive:%d\n", primsrc);
1018 printf("ele: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n",
1019 ele, vL[0], vL[1], vL[2]);
1020 printf(
1021 "ele: %d, tPot: %lg, tFx: %lg, tFy: %lg, tFz: %lg, "
1022 "Solution: %g\n",
1023 ele, tPot, tF.X, tF.Y, tF.Z, qel);
1024 printf(
1025 "ele: %d, ePot: %lg, eFx: %lg, eFy: %lg, eFz: %lg\n",
1026 ele, erPot, erF.X, erF.Y, erF.Z);
1027 fflush(stdout);
1028 }
1029 } // for all the elements on this primsrc repeated
1030 // primitive
1031
1032 pPot[primsrc] += erPot;
1033 lFx += erF.X;
1034 lFy += erF.Y;
1035 lFz += erF.Z;
1036 } // else discretized representation of this primitive
1037
1038 // if(DebugLevel == 301)
1039 if (dbgFn) {
1040 printf("basic repeated xrpt: %d. yrpt: %d, zrpt: %d\n",
1041 xrpt, yrpt, zrpt);
1042 printf(
1043 "primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: %lg\n",
1044 primsrc, pPot[primsrc], lFx, lFy, lFz);
1045 fflush(stdout);
1046 }
1047
1048 if (MirrorTypeX[primsrc] || MirrorTypeY[primsrc] ||
1049 MirrorTypeZ[primsrc]) { // Mirror effect of repeated
1050 // primitives - not parallelized
1051 printf(
1052 "Mirror not correctly implemented in this version of "
1053 "neBEM ...\n");
1054 exit(0);
1055
1056 double tmpPot;
1057 Vector3D tmpF;
1058 Point3D srcptp;
1059 Point3D localPPRM; // point primitive repeated mirrored
1060 DirnCosn3D DirCos;
1061
1062 srcptp.X = XPOfRpt;
1063 srcptp.Y = YPOfRpt;
1064 srcptp.Z = ZPOfRpt;
1065
1066 Point3D fldpt;
1067 fldpt.X = xfld;
1068 fldpt.Y = yfld;
1069 fldpt.Z = zfld;
1070 if (MirrorTypeX[primsrc]) {
1071 MirrorTypeY[primsrc] = 0;
1072 MirrorTypeZ[primsrc] = 0;
1073 }
1074 if (MirrorTypeY[primsrc]) MirrorTypeZ[primsrc] = 0;
1075
1076 if (MirrorTypeX[primsrc]) {
1077 localPPRM = ReflectPrimitiveOnMirror(
1078 'X', primsrc, srcptp, fldpt,
1079 MirrorDistXFromOrigin[primsrc], &DirCos);
1080
1081 // check whether primitive description is good enough
1082 int mirrPrimOK = 0;
1083 if (mirrPrimOK) {
1084 GetPrimPFGCS(primsrc, &localPPRM, &tmpPot, &tmpF,
1085 &DirCos);
1086 const double qpr = AvChDen[primsrc] + AvAsgndChDen[primsrc];
1087 if (MirrorTypeX[primsrc] == 1) {
1088 // opposite charge density
1089 pPot[primsrc] -= qpr * tmpPot;
1090 lFx -= qpr * tmpF.X;
1091 lFy -= qpr * tmpF.Y;
1092 lFz -= qpr * tmpF.Z;
1093 } else if (MirrorTypeX[primsrc] == 2) {
1094 // same charge density
1095 pPot[primsrc] += qpr * tmpPot;
1096 lFx += qpr * tmpF.X;
1097 lFy += qpr * tmpF.Y;
1098 lFz += qpr * tmpF.Z;
1099 }
1100 } else { // consider element representation
1101 Point3D localPERM; // point element repeated mirrored
1102 Point3D srcpte;
1103
1104 const int eleMin = ElementBgn[primsrc];
1105 const int eleMax = ElementEnd[primsrc];
1106 for (int ele = eleMin; ele <= eleMax; ++ele) {
1107 const double xsrc = (EleArr + ele - 1)->G.Origin.X;
1108 const double ysrc = (EleArr + ele - 1)->G.Origin.Y;
1109 const double zsrc = (EleArr + ele - 1)->G.Origin.Z;
1110
1111 const double XEOfRpt = xsrc + xShift;
1112 const double YEOfRpt = ysrc + yShift;
1113 const double ZEOfRpt = zsrc + zShift;
1114
1115 srcpte.X = XEOfRpt;
1116 srcpte.Y = YEOfRpt;
1117 srcpte.Z = ZEOfRpt;
1118
1119 localPERM = ReflectOnMirror(
1120 'X', ele, srcpte, fldpt,
1121 MirrorDistXFromOrigin[primsrc], &DirCos);
1122 const int type = (EleArr + ele - 1)->G.Type;
1123 const double a = (EleArr + ele - 1)->G.LX;
1124 const double b = (EleArr + ele - 1)->G.LZ;
1125 GetPFGCS(type, a, b, &localPERM, &tmpPot, &tmpF, &DirCos); // force?
1126 const double qel = (EleArr + ele - 1)->Solution + (EleArr + ele - 1)->Assigned;
1127 if (MirrorTypeX[primsrc] == 1) {
1128 // opposite charge density
1129 pPot[primsrc] -= qel * tmpPot;
1130 lFx -= qel * tmpF.X;
1131 lFy -= qel * tmpF.Y;
1132 lFz -= qel * tmpF.Z;
1133 } else if (MirrorTypeX[primsrc] == 2) {
1134 // same charge density
1135 pPot[primsrc] += qel * tmpPot;
1136 lFx += qel * tmpF.X;
1137 lFy += qel * tmpF.Y;
1138 lFz += qel * tmpF.Z;
1139 }
1140 } // loop for all elements on the primsrc primitive
1141 } // else element representation
1142 } // MirrorTypeX
1143
1144 if (MirrorTypeY[primsrc]) {
1145 localPPRM = ReflectOnMirror('Y', primsrc, srcptp, fldpt,
1146 MirrorDistYFromOrigin[primsrc],
1147 &DirCos);
1148
1149 // check whether primitive description is good enough
1150 int mirrPrimOK = 0;
1151 if (mirrPrimOK) {
1152 GetPrimPFGCS(primsrc, &localPPRM, &tmpPot, &tmpF,
1153 &DirCos);
1154 const double qpr = AvChDen[primsrc] + AvAsgndChDen[primsrc];
1155 if (MirrorTypeY[primsrc] == 1) {
1156 // opposite charge density
1157 pPot[primsrc] -= qpr * tmpPot;
1158 lFx -= qpr * tmpF.X;
1159 lFy -= qpr * tmpF.Y;
1160 lFz -= qpr * tmpF.Z;
1161 } else if (MirrorTypeY[primsrc] == 2) {
1162 // same charge density
1163 pPot[primsrc] += qpr * tmpPot;
1164 lFx += qpr * tmpF.X;
1165 lFy += qpr * tmpF.Y;
1166 lFz += qpr * tmpF.Z;
1167 }
1168 } else { // consider element representation
1169 Point3D localPERM;
1170 Point3D srcpte;
1171
1172 const int eleMin = ElementBgn[primsrc];
1173 const int eleMax = ElementEnd[primsrc];
1174 for (int ele = eleMin; ele <= eleMax; ++ele) {
1175 const double xsrc = (EleArr + ele - 1)->G.Origin.X;
1176 const double ysrc = (EleArr + ele - 1)->G.Origin.Y;
1177 const double zsrc = (EleArr + ele - 1)->G.Origin.Z;
1178
1179 const double XEOfRpt = xsrc + xShift;
1180 const double YEOfRpt = ysrc + yShift;
1181 const double ZEOfRpt = zsrc + zShift;
1182
1183 srcpte.X = XEOfRpt;
1184 srcpte.Y = YEOfRpt;
1185 srcpte.Z = ZEOfRpt;
1186
1187 localPERM = ReflectOnMirror(
1188 'Y', ele, srcpte, fldpt,
1189 MirrorDistYFromOrigin[primsrc], &DirCos);
1190 const int type = (EleArr + ele - 1)->G.Type;
1191 const double a = (EleArr + ele - 1)->G.LX;
1192 const double b = (EleArr + ele - 1)->G.LZ;
1193 GetPFGCS(type, a, b, &localPERM, &tmpPot, &tmpF, &DirCos);
1194 const double qel = (EleArr + ele - 1)->Solution + (EleArr + ele - 1)->Assigned;
1195 if (MirrorTypeY[primsrc] == 1) {
1196 // opposite charge density
1197 pPot[primsrc] -= qel * tmpPot;
1198 lFx -= qel * tmpF.X;
1199 lFy -= qel * tmpF.Y;
1200 lFz -= qel * tmpF.Z;
1201 } else if (MirrorTypeY[primsrc] == 2) {
1202 // same charge density
1203 pPot[primsrc] += qel * tmpPot;
1204 lFx += qel * tmpF.X;
1205 lFy += qel * tmpF.Y;
1206 lFz += qel * tmpF.Z;
1207 }
1208 } // loop for all elements on the primsrc primitive
1209 } // else element representations
1210 } // MirrorTypeY
1211
1212 if (MirrorTypeZ[primsrc]) {
1213 localPPRM = ReflectOnMirror('Z', primsrc, srcptp, fldpt,
1214 MirrorDistZFromOrigin[primsrc],
1215 &DirCos);
1216
1217 // check whether primitive description is good enough
1218 int mirrPrimOK = 0;
1219 if (mirrPrimOK) {
1220 GetPrimPFGCS(primsrc, &localPPRM, &tmpPot, &tmpF,
1221 &DirCos);
1222 const double qpr = AvChDen[primsrc] + AvAsgndChDen[primsrc];
1223 if (MirrorTypeZ[primsrc] == 1) {
1224 // opposite charge density
1225 pPot[primsrc] -= qpr * tmpPot;
1226 lFx -= qpr * tmpF.X;
1227 lFy -= qpr * tmpF.Y;
1228 lFz -= qpr * tmpF.Z;
1229 } else if (MirrorTypeZ[primsrc] == 2) {
1230 // same charge density
1231 pPot[primsrc] += qpr * tmpPot;
1232 lFx += qpr * tmpF.X;
1233 lFy += qpr * tmpF.Y;
1234 lFz += qpr * tmpF.Z;
1235 }
1236 } else {
1237 // elements to be considered
1238 Point3D localPERM;
1239 Point3D srcpte;
1240
1241 const int eleMin = ElementBgn[primsrc];
1242 const int eleMax = ElementEnd[primsrc];
1243 for (int ele = eleMin; ele <= eleMax; ++ele) {
1244 const double xsrc = (EleArr + ele - 1)->G.Origin.X;
1245 const double ysrc = (EleArr + ele - 1)->G.Origin.Y;
1246 const double zsrc = (EleArr + ele - 1)->G.Origin.Z;
1247
1248 const double XEOfRpt = xsrc + xShift;
1249 const double YEOfRpt = ysrc + yShift;
1250 const double ZEOfRpt = zsrc + zShift;
1251
1252 srcpte.X = XEOfRpt;
1253 srcpte.Y = YEOfRpt;
1254 srcpte.Z = ZEOfRpt;
1255
1256 localPERM = ReflectOnMirror(
1257 'Z', ele, srcpte, fldpt,
1258 MirrorDistZFromOrigin[primsrc], &DirCos);
1259 const int type = (EleArr + ele - 1)->G.Type;
1260 const double a = (EleArr + ele - 1)->G.LX;
1261 const double b = (EleArr + ele - 1)->G.LZ;
1262 GetPFGCS(type, a, b, &localPERM, &tmpPot, &tmpF, &DirCos);
1263 const double qel = (EleArr + ele - 1)->Solution + (EleArr + ele - 1)->Assigned;
1264 if (MirrorTypeZ[primsrc] == 1) {
1265 // opposite charge density
1266 pPot[primsrc] -= qel * tmpPot;
1267 lFx -= qel * tmpF.X;
1268 lFy -= qel * tmpF.Y;
1269 lFz -= qel * tmpF.Z;
1270 } else if (MirrorTypeZ[primsrc] == 2) {
1271 // same charge density
1272 pPot[primsrc] += qel * tmpPot;
1273 lFx += qel * tmpF.X;
1274 lFy += qel * tmpF.Y;
1275 lFz += qel * tmpF.Z;
1276 }
1277 } // loop for all elements on the primsrc primitive
1278 } // else consider element representation
1279 } // MirrorTypeZ
1280 } // Mirror effect for repeated primitives ends
1281
1282 } // for zrpt
1283 } // for yrpt
1284 } // for xrpt
1285 } // PeriodicInX || PeriodicInY || PeriodicInZ
1286 } // PeriodicType == 1
1287 Vector3D localF;
1288 localF.X = lFx;
1289 localF.Y = lFy;
1290 localF.Z = lFz;
1291 Vector3D tmpF = RotateVector3D(&localF, &PrimDC[primsrc], local2global);
1292 plFx[primsrc] = tmpF.X;
1293 plFy[primsrc] = tmpF.Y;
1294 plFz[primsrc] = tmpF.Z;
1295 } // for all primitives: basic device, mirror reflections and repetitions
1296 } // pragma omp parallel
1297
1298 double totPot = 0.0;
1299 Vector3D totF;
1300 totF.X = totF.Y = totF.Z = 0.0;
1301 for (int prim = 1; prim <= NbPrimitives; ++prim) {
1302 totPot += pPot[prim];
1303 totF.X += plFx[prim];
1304 totF.Y += plFy[prim];
1305 totF.Z += plFz[prim];
1306 }
1307
1308 // This is done at the end of the function - before freeing memory
1309#ifdef __cplusplus
1310 *Potential = totPot * InvFourPiEps0;
1311 globalF->X = totF.X * InvFourPiEps0;
1312 globalF->Y = totF.Y * InvFourPiEps0;
1313 globalF->Z = totF.Z * InvFourPiEps0;
1314#else
1315 *Potential = totPot / MyFACTOR;
1316 globalF->X = totF.X / MyFACTOR;
1317 globalF->Y = totF.Y / MyFACTOR;
1318 globalF->Z = totF.Z / MyFACTOR;
1319#endif
1320 (*Potential) += VSystemChargeZero; // respect total system charge constraint
1321
1322 if (dbgFn) {
1323 printf("Final values due to all primitives: ");
1324 // printf("xfld\tyfld\tzfld\tPot\tFx\tFy\tFz\n"); // refer, do not
1325 // uncomment
1326 printf("%lg\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n\n", xfld, yfld, zfld,
1327 (*Potential), globalF->X, globalF->Y, globalF->Z);
1328 fflush(stdout);
1329 }
1330
1331 free_dvector(pPot, 1, NbPrimitives);
1332 free_dvector(plFx, 1, NbPrimitives);
1333 free_dvector(plFy, 1, NbPrimitives);
1334 free_dvector(plFz, 1, NbPrimitives);
1335
1336 return (0);
1337} // end of ElePFAtPoint
1338
1339// Evaluate effects due to known charge distributions
1340// Since there is no intermediate function that interfaces PointKnChPF etc,
1341// division by MyFACTOR is necessary.
1342// CHECK OpenMP / GPU possibilities:
1343// Do parallelize before using these known charges - points or distributions
1344int KnChPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF) {
1345 int dbgFn = 0;
1346 double tmpPot;
1347 Point3D tmpPt;
1348 tmpPt.X = globalP->X;
1349 tmpPt.Y = globalP->Y;
1350 tmpPt.Z = globalP->Z;
1351 Vector3D tmpF;
1352
1353 for (int point = 1; point <= NbPointsKnCh; ++point) {
1354 tmpPot = PointKnChPF((PointKnChArr + point - 1)->P, tmpPt, &tmpF);
1355 (*Potential) += (PointKnChArr + point - 1)->Assigned * tmpPot / MyFACTOR;
1356 globalF->X += (PointKnChArr + point - 1)->Assigned * tmpF.X / MyFACTOR;
1357 globalF->Y += (PointKnChArr + point - 1)->Assigned * tmpF.Y / MyFACTOR;
1358 globalF->Z += (PointKnChArr + point - 1)->Assigned * tmpF.Z / MyFACTOR;
1359 }
1360
1361 for (int line = 1; line <= NbLinesKnCh; ++line) {
1362 tmpPot = LineKnChPF((LineKnChArr + line - 1)->Start,
1363 (LineKnChArr + line - 1)->Stop,
1364 (LineKnChArr + line - 1)->Radius, tmpPt, &tmpF);
1365 (*Potential) += (LineKnChArr + line - 1)->Assigned * tmpPot / MyFACTOR;
1366 globalF->X += (LineKnChArr + line - 1)->Assigned * tmpF.X / MyFACTOR;
1367 globalF->Y += (LineKnChArr + line - 1)->Assigned * tmpF.Y / MyFACTOR;
1368 globalF->Z += (LineKnChArr + line - 1)->Assigned * tmpF.Z / MyFACTOR;
1369 }
1370
1371 for (int area = 1; area <= NbAreasKnCh; ++area) {
1372 tmpPot = AreaKnChPF((AreaKnChArr + area - 1)->NbVertices,
1373 ((AreaKnChArr + area - 1)->Vertex), tmpPt, &tmpF);
1374 (*Potential) += (AreaKnChArr + area - 1)->Assigned * tmpPot / MyFACTOR;
1375 globalF->X += (AreaKnChArr + area - 1)->Assigned * tmpF.X / MyFACTOR;
1376 globalF->Y += (AreaKnChArr + area - 1)->Assigned * tmpF.Y / MyFACTOR;
1377 globalF->Z += (AreaKnChArr + area - 1)->Assigned * tmpF.Z / MyFACTOR;
1378 }
1379
1380 for (int vol = 1; vol <= NbVolumesKnCh; ++vol) {
1381 tmpPot = VolumeKnChPF((VolumeKnChArr + vol - 1)->NbVertices,
1382 ((VolumeKnChArr + vol - 1)->Vertex), tmpPt, &tmpF);
1383 (*Potential) += (VolumeKnChArr + vol - 1)->Assigned * tmpPot / MyFACTOR;
1384 globalF->X += (VolumeKnChArr + vol - 1)->Assigned * tmpF.X / MyFACTOR;
1385 globalF->Y += (VolumeKnChArr + vol - 1)->Assigned * tmpF.Y / MyFACTOR;
1386 globalF->Z += (VolumeKnChArr + vol - 1)->Assigned * tmpF.Z / MyFACTOR;
1387 }
1388
1389 if (dbgFn) {
1390 printf("Final values due to all known charges: ");
1391 // printf("xfld\tyfld\tzfld\tPot\tFx\tFy\tFz\n"); // refer, do not
1392 // uncomment
1393 printf("%lg\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n\n", tmpPt.X, tmpPt.Y, tmpPt.Z,
1394 (*Potential), globalF->X, globalF->Y, globalF->Z);
1395 fflush(stdout);
1396 }
1397
1398 return 0;
1399} // KnChPFAtPoint ends
1400
1401// Compute voxelized data for export to Garfield++
1402int VoxelFPR(void) {
1403 int dbgFn = 0;
1404 int fstatus;
1405
1406 int nbXCells;
1407 int nbYCells;
1408 int nbZCells;
1409 double startX;
1410 double startY;
1411 double startZ;
1412 double delX;
1413 double delY;
1414 double delZ;
1415
1416 printf("\nPotential and field computation for voxelized data export\n");
1417
1418 char VoxelFile[256];
1419 FILE *fVoxel;
1420 strcpy(VoxelFile, BCOutDir);
1421 strcat(VoxelFile, "/VoxelFPR.out");
1422 fVoxel = fopen(VoxelFile, "w");
1423 if (fVoxel == NULL) {
1424 neBEMMessage("VoxelFPR - VoxelFile");
1425 return -1;
1426 }
1427 fprintf(
1428 fVoxel,
1429 "# X(cm)\tY(cm)\tZ(cm)\tFX(V/cm)\tFY(V/cm)\tFZ(V/cm)\tPot(V)\tRegion\n");
1430
1431 if (dbgFn) {
1432 printf("VoxelFPR.out created ...\n");
1433 fflush(stdout);
1434 }
1435
1436 nbXCells = Voxel.NbXCells;
1437 nbYCells = Voxel.NbYCells;
1438 nbZCells = Voxel.NbZCells;
1439 startX = Voxel.Xmin;
1440 startY = Voxel.Ymin;
1441 startZ = Voxel.Zmin;
1442 delX = (Voxel.Xmax - Voxel.Xmin) / nbXCells;
1443 delY = (Voxel.Ymax - Voxel.Ymin) / nbYCells;
1444 delZ = (Voxel.Zmax - Voxel.Zmin) / nbZCells;
1445
1446 int ivol; // relates XYZ position to volume number
1447 double *VoxelFX, *VoxelFY, *VoxelFZ, *VoxelP;
1448 VoxelFX = dvector(0, nbZCells + 1);
1449 VoxelFY = dvector(0, nbZCells + 1);
1450 VoxelFZ = dvector(0, nbZCells + 1);
1451 VoxelP = dvector(0, nbZCells + 1);
1452
1453 if (dbgFn) {
1454 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
1455 nbZCells);
1456 printf("startX, startY, startZ: %le, %le, %le\n", startX, startY, startZ);
1457 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
1458 fflush(stdout);
1459 }
1460
1461 for (int i = 1; i <= nbXCells + 1; ++i) {
1462 for (int j = 1; j <= nbYCells + 1; ++j) {
1463 if (dbgFn) {
1464 printf("VoxelFPR => i: %4d, j: %4d", i, j);
1465 fflush(stdout);
1466 }
1467
1468 Point3D point;
1469#ifdef _OPENMP
1470 int nthreads = 1, tid = 0;
1471 #pragma omp parallel private(nthreads, tid)
1472#endif
1473 {
1474#ifdef _OPENMP
1475 if (dbgFn) {
1476 tid = omp_get_thread_num();
1477 if (tid == 0) {
1478 nthreads = omp_get_num_threads();
1479 printf("Starting voxel computation with %d threads\n", nthreads);
1480 }
1481 }
1482#endif
1483 int k;
1484 Vector3D field;
1485 double potential;
1486#ifdef _OPENMP
1487 #pragma omp for private(k, point, potential, field)
1488#endif
1489 for (k = 1; k <= nbZCells + 1; ++k) {
1490 potential = 0.0;
1491 field.X = field.Y = field.Z = 0.0;
1492
1493 point.X = startX + (i - 1) * delX; // all 3 components need to be
1494 point.Y = startY + (j - 1) * delY; // evaluated after pragma omp
1495 point.Z = startZ + (k - 1) * delZ;
1496
1497 if (dbgFn) {
1498 printf("i, j, k: %d, %d, %d\n", i, j, k);
1499 printf("point X, Y, Z: %.8lg\t%.8lg\t%.8lg\n",
1500 point.X / LengthScale, point.Y / LengthScale,
1501 point.Z / LengthScale);
1502 fflush(stdout);
1503 }
1504
1505 fstatus = PFAtPoint(&point, &potential, &field);
1506 if (fstatus != 0) {
1507 neBEMMessage("wrong PFAtPoint return value in VoxelFPR\n");
1508 // return -1;
1509 }
1510
1511 if (dbgFn) {
1512 printf("%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
1513 point.X / LengthScale, point.Y / LengthScale,
1514 point.Z / LengthScale, field.X, field.Y, field.Z,
1515 potential / LengthScale);
1516 fflush(stdout);
1517 }
1518
1519 VoxelFX[k] = field.X;
1520 VoxelFY[k] = field.Y;
1521 VoxelFZ[k] = field.Z;
1522 VoxelP[k] = potential;
1523 } // loop k
1524 } // pragma omp parallel
1525
1526 for (int k = 1; k <= nbZCells + 1; ++k) // file output
1527 {
1528 point.X = startX + (i - 1) * delX;
1529 point.Y = startY + (j - 1) * delY;
1530 point.Z = startZ + (k - 1) * delZ;
1531
1532 ivol = neBEMVolumePoint(point.X, point.Y, point.Z);
1533 /*
1534 volMaterial[ivol]; // region linked to material
1535 neBEMVolumeDescription(ivol, &vshp, &vmat, &veps, &vpot, &vq, &vtype);
1536if(dbgFn)
1537{
1538printf("volref: %d\n", ivol);
1539printf("shape: %d, material: %d\n", volShape[ivol], volMaterial[ivol]);
1540printf("eps: %d, pot: %d\n", volEpsilon[ivol], volPotential[ivol]);
1541printf("q: %d, type: %d\n", volCharge[ivol], volBoundaryType[ivol]);
1542printf("shape: %d, material: %d\n", vshp, vmat);
1543printf("eps: %d, pot: %d\n", veps, vpot);
1544printf("q: %d, type: %d\n", vq, vtype);
1545}
1546 */
1547
1548 fprintf(fVoxel,
1549 "%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%4d\n",
1550 100.0 * point.X / LengthScale, 100.0 * point.Y / LengthScale,
1551 100.0 * point.Z / LengthScale, VoxelFX[k] / 100.0,
1552 VoxelFY[k] / 100.0, VoxelFZ[k] / 100.0, VoxelP[k] / LengthScale,
1553 ivol + 1);
1554 }
1555 fflush(fVoxel); // file output over
1556
1557 // printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
1558 } // loop j
1559 } // loop i
1560
1561 fclose(fVoxel);
1562
1563 free_dvector(VoxelFX, 0, nbZCells + 1);
1564 free_dvector(VoxelFY, 0, nbZCells + 1);
1565 free_dvector(VoxelFZ, 0, nbZCells + 1);
1566 free_dvector(VoxelP, 0, nbZCells + 1);
1567
1568 return 0;
1569} // end of VoxelFPR
1570
1571// Compute 3dMap data for export to Garfield++.
1572// The 3dMap data for weighting field can be generated using the same function.
1573// After creation, the exported file has to be properly
1574// named and then imported by ComponentNeBem3dMap.
1575int MapFPR(void) {
1576 int dbgFn = 0;
1577
1578 printf("\nPotential and field computation for 3dMap data export\n");
1579
1580 char MapInfoFile[256];
1581 strcpy(MapInfoFile, BCOutDir);
1582 strcat(MapInfoFile, "/MapInfo.out");
1583 FILE *fMapInfo = fopen(MapInfoFile, "w");
1584 if (fMapInfo == NULL) {
1585 neBEMMessage("MapFPR - MapInfoFile");
1586 return -1;
1587 }
1588 if (dbgFn) {
1589 printf("MapInfoFile.out created ...\n");
1590 fflush(stdout);
1591 }
1592
1593 // In certain versions, we may have only the version number in the header and
1594 // nothing more. In that case, it is unsafe to assume that OptMap or
1595 // OptStaggerMap will be at all present in the output file. This decision
1596 // may need to be taken immediately after reading the MapVersion value.
1597 fprintf(fMapInfo, "%s\n", MapVersion);
1598 fprintf(fMapInfo, "%d\n", OptMap);
1599 fprintf(fMapInfo, "%d\n", OptStaggerMap);
1600 fprintf(fMapInfo, "%d\n", Map.NbXCells + 1);
1601 fprintf(fMapInfo, "%d\n", Map.NbYCells + 1);
1602 fprintf(fMapInfo, "%d\n", Map.NbZCells + 1);
1603 fprintf(fMapInfo, "%le %le\n", Map.Xmin * 100.0, Map.Xmax * 100.0);
1604 fprintf(fMapInfo, "%le %le\n", Map.Ymin * 100.0, Map.Ymax * 100.0);
1605 fprintf(fMapInfo, "%le %le\n", Map.Zmin * 100.0, Map.Zmax * 100.0);
1606 fprintf(fMapInfo, "%le\n", Map.XStagger * 100.0);
1607 fprintf(fMapInfo, "%le\n", Map.YStagger * 100.0);
1608 fprintf(fMapInfo, "%le\n", Map.ZStagger * 100.0);
1609 fprintf(fMapInfo, "MapFPR.out\n");
1610 // if (OptStaggerMap) fprintf(fMapInfo, "StgrMapFPR.out\n"); /// not being read
1611 fclose(fMapInfo);
1612
1613 char MapFile[256];
1614 strcpy(MapFile, BCOutDir);
1615 strcat(MapFile, "/MapFPR.out");
1616 FILE *fMap = fopen(MapFile, "w");
1617 if (fMap == NULL) {
1618 neBEMMessage("MapFPR - MapFile");
1619 return -1;
1620 }
1621 if (dbgFn) {
1622 printf("MapFPR.out created ...\n");
1623 fflush(stdout);
1624 }
1625
1626 fprintf(
1627 fMap,
1628 "# X(cm)\tY(cm)\tZ(cm)\tFX(V/cm)\tFY(V/cm)\tFZ(V/cm)\tPot(V)\tRegion\n");
1629
1630 int nbXCells = Map.NbXCells;
1631 int nbYCells = Map.NbYCells;
1632 int nbZCells = Map.NbZCells;
1633 double startX = Map.Xmin;
1634 double startY = Map.Ymin;
1635 double startZ = Map.Zmin;
1636 double delX = (Map.Xmax - Map.Xmin) / nbXCells;
1637 double delY = (Map.Ymax - Map.Ymin) / nbYCells;
1638 double delZ = (Map.Zmax - Map.Zmin) / nbZCells;
1639
1640 double *MapFX = dvector(0, nbZCells + 1);
1641 double *MapFY = dvector(0, nbZCells + 1);
1642 double *MapFZ = dvector(0, nbZCells + 1);
1643 double *MapP = dvector(0, nbZCells + 1);
1644
1645 if (dbgFn) {
1646 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
1647 nbZCells);
1648 printf("startX, startY, startZ: %le, %le, %le\n", startX, startY, startZ);
1649 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
1650 fflush(stdout);
1651 }
1652
1653 for (int i = 1; i <= nbXCells + 1; ++i) {
1654 for (int j = 1; j <= nbYCells + 1; ++j) {
1655 if (dbgFn) {
1656 printf("MapFPR => i: %4d, j: %4d", i, j);
1657 fflush(stdout);
1658 }
1659
1660 Point3D point;
1661#ifdef _OPENMP
1662 int nthreads = 1, tid = 0;
1663 #pragma omp parallel private(nthreads, tid)
1664#endif
1665 {
1666#ifdef _OPENMP
1667 if (dbgFn) {
1668 tid = omp_get_thread_num();
1669 if (tid == 0) {
1670 nthreads = omp_get_num_threads();
1671 printf("Starting voxel computation with %d threads\n", nthreads);
1672 }
1673 }
1674#endif
1675 int k;
1676 Vector3D field;
1677 double potential;
1678#ifdef _OPENMP
1679 #pragma omp for private(k, point, potential, field)
1680#endif
1681 for (k = 1; k <= nbZCells + 1; ++k) {
1682 point.X = startX + (i - 1) * delX; // all 3 components need to be
1683 point.Y = startY + (j - 1) * delY; // evaluated after pragma omp
1684 point.Z = startZ + (k - 1) * delZ;
1685
1686 if (dbgFn) {
1687 printf("i, j, k: %d, %d, %d\n", i, j, k);
1688 printf("point X, Y, Z: %.8lg\t%.8lg\t%.8lg\n",
1689 point.X / LengthScale, point.Y / LengthScale,
1690 point.Z / LengthScale);
1691 fflush(stdout);
1692 }
1693
1694 if (OptReadFastPF) {
1695 int fstatus = FastPFAtPoint(&point, &potential, &field);
1696 if (fstatus != 0) {
1697 neBEMMessage("wrong FastPFAtPoint return value in MapFPR\n");
1698 // return -1;
1699 }
1700 } else {
1702 "Suggestion: Use of FastVol can expedite generation of Map.\n");
1703 int fstatus = PFAtPoint(&point, &potential, &field);
1704 if (fstatus != 0) {
1705 neBEMMessage("wrong PFAtPoint return value in MapFPR\n");
1706 // return -1;
1707 }
1708 }
1709
1710 if (dbgFn) {
1711 printf("%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
1712 point.X / LengthScale, point.Y / LengthScale,
1713 point.Z / LengthScale, field.X, field.Y, field.Z,
1714 potential / LengthScale);
1715 fflush(stdout);
1716 }
1717
1718 MapFX[k] = field.X;
1719 MapFY[k] = field.Y;
1720 MapFZ[k] = field.Z;
1721 MapP[k] = potential;
1722 } // loop k
1723 } // pragma omp parallel
1724
1725 for (int k = 1; k <= nbZCells + 1; ++k) {
1726 // file output
1727 point.X = startX + (i - 1) * delX;
1728 point.Y = startY + (j - 1) * delY;
1729 point.Z = startZ + (k - 1) * delZ;
1730
1731 int ivol = neBEMVolumePoint(point.X, point.Y, point.Z);
1732 /*
1733 volMaterial[ivol]; // region linked to material
1734 neBEMVolumeDescription(ivol, &vshp, &vmat, &veps, &vpot, &vq, &vtype);
1735 if (dbgFn) {
1736 printf("volref: %d\n", ivol);
1737 printf("shape: %d, material: %d\n", volShape[ivol], volMaterial[ivol]);
1738 printf("eps: %d, pot: %d\n", volEpsilon[ivol], volPotential[ivol]);
1739 printf("q: %d, type: %d\n", volCharge[ivol], volBoundaryType[ivol]);
1740 printf("shape: %d, material: %d\n", vshp, vmat);
1741 printf("eps: %d, pot: %d\n", veps, vpot);
1742 printf("q: %d, type: %d\n", vq, vtype);
1743 }
1744 */
1745
1746 fprintf(fMap, "%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%4d\n",
1747 100.0 * point.X / LengthScale, 100.0 * point.Y / LengthScale,
1748 100.0 * point.Z / LengthScale, MapFX[k] / 100.0,
1749 MapFY[k] / 100.0, MapFZ[k] / 100.0, MapP[k] / LengthScale,
1750 ivol + 1);
1751 }
1752 fflush(fMap); // file output over
1753 } // loop j
1754 } // loop i
1755
1756 fclose(fMap);
1757
1758 free_dvector(MapFX, 0, nbZCells + 1);
1759 free_dvector(MapFY, 0, nbZCells + 1);
1760 free_dvector(MapFZ, 0, nbZCells + 1);
1761 free_dvector(MapP, 0, nbZCells + 1);
1762
1763 // If staggered map
1764 if (OptStaggerMap) {
1765 char StgrMapFile[256];
1766 strcpy(StgrMapFile, BCOutDir);
1767 strcat(StgrMapFile, "/StgrMapFPR.out");
1768 fMap = fopen(StgrMapFile, "w");
1769 if (fMap == NULL) {
1770 neBEMMessage("StgrMapFPR - Staggered MapFile");
1771 return -1;
1772 }
1773 if (dbgFn) {
1774 printf("StgrMapFPR.out created ...\n");
1775 fflush(stdout);
1776 }
1777
1778 fprintf(
1779 fMap,
1780 "# "
1781 "X(cm)\tY(cm)\tZ(cm)\tFX(V/cm)\tFY(V/cm)\tFZ(V/cm)\tPot(V)\tRegion\n");
1782 // Very static stagger where X-shift is one map long
1783 double LX = (Map.Xmax - Map.Xmin);
1784 Map.Xmin = Map.Xmax;
1785 Map.Xmax = Map.Xmin + LX;
1786 double LY = (Map.Ymax - Map.Ymin);
1788 Map.Ymax = Map.Ymin + LY;
1789 nbXCells = Map.NbXCells;
1790 nbYCells = Map.NbYCells;
1791 nbZCells = Map.NbZCells;
1792 startX = Map.Xmin;
1793 // and y-shift is of the presecribed amount
1794 startY = Map.Ymin + Map.YStagger;
1795 startZ = Map.Zmin;
1796 delX = (Map.Xmax - Map.Xmin) / nbXCells;
1797 delY = (Map.Ymax - Map.Ymin) / nbYCells;
1798 delZ = (Map.Zmax - Map.Zmin) / nbZCells;
1799
1800 MapFX = dvector(0, nbZCells + 1);
1801 MapFY = dvector(0, nbZCells + 1);
1802 MapFZ = dvector(0, nbZCells + 1);
1803 MapP = dvector(0, nbZCells + 1);
1804
1805 if (dbgFn) {
1806 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
1807 nbZCells);
1808 printf("startX, startY, startZ: %le, %le, %le\n", startX, startY, startZ);
1809 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
1810 fflush(stdout);
1811 }
1812
1813 for (int i = 1; i <= nbXCells + 1; ++i) {
1814 for (int j = 1; j <= nbYCells + 1; ++j) {
1815 if (dbgFn) {
1816 printf("StgrMapFPR => i: %4d, j: %4d", i, j);
1817 fflush(stdout);
1818 }
1819
1820 Point3D point;
1821#ifdef _OPENMP
1822 int nthreads = 1, tid = 0;
1823 #pragma omp parallel private(nthreads, tid)
1824#endif
1825 {
1826#ifdef _OPENMP
1827 if (dbgFn) {
1828 tid = omp_get_thread_num();
1829 if (tid == 0) {
1830 nthreads = omp_get_num_threads();
1831 printf("Starting voxel computation with %d threads\n", nthreads);
1832 }
1833 } // if dbgFn
1834#endif
1835 int k;
1836 Vector3D field;
1837 double potential;
1838#ifdef _OPENMP
1839 #pragma omp for private(k, point, potential, field)
1840#endif
1841 for (k = 1; k <= nbZCells + 1; ++k) {
1842 point.X = startX + (i - 1) * delX; // all 3 components need to be
1843 point.Y = startY + (j - 1) * delY; // evaluated after pragma omp
1844 point.Z = startZ + (k - 1) * delZ;
1845
1846 if (dbgFn) {
1847 printf("i, j, k: %d, %d, %d\n", i, j, k);
1848 printf("point X, Y, Z: %.8lg\t%.8lg\t%.8lg\n",
1849 point.X / LengthScale, point.Y / LengthScale,
1850 point.Z / LengthScale);
1851 fflush(stdout);
1852 }
1853
1854 if (OptReadFastPF) {
1855 int fstatus = FastPFAtPoint(&point, &potential, &field);
1856 if (fstatus != 0) {
1857 neBEMMessage("wrong FastPFAtPoint return value in MapFPR\n");
1858 // return -1;
1859 }
1860 } else {
1862 "Suggestion: Use of FastVol can expedite generation of "
1863 "Map.\n");
1864 int fstatus = PFAtPoint(&point, &potential, &field);
1865 if (fstatus != 0) {
1866 neBEMMessage("wrong PFAtPoint return value in MapFPR\n");
1867 // return -1;
1868 }
1869 }
1870
1871 if (dbgFn) {
1872 printf("%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
1873 point.X / LengthScale, point.Y / LengthScale,
1874 point.Z / LengthScale, field.X, field.Y, field.Z,
1875 potential / LengthScale);
1876 fflush(stdout);
1877 }
1878
1879 MapFX[k] = field.X;
1880 MapFY[k] = field.Y;
1881 MapFZ[k] = field.Z;
1882 MapP[k] = potential;
1883 } // loop k
1884 } // pragma omp parallel
1885
1886 for (int k = 1; k <= nbZCells + 1; ++k) {
1887 // file output
1888 point.X = startX + (i - 1) * delX;
1889 point.Y = startY + (j - 1) * delY;
1890 point.Z = startZ + (k - 1) * delZ;
1891
1892 int ivol = neBEMVolumePoint(point.X, point.Y, point.Z);
1893 /*
1894 volMaterial[ivol]; // region linked to material
1895 neBEMVolumeDescription(ivol, &vshp, &vmat, &veps, &vpot, &vq, &vtype);
1896 if (dbgFn) {
1897 printf("volref: %d\n", ivol);
1898 printf("shape: %d, material: %d\n", volShape[ivol], volMaterial[ivol]);
1899 printf("eps: %d, pot: %d\n", volEpsilon[ivol], volPotential[ivol]);
1900 printf("q: %d, type: %d\n", volCharge[ivol], volBoundaryType[ivol]);
1901 printf("shape: %d, material: %d\n", vshp, vmat);
1902 printf("eps: %d, pot: %d\n", veps, vpot);
1903 printf("q: %d, type: %d\n", vq, vtype);
1904 }
1905 */
1906
1907 fprintf(
1908 fMap, "%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%4d\n",
1909 100.0 * point.X / LengthScale, 100.0 * point.Y / LengthScale,
1910 100.0 * point.Z / LengthScale, MapFX[k] / 100.0, MapFY[k] / 100.0,
1911 MapFZ[k] / 100.0, MapP[k] / LengthScale, ivol + 1);
1912 } // for k <= nbZCells
1913 fflush(fMap); // file output over
1914
1915 } // loop j
1916 } // loop i
1917
1918 fclose(fMap);
1919
1920 free_dvector(MapFX, 0, nbZCells + 1);
1921 free_dvector(MapFY, 0, nbZCells + 1);
1922 free_dvector(MapFZ, 0, nbZCells + 1);
1923 free_dvector(MapP, 0, nbZCells + 1);
1924 } // If staggered map
1925
1926 return 0;
1927} // end of MapFPR
1928
1929// Compute potential and field in a mesh within the Fast Volume
1930int FastVolPF(void) {
1931
1932 // The following may be necessary only during the first time step / iteration
1933 // At present, FastVolElePF() considers both element and KnCh effects
1934 // and create one combined fast volume.
1935 int fstatus = FastVolElePF();
1936 if (fstatus) {
1937 printf(
1938 "Problem in FastVolElePF being called from FastVolPF ... returning\n");
1939 return -1;
1940 }
1941
1942 /*
1943 // The following is likely to change throughout the computation and necessary
1944 // at all time steps. However, in order to achieve computational economy, it
1945 // may be prudent to carry out the following only after several time steps.
1946 if (OptKnCh) {
1947 fstatus = FastVolKnChPF();
1948 if (fstatus) {
1949 printf("Problem in FastVolKnChPF being called from FastVolPF... returning\n");
1950 return -1;
1951 }
1952 }
1953 */
1954
1955 return 0;
1956} // FastVolPF ends
1957
1958// Compute potential and field in a mesh within the Fast Volume
1959// Possible pitfall: evaluation of n-skips
1960// As the name implies, this function uses the ElePFAtPoint function only.
1961// As a result, KnChPFAtPoint is not included in the resulting values.
1962// The effects due to known charge distributions can be included separately
1963// as if they are perturbations on the background system.
1964int FastVolElePF(void) {
1965 int dbgFn = 0;
1966 int fstatus;
1967
1968 int nbXCells;
1969 int nbYCells;
1970 int nbZCells;
1971 double startX;
1972 double startY;
1973 double startZ;
1974 double delX;
1975 double delY;
1976 double delZ;
1977
1978 printf("\nPotential and field computation within basic fast volume\n");
1979 int bskip = 0, iskip = 0, jskip = 0, kskip = 0;
1980
1981 // calculate n-skips based on NbPtSkip
1982 if (NbPtSkip) {
1983 int volptcnt = 0, endskip = 0;
1984
1985 for (int block = 1; block <= FastVol.NbBlocks; ++block) {
1986 nbXCells = BlkNbXCells[block];
1987 nbYCells = BlkNbYCells[block];
1988 nbZCells = BlkNbZCells[block];
1989 for (int i = 1; i <= nbXCells + 1; ++i) {
1990 for (int j = 1; j <= nbYCells + 1; ++j) {
1991 for (int k = 1; k <= nbZCells + 1; ++k) {
1992 ++volptcnt;
1993
1994 if (volptcnt == NbPtSkip) {
1995 bskip = block - 1;
1996 iskip = i - 1;
1997 jskip = j - 1;
1998 kskip = k;
1999 endskip = 1;
2000 }
2001
2002 if (endskip) break;
2003 }
2004 if (endskip) break;
2005 }
2006 if (endskip) break;
2007 }
2008 if (endskip) break;
2009 }
2010 if (dbgFn) {
2011 printf(
2012 "Basic fast volume => bskip, iskip, jskip, kskip: %d, %d, %d, %d\n",
2013 bskip, iskip, jskip, kskip);
2014 }
2015 } // NbPtSkip
2016
2017 char FastVolPFFile[256];
2018 FILE *fFastVolPF;
2019 strcpy(FastVolPFFile, BCOutDir);
2020 strcat(FastVolPFFile, "/FastVolPF.out");
2021 fFastVolPF = fopen(FastVolPFFile, "w");
2022 if (fFastVolPF == NULL) {
2023 neBEMMessage("FastVolPF - FastVolPFFile");
2024 return -1;
2025 }
2026 fprintf(fFastVolPF, "#block\tX\tY\tZ\tPot\tFX\tFY\tFZ\n");
2027
2028 if (dbgFn) {
2029 printf("FastVolPF.out created ...\n");
2030 fflush(stdout);
2031 }
2032
2033 for (int block = 1 + bskip; block <= FastVol.NbBlocks; ++block) {
2034 nbXCells = BlkNbXCells[block];
2035 nbYCells = BlkNbYCells[block];
2036 nbZCells = BlkNbZCells[block];
2037 startX = FastVol.CrnrX;
2038 startY = FastVol.CrnrY;
2039 startZ = BlkCrnrZ[block];
2040 delX = FastVol.LX / nbXCells;
2041 delY = FastVol.LY / nbYCells;
2042 delZ = BlkLZ[block] / nbZCells;
2043 printf(
2044 "NbBlocks: %d, block: %d, nbXCells: %d, nbYCells: %d, nbZCells: %d\n",
2045 FastVol.NbBlocks, block, nbXCells, nbYCells, nbZCells);
2046
2047 if (dbgFn) {
2048 printf("block: %d\n", block);
2049 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
2050 nbZCells);
2051 printf("startX, startY, startZ: %le, %le, %le\n", startX, startY, startZ);
2052 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
2053 printf("bskip, iskip, jskip, kskip: %d, %d, %d, %d\n", bskip, iskip,
2054 jskip, kskip);
2055 fflush(stdout);
2056 }
2057 // total number of points in a given block
2058 // int blktotpt = (nbXCells + 1) * (nbYCells + 1) * (nbZCells + 1);
2059 for (int i = 1 + iskip; i <= nbXCells + 1; ++i) {
2060 for (int j = 1 + jskip; j <= nbYCells + 1; ++j) {
2061 printf("Fast volume => block: %3d, i: %4d, j: %4d", block, i, j);
2062 fflush(stdout);
2063
2064 Point3D point;
2065#ifdef _OPENMP
2066 int nthreads = 1, tid = 0;
2067 #pragma omp parallel private(nthreads, tid)
2068#endif
2069 {
2070#ifdef _OPENMP
2071 if (dbgFn) {
2072 tid = omp_get_thread_num();
2073 if (tid == 0) {
2074 nthreads = omp_get_num_threads();
2075 printf("Starting fast volume computation with %d threads\n",
2076 nthreads);
2077 }
2078 }
2079#endif
2080 int k;
2081 int omitFlag;
2082 double potential;
2083 Vector3D field;
2084#ifdef _OPENMP
2085 #pragma omp for private(k, point, omitFlag, potential, field)
2086#endif
2087 for (k = 1 + kskip; k <= nbZCells + 1; ++k) {
2088 potential = 0.0;
2089 field.X = field.Y = field.Z = 0.0;
2090
2091 point.X = startX + (i - 1) * delX;
2092 point.Y = startY + (j - 1) * delY;
2093 point.Z = startZ + (k - 1) * delZ;
2094
2095 // Check whether the point falls within a volume that should be
2096 // ignored
2097 omitFlag = 0;
2098 for (int omit = 1; omit <= FastVol.NbOmitVols; ++omit) {
2099 if ((point.X > OmitVolCrnrX[omit]) &&
2100 (point.X < OmitVolCrnrX[omit] + OmitVolLX[omit]) &&
2101 (point.Y > OmitVolCrnrY[omit]) &&
2102 (point.Y < OmitVolCrnrY[omit] + OmitVolLY[omit]) &&
2103 (point.Z > OmitVolCrnrZ[omit]) &&
2104 (point.Z < OmitVolCrnrZ[omit] + OmitVolLZ[omit])) {
2105 omitFlag = 1;
2106 break;
2107 }
2108 } // loop over omitted volumes
2109
2110 if (dbgFn) {
2111 printf("block, i, j, k: %d, %d, %d, %d\n", block, i, j, k);
2112 printf("point X, Y, Z: %.8lg\t%.8lg\t%.8lg\n",
2113 point.X / LengthScale, point.Y / LengthScale,
2114 point.Z / LengthScale);
2115 printf("omitFlag: %d\n", omitFlag);
2116 fflush(stdout);
2117 }
2118
2119 if (omitFlag) {
2120 potential = field.X = field.Y = field.Z = 0.0;
2121 } else {
2122 // fstatus = ElePFAtPoint(&point, &potential, &field);
2123 fstatus =
2124 PFAtPoint(&point, &potential, &field); // both ele and KnCh
2125 if (fstatus != 0) {
2127 "wrong ElePFAtPoint return value in FastVolElePF.\n");
2128 // return -1;
2129 }
2130 }
2131 if (dbgFn) {
2132 printf("%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2133 point.X / LengthScale, point.Y / LengthScale,
2134 point.Z / LengthScale, potential / LengthScale, field.X,
2135 field.Y, field.Z);
2136 fflush(stdout);
2137 }
2138
2139 FastPot[block][i][j][k] = potential;
2140 FastFX[block][i][j][k] = field.X;
2141 FastFY[block][i][j][k] = field.Y;
2142 FastFZ[block][i][j][k] = field.Z;
2143 } // loop k
2144 } // pragma omp parallel
2145
2146 for (int k = 1 + kskip; k <= nbZCells + 1; ++k) // file output
2147 {
2148 point.X = startX + (i - 1) * delX;
2149 point.Y = startY + (j - 1) * delY;
2150 point.Z = startZ + (k - 1) * delZ;
2151
2152 fprintf(fFastVolPF,
2153 "%4d\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2154 block, point.X / LengthScale, point.Y / LengthScale,
2155 point.Z / LengthScale, FastPot[block][i][j][k],
2156 FastFX[block][i][j][k], FastFY[block][i][j][k],
2157 FastFZ[block][i][j][k]);
2158 }
2159 fflush(fFastVolPF); // file output over
2160
2161 printf(
2162 "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
2163 "\b\b\b\b\b\b\b\b\b\b");
2164 } // loop j
2165 } // loop i
2166 } // loop block
2167
2168 fclose(fFastVolPF);
2169
2170 if (OptStaggerFastVol) {
2171 printf("Potential and field computation within staggered fast volume\n");
2172
2173 bskip = iskip = jskip = kskip = 0;
2174
2175 // calculate n-skips based on NbStgPtSkip
2176 if (NbStgPtSkip) {
2177 int volptcnt = 0, endskip = 0;
2178
2179 for (int block = 1; block <= FastVol.NbBlocks; ++block) {
2180 nbXCells = BlkNbXCells[block];
2181 nbYCells = BlkNbYCells[block];
2182 nbZCells = BlkNbZCells[block];
2183 for (int i = 1; i <= nbXCells + 1; ++i) {
2184 for (int j = 1; j <= nbYCells + 1; ++j) {
2185 for (int k = 1; k <= nbZCells + 1; ++k) {
2186 ++volptcnt;
2187
2188 if (volptcnt == NbStgPtSkip) {
2189 bskip = block - 1;
2190 iskip = i - 1;
2191 jskip = j - 1;
2192 kskip = k;
2193 endskip = 1;
2194 }
2195
2196 if (endskip) break;
2197 }
2198 if (endskip) break;
2199 }
2200 if (endskip) break;
2201 }
2202 if (endskip) break;
2203 }
2204 if (dbgFn) {
2205 printf(
2206 "Staggered volume => bskip, iskip, jskip, kskip: %d, %d, %d, %d\n",
2207 bskip, iskip, jskip, kskip);
2208 }
2209 } // NbStgPtSkip
2210
2211 char FastStgVolPFFile[256];
2212 FILE *fFastStgVolPF;
2213 strcpy(FastStgVolPFFile, BCOutDir);
2214 strcat(FastStgVolPFFile, "/FastStgVolPF.out");
2215 fFastStgVolPF = fopen(FastStgVolPFFile, "w");
2216 if (fFastStgVolPF == NULL) {
2217 neBEMMessage("FastVolPF - FastStgVolPFFile");
2218 return -1;
2219 }
2220 fprintf(fFastStgVolPF, "#block\tX\tY\tZ\tPot\tFX\tFY\tFZ\n");
2221
2222 if (dbgFn) {
2223 printf("FastStgVolPF.out created ...\n");
2224 fflush(stdout);
2225 }
2226
2227 for (int block = 1 + bskip; block <= FastVol.NbBlocks; ++block) {
2228 nbXCells = BlkNbXCells[block];
2229 nbYCells = BlkNbYCells[block];
2230 nbZCells = BlkNbZCells[block];
2231 startX = FastVol.CrnrX + FastVol.LX;
2232 startY = FastVol.CrnrY + FastVol.YStagger;
2233 startZ = BlkCrnrZ[block];
2234 delX = FastVol.LX / nbXCells;
2235 delY = FastVol.LY / nbYCells;
2236 delZ = BlkLZ[block] / nbZCells;
2237 printf(
2238 "NbBlocks: %d, block: %d, nbXCells: %d, nbYCells: %d, nbZCells: %d\n",
2239 FastVol.NbBlocks, block, nbXCells, nbYCells, nbZCells);
2240
2241 if (dbgFn) {
2242 printf("block: %d\n", block);
2243 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
2244 nbZCells);
2245 printf("startX, startY, startZ: %le, %le, %le\n", startX, startY,
2246 startZ);
2247 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
2248 printf("bskip, iskip, jskip, kskip: %d, %d, %d, %d\n", bskip, iskip,
2249 jskip, kskip);
2250 fflush(stdout);
2251 }
2252
2253 // int blktotpt = (nbXCells + 1) * (nbYCells + 1) * (nbZCells + 1);
2254 for (int i = 1 + iskip; i <= nbXCells + 1; ++i) {
2255 for (int j = 1 + jskip; j <= nbYCells + 1; ++j) {
2256 printf("Fast volume => block: %3d, i: %4d, j: %4d", block, i, j);
2257 fflush(stdout);
2258
2259 Point3D point;
2260#ifdef _OPENMP
2261 int nthreads = 1, tid = 0;
2262 #pragma omp parallel private(nthreads, tid)
2263#endif
2264 {
2265#ifdef _OPENMP
2266 if (dbgFn) {
2267 tid = omp_get_thread_num();
2268 if (tid == 0) {
2269 nthreads = omp_get_num_threads();
2270 printf(
2271 "Starting staggered fast volume computation with %d "
2272 "threads\n",
2273 nthreads);
2274 }
2275 }
2276#endif
2277 int k;
2278 int omitFlag;
2279 double potential;
2280 Vector3D field;
2281#ifdef _OPENMP
2282 #pragma omp for private(k, point, omitFlag, potential, field)
2283#endif
2284 for (k = 1 + kskip; k <= nbZCells + 1; ++k) {
2285 potential = 0.0;
2286 field.X = field.Y = field.Z = 0.0;
2287
2288 point.X = startX + (i - 1) * delX;
2289 point.Y = startY + (j - 1) * delY;
2290 point.Z = startZ + (k - 1) * delZ;
2291
2292 // Check whether point falls within a volume that should be
2293 // ignored
2294 omitFlag = 0;
2295 for (int omit = 1; omit <= FastVol.NbOmitVols; ++omit) {
2296 if ((point.X > OmitVolCrnrX[omit] + FastVol.LX) &&
2297 (point.X <
2298 OmitVolCrnrX[omit] + OmitVolLX[omit] + FastVol.LX) &&
2299 (point.Y > OmitVolCrnrY[omit] + FastVol.YStagger) &&
2300 (point.Y <
2301 OmitVolCrnrY[omit] + OmitVolLY[omit] + FastVol.YStagger) &&
2302 (point.Z > OmitVolCrnrZ[omit]) &&
2303 (point.Z < OmitVolCrnrZ[omit] + OmitVolLZ[omit])) {
2304 omitFlag = 1;
2305 break;
2306 }
2307 } // loop over omitted volumes
2308
2309 if (dbgFn) {
2310 printf("point X, Y, Z: %.8lg\t%.8lg\t%.8lg\n",
2311 point.X / LengthScale, point.Y / LengthScale,
2312 point.Z / LengthScale);
2313 printf("omitFlag: %d\n", omitFlag);
2314 fflush(stdout);
2315 }
2316
2317 if (omitFlag) {
2318 potential = field.X = field.Y = field.Z = 0.0;
2319 } else {
2320 // fstatus = ElePFAtPoint(&point, &potential, &field);
2321 fstatus =
2322 PFAtPoint(&point, &potential, &field); // both ele & KnCh
2323 if (fstatus != 0) {
2325 "wrong PFAtPoint return value in FastVolElePF.\n");
2326 // return -1;
2327 }
2328 }
2329 if (dbgFn) {
2330 printf("%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2331 point.X / LengthScale, point.Y / LengthScale,
2332 point.Z / LengthScale, potential / LengthScale, field.X,
2333 field.Y, field.Z);
2334 fflush(stdout);
2335 }
2336
2337 FastStgPot[block][i][j][k] = potential;
2338 FastStgFX[block][i][j][k] = field.X;
2339 FastStgFY[block][i][j][k] = field.Y;
2340 FastStgFZ[block][i][j][k] = field.Z;
2341 } // loop k
2342 } // pragma omp
2343
2344 for (int k = 1 + kskip; k <= nbZCells + 1; ++k) // file output
2345 {
2346 point.X = startX + (i - 1) * delX;
2347 point.Y = startY + (j - 1) * delY;
2348 point.Z = startZ + (k - 1) * delZ;
2349
2350 fprintf(fFastStgVolPF,
2351 "%4d\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2352 block, point.X / LengthScale, point.Y / LengthScale,
2353 point.Z / LengthScale, FastPot[block][i][j][k],
2354 FastFX[block][i][j][k], FastFY[block][i][j][k],
2355 FastFZ[block][i][j][k]);
2356 }
2357 fflush(fFastStgVolPF); // file output over
2358
2359 printf(
2360 "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
2361 "\b\b\b\b\b\b\b\b\b\b\b");
2362 } // loop j
2363 } // loop i
2364 } // loop block
2365
2366 fclose(fFastStgVolPF);
2367 } // if OptStaggerFastVol
2368
2369 return 0;
2370} // FastVolElePF ends
2371
2372/* This at present is unnecessary since FastVolElePF considers effects due to
2373 * elements, as well as known charges.
2374// Compute potential and field in a mesh within the Fast Volume
2375// Possible pitfall: evaluation of n-skips
2376// As the name implies, this function does NOT use the ElePFAtPoint function.
2377// Only KnChPFAtPoint is included in the resulting values.
2378// These effects due to known charge distributions are expected to be
2379// perturbations on the background system.
2380int FastVolKnChPF(void)
2381{
2382int dbgFn = 0;
2383int fstatus;
2384
2385int nbXCells;
2386int nbYCells;
2387int nbZCells;
2388double startX;
2389double startY;
2390double startZ;
2391double delX;
2392double delY;
2393double delZ;
2394
2395printf("\nPotential and field computation within basic fast volume\n");
2396int blktotpt; // total number of points in a given block
2397int bskip = 0, iskip = 0, jskip = 0, kskip = 0;
2398
2399// calculate n-skips based on NbPtSkip
2400if(NbPtSkip)
2401 {
2402 int volptcnt = 0, endskip = 0;
2403
2404 for(int block = 1; block <= FastVol.NbBlocks; ++block)
2405 {
2406 nbXCells = BlkNbXCells[block];
2407 nbYCells = BlkNbYCells[block];
2408 nbZCells = BlkNbZCells[block];
2409 for(int i = 1; i <= nbXCells+1; ++i)
2410 {
2411 for(int j = 1; j <= nbYCells+1; ++j)
2412 {
2413 for(int k = 1; k <= nbZCells+1; ++k)
2414 {
2415 ++volptcnt;
2416
2417 if(volptcnt == NbPtSkip)
2418 {
2419 bskip = block-1; iskip = i-1;
2420jskip = j-1; kskip = k; endskip = 1;
2421 }
2422
2423 if(endskip) break;
2424 }
2425 if(endskip) break;
2426 }
2427 if(endskip) break;
2428 }
2429 if(endskip) break;
2430 }
2431 if(dbgFn)
2432 {
2433 printf("Basic fast volume => bskip, iskip, jskip, kskip: %d, %d,
2434%d, %d\n", bskip, iskip, jskip, kskip);
2435 }
2436 } // NbPtSkip
2437
2438char FastVolKnChPFFile[256];
2439FILE *fFastVolKnChPF;
2440strcpy(FastVolKnChPFFile, BCOutDir);
2441strcat(FastVolKnChPFFile, "/FastVolKnChPF.out");
2442fFastVolKnChPF = fopen(FastVolKnChPFFile, "w");
2443if(fFastVolKnChPF == NULL)
2444 {
2445 neBEMMessage("FastVolKnChPF - FastVolKnChPFFile");
2446 return -1;
2447 }
2448fprintf(fFastVolKnChPF, "#block\tX\tY\tZ\tPot\tFX\tFY\tFZ\n");
2449
2450if(dbgFn)
2451 {
2452 printf("FastVolKnChPF.out created ...\n"); fflush(stdout);
2453 }
2454
2455for(int block = 1+bskip; block <= FastVol.NbBlocks; ++block)
2456 {
2457 nbXCells = BlkNbXCells[block];
2458 nbYCells = BlkNbYCells[block];
2459 nbZCells = BlkNbZCells[block];
2460 startX = FastVol.CrnrX;
2461 startY = FastVol.CrnrY;
2462 startZ = BlkCrnrZ[block];
2463 delX = FastVol.LX / nbXCells;
2464 delY = FastVol.LY / nbYCells;
2465 delZ = BlkLZ[block] / nbZCells;
2466 printf("NbBlocks: %d, block: %d, nbXCells: %d, nbYCells: %d, nbZCells:
2467%d\n", FastVol.NbBlocks, block, nbXCells, nbYCells, nbZCells);
2468
2469 if(dbgFn)
2470 {
2471 printf("block: %d\n", block);
2472 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n",
2473 nbXCells, nbYCells, nbZCells);
2474 printf("startX, startY, startZ: %le, %le, %le\n", startX,
2475startY, startZ); printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
2476 printf("bskip, iskip, jskip, kskip: %d, %d, %d, %d\n",
2477 bskip, iskip, jskip, kskip);
2478 fflush(stdout);
2479 }
2480
2481 blktotpt = (nbXCells+1)*(nbYCells+1)*(nbZCells+1);
2482 for(int i = 1+iskip; i <= nbXCells+1; ++i)
2483 {
2484 for(int j = 1+jskip; j <= nbYCells+1; ++j)
2485 {
2486
2487 printf("Fast volume => block: %3d, i: %4d, j: %4d",
2488block, i, j); fflush(stdout);
2489
2490 Point3D point;
2491 int nthreads = 1, tid = 0;
2492 #pragma omp parallel private(nthreads, tid)
2493 {
2494 if(dbgFn)
2495 {
2496 tid = omp_get_thread_num();
2497 if (tid == 0)
2498 {
2499 nthreads = omp_get_num_threads();
2500 printf("Starting fast volume computation with %d
2501threads\n", nthreads);
2502 }
2503 }
2504
2505 int k;
2506 int omitFlag;
2507 double potential;
2508 Vector3D field;
2509 #pragma omp for private(k, point, omitFlag, potential,
2510field) for(k = 1+kskip; k <= nbZCells+1; ++k)
2511 {
2512 point.X = startX + (i-1)*delX;
2513 point.Y = startY + (j-1)*delY;
2514 point.Z = startZ + (k-1)*delZ;
2515
2516 // Check whether the point falls within a volume
2517that should be ignored omitFlag = 0; for(int omit = 1; omit <=
2518FastVol.NbOmitVols; ++omit)
2519 {
2520 if((point.X > OmitVolCrnrX[omit])
2521 && (point.X <
2522OmitVolCrnrX[omit]+OmitVolLX[omit])
2523 && (point.Y >
2524OmitVolCrnrY[omit])
2525 && (point.Y <
2526OmitVolCrnrY[omit]+OmitVolLY[omit])
2527 && (point.Z >
2528OmitVolCrnrZ[omit])
2529 && (point.Z <
2530OmitVolCrnrZ[omit]+OmitVolLZ[omit]))
2531 {
2532 omitFlag = 1;
2533 break;
2534 }
2535 } // loop over omitted volumes
2536
2537 if(dbgFn)
2538 {
2539 printf("block, i, j, k: %d, %d, %d,
2540%d\n", block, i, j, k); printf("point X, Y, Z: %.8lg\t%.8lg\t%.8lg\n",
2541 point.X/LengthScale, point.Y/LengthScale,
2542point.Z/LengthScale); printf("omitFlag: %d\n", omitFlag); fflush(stdout);
2543 }
2544
2545 if(omitFlag)
2546 {
2547 potential = field.X = field.Y = field.Z
2548= 0.0;
2549 }
2550 else
2551 {
2552 fstatus = KnChPFAtPoint(&point, &potential, &field);
2553 if(fstatus != 0)
2554 {
2555 neBEMMessage("wrong
2556KnChPFAtPoint return value in FastVolKnChPF.\n");
2557 // return -1;
2558 }
2559 }
2560 if(dbgFn)
2561 {
2562 printf("%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2563 point.X/LengthScale, point.Y/LengthScale,
2564point.Z/LengthScale, potential/LengthScale, field.X, field.Y, field.Z);
2565 fflush(stdout);
2566 }
2567
2568 FastPot[block][i][j][k] = potential;
2569 FastFX[block][i][j][k] = field.X;
2570 FastFY[block][i][j][k] = field.Y;
2571 FastFZ[block][i][j][k] = field.Z;
2572 } // loop k
2573 } // pragma omp parallel
2574
2575 for(int k = 1+kskip; k <= nbZCells+1; ++k) // file
2576output
2577 {
2578 point.X = startX + (i-1)*delX;
2579 point.Y = startY + (j-1)*delY;
2580 point.Z = startZ + (k-1)*delZ;
2581
2582 fprintf(fFastVolKnChPF,
2583 "%4d\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2584 block,
2585 point.X/LengthScale,
2586point.Y/LengthScale, point.Z/LengthScale,
2587 FastPot[block][i][j][k],FastFX[block][i][j][k],
2588 FastFY[block][i][j][k],
2589FastFZ[block][i][j][k]);
2590 }
2591 fflush(fFastVolKnChPF); // file output over
2592
2593 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
2594 } // loop j
2595 } // loop i
2596 } // loop block
2597
2598fclose(fFastVolKnChPF);
2599
2600if(OptStaggerFastVol)
2601 {
2602 printf("Potential and field computation within staggered fast
2603volume\n");
2604
2605 bskip = iskip = jskip = kskip = 0;
2606
2607 // calculate n-skips based on NbStgPtSkip
2608 if(NbStgPtSkip)
2609 {
2610 int volptcnt = 0, endskip = 0;
2611
2612 for(int block = 1; block <= FastVol.NbBlocks; ++block)
2613 {
2614 nbXCells = BlkNbXCells[block];
2615 nbYCells = BlkNbYCells[block];
2616 nbZCells = BlkNbZCells[block];
2617 for(int i = 1; i <= nbXCells+1; ++i)
2618 {
2619 for(int j = 1; j <= nbYCells+1; ++j)
2620 {
2621 for(int k = 1; k <= nbZCells+1; ++k)
2622 {
2623 ++volptcnt;
2624
2625 if(volptcnt == NbStgPtSkip)
2626 {
2627 bskip = block-1; iskip =
2628i-1; jskip = j-1; kskip = k; endskip = 1;
2629 }
2630
2631 if(endskip) break;
2632 }
2633 if(endskip) break;
2634 }
2635 if(endskip) break;
2636 }
2637 if(endskip) break;
2638 }
2639 if(dbgFn)
2640 {
2641 printf("Staggered volume => bskip, iskip, jskip, kskip:
2642%d, %d, %d, %d\n", bskip, iskip, jskip, kskip);
2643 }
2644 } // NbStgPtSkip
2645
2646 char FastStgVolKnChPFFile[256];
2647 FILE *fFastStgVolKnChPF;
2648 strcpy(FastStgVolKnChPFFile, BCOutDir);
2649 strcat(FastStgVolKnChPFFile, "/FastStgVolKnChPF.out");
2650 fFastStgVolKnChPF = fopen(FastStgVolKnChPFFile, "w");
2651 if(fFastStgVolKnChPF == NULL)
2652 {
2653 neBEMMessage("FastVolKnChPF - FastStgVolKnChPFFile");
2654 return -1;
2655 }
2656 fprintf(fFastStgVolKnChPF, "#block\tX\tY\tZ\tPot\tFX\tFY\tFZ\n");
2657
2658 if(dbgFn)
2659 {
2660 printf("FastStgVolKnChPF.out created ...\n"); fflush(stdout);
2661 }
2662
2663 for(int block = 1+bskip; block <= FastVol.NbBlocks; ++block)
2664 {
2665 nbXCells = BlkNbXCells[block];
2666 nbYCells = BlkNbYCells[block];
2667 nbZCells = BlkNbZCells[block];
2668 startX = FastVol.CrnrX + FastVol.LX;
2669 startY = FastVol.CrnrY + FastVol.YStagger;
2670 startZ = BlkCrnrZ[block];
2671 delX = FastVol.LX / nbXCells;
2672 delY = FastVol.LY / nbYCells;
2673 delZ = BlkLZ[block] / nbZCells;
2674 printf(
2675 "NbBlocks: %d, block: %d, nbXCells: %d,
2676nbYCells: %d, nbZCells: %d\n", FastVol.NbBlocks, block, nbXCells, nbYCells,
2677nbZCells);
2678
2679 if(dbgFn)
2680 {
2681 printf("block: %d\n", block);
2682 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n",
2683 nbXCells, nbYCells,
2684nbZCells); printf("startX, startY, startZ: %le, %le, %le\n", startX, startY,
2685startZ); printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
2686 printf("bskip, iskip, jskip, kskip: %d, %d, %d, %d\n",
2687 bskip, iskip, jskip,
2688kskip); fflush(stdout);
2689 }
2690
2691 blktotpt = (nbXCells+1)*(nbYCells+1)*(nbZCells+1);
2692 for(int i = 1+iskip; i <= nbXCells+1; ++i)
2693 {
2694 for(int j = 1+jskip; j <= nbYCells+1; ++j)
2695 {
2696
2697 printf("Fast volume => block: %3d, i: %4d, j:
2698%4d", block, i, j); fflush(stdout);
2699
2700 Point3D point;
2701 int nthreads, tid;
2702 #pragma omp parallel private(nthreads, tid)
2703 {
2704 if(dbgFn)
2705 {
2706 tid = omp_get_thread_num();
2707 if (tid == 0)
2708 {
2709 nthreads = omp_get_num_threads();
2710 printf(
2711 "Starting
2712staggered fast volume computation with %d threads\n", nthreads);
2713 }
2714 }
2715
2716 int k;
2717 int omitFlag;
2718 double potential;
2719 Vector3D field;
2720 #pragma omp for private(k, point, omitFlag,
2721potential, field) for(k = 1+kskip; k <= nbZCells+1; ++k)
2722 {
2723 point.X = startX + (i-1)*delX;
2724 point.Y = startY + (j-1)*delY;
2725 point.Z = startZ + (k-1)*delZ;
2726
2727 // Check whether point falls within a
2728volume that should be ignored omitFlag = 0; for(int omit = 1; omit <=
2729FastVol.NbOmitVols; ++omit)
2730 {
2731 if((point.X >
2732OmitVolCrnrX[omit]+FastVol.LX)
2733 && (point.X <
2734OmitVolCrnrX[omit]+OmitVolLX[omit]+FastVol.LX)
2735 && (point.Y >
2736OmitVolCrnrY[omit]+FastVol.YStagger)
2737 && (point.Y <
2738OmitVolCrnrY[omit]+OmitVolLY[omit]+FastVol.YStagger)
2739 && (point.Z >
2740OmitVolCrnrZ[omit])
2741 && (point.Z <
2742OmitVolCrnrZ[omit]+OmitVolLZ[omit]))
2743 {
2744 omitFlag = 1;
2745 break;
2746 }
2747 } // loop over omitted
2748volumes
2749
2750 if(dbgFn)
2751 {
2752 printf("point X, Y, Z: %.8lg\t%.8lg\t%.8lg\n",
2753 point.X/LengthScale, point.Y/LengthScale,
2754point.Z/LengthScale); printf("omitFlag: %d\n", omitFlag); fflush(stdout);
2755 }
2756
2757 if(omitFlag)
2758 {
2759 potential = field.X = field.Y =
2760field.Z = 0.0;
2761 }
2762 else
2763 {
2764 fstatus = KnChPFAtPoint(&point, &potential, &field);
2765 if(fstatus != 0)
2766 {
2767 neBEMMessage("wrong
2768KnChPFAtPoint return value in FastVolKnChPF.\n");
2769 // return -1;
2770 }
2771 }
2772 if(dbgFn)
2773 {
2774 printf("%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2775 point.X/LengthScale, point.Y/LengthScale,
2776point.Z/LengthScale, potential/LengthScale, field.X, field.Y, field.Z);
2777 fflush(stdout);
2778 }
2779
2780 FastStgPot[block][i][j][k] = potential;
2781 FastStgFX[block][i][j][k] = field.X;
2782 FastStgFY[block][i][j][k] = field.Y;
2783 FastStgFZ[block][i][j][k] = field.Z;
2784 } // loop k
2785 } // pragma omp
2786
2787 for(int k = 1+kskip; k <= nbZCells+1; ++k)
2788// file output
2789 {
2790 point.X = startX + (i-1)*delX;
2791 point.Y = startY + (j-1)*delY;
2792 point.Z = startZ + (k-1)*delZ;
2793
2794 fprintf(fFastStgVolKnChPF,
2795 "%4d\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\t%.8lg\n",
2796 block,
2797 point.X/LengthScale,
2798point.Y/LengthScale, point.Z/LengthScale,
2799 FastPot[block][i][j][k],FastFX[block][i][j][k],
2800 FastFY[block][i][j][k],
2801FastFZ[block][i][j][k]);
2802 }
2803 fflush(fFastStgVolKnChPF); // file output
2804over
2805
2806 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
2807 } // loop j
2808 } // loop i
2809 } // loop block
2810
2811 fclose(fFastStgVolKnChPF);
2812 } // if OptStaggerFastVol
2813
2814return 0;
2815} // FastVolKnChPF ends
2816*/
2817
2818// Gives three components of the total Potential and flux in the global
2819// coordinate system due to all the elements using the results stored in
2820// the FAST volume mesh.
2821int FastPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF) {
2822 int dbgFn = 0;
2823 double Xpt = globalP->X;
2824 double Ypt = globalP->Y;
2825 double Zpt = globalP->Z;
2826 double RptVolLX = FastVol.LX;
2827 double RptVolLY = FastVol.LY;
2828 double RptVolLZ = FastVol.LZ;
2829 double CornerX = FastVol.CrnrX;
2830 double CornerY = FastVol.CrnrY;
2831 double CornerZ = FastVol.CrnrZ;
2832 double TriLin(double xd, double yd, double zd, double c000, double c100,
2833 double c010, double c001, double c110, double c101, double c011,
2834 double c111);
2835
2836 // First of all, check how the point in question should be treated ...
2837
2838 // Check whether the point falls within a volume that is not regarded as
2839 // FastVol
2840 for (int ignore = 1; ignore <= FastVol.NbIgnoreVols; ++ignore) {
2841 if ((Xpt >= (IgnoreVolCrnrX[ignore])) &&
2842 (Xpt <= (IgnoreVolCrnrX[ignore] + IgnoreVolLX[ignore])) &&
2843 (Ypt >= (IgnoreVolCrnrY[ignore])) &&
2844 (Ypt <= (IgnoreVolCrnrY[ignore] + IgnoreVolLY[ignore])) &&
2845 (Zpt >= (IgnoreVolCrnrZ[ignore])) &&
2846 (Zpt <= (IgnoreVolCrnrZ[ignore] + IgnoreVolLZ[ignore]))) {
2847 if (dbgFn)
2848 neBEMMessage("In FastPFAtPoint: point in an ignored volume!\n");
2849
2850 int fstatus = PFAtPoint(globalP, Potential, globalF);
2851 if (fstatus != 0) {
2852 neBEMMessage("wrong PFAtPoint return value in FastVolPF.\n");
2853 return -1;
2854 } else
2855 return 0;
2856 }
2857 } // loop over ignored volumes
2858
2859 // If not ignored, the point qualifies for FastVol evaluation ...
2860
2861 // for a staggered fast volume, the volume repeated in X is larger
2862 if (OptStaggerFastVol) {
2863 RptVolLX += FastVol.LX;
2864 }
2865 if (dbgFn) {
2866 printf("\nin FastPFAtPoint\n");
2867 printf("x, y, z: %g, %g, %g\n", Xpt, Ypt, Zpt);
2868 printf("RptVolLX, RptVolLY, RptVolLZ: %g, %g, %g\n", RptVolLX, RptVolLY,
2869 RptVolLZ);
2870 printf("CornerX, CornerY, CornerZ: %g, %g, %g\n", CornerX, CornerY,
2871 CornerZ);
2872 printf("Nb of blocks: %d\n", FastVol.NbBlocks);
2873 for (int block = 1; block <= FastVol.NbBlocks; ++block) {
2874 printf("NbOfXCells: %d\n", BlkNbXCells[block]);
2875 printf("NbOfYCells: %d\n", BlkNbYCells[block]);
2876 printf("NbOfZCells: %d\n", BlkNbZCells[block]);
2877 printf("LZ: %le\n", BlkLZ[block]);
2878 printf("CornerZ: %le\n", BlkCrnrZ[block]);
2879 }
2880 }
2881
2882 // Find equivalent position inside the basic / staggered volume.
2883 // real distance from volume corner
2884 double dx = Xpt - CornerX;
2885 double dy = Ypt - CornerY;
2886 double dz = Zpt - CornerZ;
2887 if (dbgFn)
2888 printf("real dx, dy, dz from volume corner: %g, %g, %g\n", dx, dy, dz);
2889
2890 int NbFastVolX = (int)(dx / RptVolLX);
2891 if (dx < 0.0) --NbFastVolX;
2892 int NbFastVolY = (int)(dy / RptVolLY);
2893 if (dy < 0.0) --NbFastVolY;
2894 int NbFastVolZ = (int)(dz / RptVolLZ);
2895 if (dz < 0.0) --NbFastVolZ;
2896 if (dbgFn)
2897 printf("Volumes in x, y, z: %d, %d, %d\n", NbFastVolX, NbFastVolY,
2898 NbFastVolZ);
2899
2900 // equivalent distances from fast volume corner
2901 dx -= NbFastVolX * RptVolLX;
2902 dy -= NbFastVolY * RptVolLY;
2903 dz -= NbFastVolZ * RptVolLZ;
2904 // The following conditions should never happen - generate an error message
2905 if (dx < 0.0) {
2906 dx = 0.0;
2907 neBEMMessage("equiv dx < 0.0 - not correct!\n");
2908 }
2909 if (dy < 0.0) {
2910 dy = 0.0;
2911 neBEMMessage("equiv dy < 0.0 - not correct!\n");
2912 }
2913 if (dz < 0.0) {
2914 dz = 0.0;
2915 neBEMMessage("equiv dz < 0.0 - not correct!\n");
2916 }
2917 if (dx > RptVolLX) {
2918 dx = RptVolLX;
2919 neBEMMessage("equiv dx > RptVolLX - not correct!\n");
2920 }
2921 if (dy > RptVolLY) {
2922 dy = RptVolLY;
2923 neBEMMessage("equiv dy > RptVolLY - not correct!\n");
2924 }
2925 if (dz > RptVolLZ) {
2926 dz = RptVolLZ;
2927 neBEMMessage("equiv dz > RptVolLZ - not correct!\n");
2928 }
2929 if (dbgFn)
2930 printf("equivalent dist from corner - dx, dy, dz: %g, %g, %g\n", dx, dy,
2931 dz);
2932
2933 // Take care of possible trouble-makers
2934 if (dx < MINDIST) dx = MINDIST; // -ve dx has already been made equal to 0
2935 if (dy < MINDIST) dy = MINDIST;
2936 if (dz < MINDIST) dz = MINDIST;
2937 if ((RptVolLX - dx) < MINDIST)
2938 dx = RptVolLX - MINDIST; // dx > RptVolLX taken care of
2939 if ((RptVolLY - dy) < MINDIST) dy = RptVolLY - MINDIST;
2940 if ((RptVolLZ - dz) < MINDIST) dz = RptVolLZ - MINDIST;
2941 // For staggered volumes, there is another plane where difficulties may occur
2942 if ((dx <= FastVol.LX) && (FastVol.LX - dx) < MINDIST)
2943 dx = FastVol.LX - MINDIST;
2944 // else if((dx > FastVol.LX) && (fabs(FastVol.LX-dx) < MINDIST))
2945 else if ((dx > FastVol.LX) && (dx - FastVol.LX) < MINDIST) // more inttuitive
2946 dx = FastVol.LX + MINDIST;
2947 if (dbgFn)
2948 printf("equivalent dist adjusted - dx, dy, dz: %g, %g, %g\n", dx, dy, dz);
2949
2950 // If volume is staggered, we have a few more things to do before finalizing
2951 // the values of equivalent distance
2952 // sector identification
2953 // _................__________________
2954 // | . . | Sector 3 |
2955 // | . . | |
2956 // | . | . |
2957 // | | . . |
2958 // | Sector 2 | . . |
2959 // |----------------| . . |
2960 // | | . |
2961 // | . | |
2962 // | . . | |
2963 // | . . |----------------|
2964 // | . . | Sector 4 |
2965 // | . | . |
2966 // | | . . |
2967 // | Sector 1 | . . |
2968 // |----------------|................|
2969
2970 int sector = 1; // kept outside `if' since this is necessary further below
2971 if (OptStaggerFastVol) {
2972 if ((dx >= 0.0) && (dx <= FastVol.LX) && (dy >= 0.0) &&
2973 (dy <= FastVol.LY)) {
2974 // point lies in sector 1, everything remains unchanged
2975 sector = 1;
2976 } else if ((dx >= 0.0) && (dx <= FastVol.LX) && (dy > FastVol.LY) &&
2977 (dy <= FastVol.LY + FastVol.YStagger)) {
2978 // point lies in sector 2, move basic volume one step up
2979 sector = 2;
2980 ++NbFastVolY;
2981 CornerY += FastVol.LY; // repeat length in Y is LY
2982 dy -= FastVol.LY;
2983 } else if ((dx > FastVol.LX) && (dx <= 2.0 * FastVol.LX) &&
2984 (dy >= FastVol.YStagger) &&
2985 (dy <= FastVol.LY + FastVol.YStagger)) {
2986 // point lies in sector 3, pt in staggered vol, change corner coords
2987 sector = 3;
2988 CornerX += FastVol.LX;
2989 CornerY += FastVol.YStagger;
2990 dx -= FastVol.LX;
2991 dy -= FastVol.YStagger;
2992 } else if ((dx > FastVol.LX) && (dx <= 2.0 * FastVol.LX) && (dy >= 0.0) &&
2993 (dy < FastVol.YStagger)) {
2994 // point lies in sector 4, move basic volume one step down and consider
2995 // staggered fast volume
2996 sector = 4;
2997 --NbFastVolY;
2998 CornerX += FastVol.LX; // in the staggered part of the repeated volume
2999 CornerY -= (FastVol.LY - FastVol.YStagger);
3000 dx -= FastVol.LX;
3001 dy += (FastVol.LY - FastVol.YStagger);
3002 } else {
3003 neBEMMessage("FastPFAtPoint: point in none of the sectors!\n");
3004 }
3005 if (dbgFn) printf("stagger modified dx, dy, dz: %g, %g, %g\n", dx, dy, dz);
3006 }
3007
3008 // Take care of possible trouble-makers - once more
3009 if (dx < MINDIST) dx = MINDIST; // -ve dx has already been made equal to 0
3010 if (dy < MINDIST) dy = MINDIST;
3011 if (dz < MINDIST) dz = MINDIST;
3012 if ((RptVolLX - dx) < MINDIST)
3013 dx = RptVolLX - MINDIST; // dx > RptVolLX taken care of
3014 if ((RptVolLY - dy) < MINDIST) dy = RptVolLY - MINDIST;
3015 if ((RptVolLZ - dz) < MINDIST) dz = RptVolLZ - MINDIST;
3016 // For staggered volumes, there is another plane where difficulties may occur
3017 if ((dx <= FastVol.LX) && (FastVol.LX - dx) < MINDIST)
3018 dx = FastVol.LX - MINDIST;
3019 // else if((dx > FastVol.LX) && (fabs(FastVol.LX-dx) < MINDIST))
3020 else if ((dx > FastVol.LX) && (dx - FastVol.LX) < MINDIST) // more intuitive
3021 dx = FastVol.LX + MINDIST;
3022 if (dbgFn)
3023 printf("equivalent dist adjusted for staggered: %g, %g, %g\n", dx, dy, dz);
3024
3025 /*
3026 // Check whether the point falls within a volume that is omitted
3027 for(int omit = 1; omit <= FastVol.NbOmitVols; ++omit)
3028 {
3029 if((dx >= (OmitVolCrnrX[omit]-FastVol.CrnrX))
3030 && (dx <=
3031 (OmitVolCrnrX[omit]+OmitVolLX[omit]-FastVol.CrnrX))
3032 && (dy >= (OmitVolCrnrY[omit]-FastVol.CrnrY))
3033 && (dy <=
3034 (OmitVolCrnrY[omit]+OmitVolLY[omit]-FastVol.CrnrY))
3035 && (dz >= (OmitVolCrnrZ[omit]-FastVol.CrnrZ))
3036 && (dz <=
3037 (OmitVolCrnrZ[omit]+OmitVolLZ[omit]-FastVol.CrnrZ)))
3038 {
3039 neBEMMessage("In FastPFAtPoint: point in an omitted
3040 volume!\n"); *Potential = 0.0; globalF->X = 0.0; globalF->Y = 0.0; globalF->Z
3041 = 0.0;
3042 }
3043 } // loop over omitted volumes
3044 */
3045
3046 // Find the block in which the point lies
3047 /*
3048 int thisBlock = 1;
3049 if(FastVol.NbBlocks > 1)
3050 {
3051 for(int block = 1; block <= FastVol.NbBlocks; ++block)
3052 {
3053 if(dbgFn)
3054 {
3055 printf("dz,(BlkCrnrZ-CornerZ),(BlkCrnrZ+BlkLZ-CornerZ):
3056 %lg, %lg, %lg\n", dz, (BlkCrnrZ[block]-CornerZ),
3057 (BlkCrnrZ[block]+BlkLZ[block]-CornerZ));
3058 }
3059 if((dz >= (BlkCrnrZ[block]-CornerZ))
3060 && (dz <=
3061 (BlkCrnrZ[block]+BlkLZ[block]-CornerZ)))
3062 {
3063 thisBlock = block;
3064 break;
3065 }
3066 }
3067 } // if NbBlocks > 1
3068 */
3069
3070 int thisBlock = 0;
3071 for (int block = 1; block <= FastVol.NbBlocks; ++block) {
3072 double blkBtmZ = BlkCrnrZ[block] - CornerZ; // since CornerZ has been
3073 double blkTopZ = blkBtmZ + BlkLZ[block]; // subtracted from dz already
3074 if (dbgFn) {
3075 printf("block, dz, blkBtmZ, blkTopZ: %d, %lg, %lg, %lg\n", block, dz,
3076 blkBtmZ, blkTopZ);
3077 }
3078
3079 // take care of difficult situations
3080 if ((dz <= blkBtmZ) && ((blkBtmZ - dz) < MINDIST)) dz = blkBtmZ - MINDIST;
3081 if ((dz >= blkBtmZ) && ((dz - blkBtmZ) < MINDIST)) dz = blkBtmZ + MINDIST;
3082 if ((dz <= blkTopZ) && ((blkTopZ - dz) < MINDIST)) dz = blkTopZ - MINDIST;
3083 if ((dz >= blkTopZ) && ((dz - blkTopZ) < MINDIST)) dz = blkTopZ + MINDIST;
3084
3085 if ((dz >= blkBtmZ) && (dz <= blkTopZ)) {
3086 thisBlock = block;
3087 break;
3088 }
3089 }
3090 if (!thisBlock) {
3091 neBEMMessage("FastPFAtPoint: point in none of the blocks!\n");
3092 }
3093
3094 int nbXCells = BlkNbXCells[thisBlock];
3095 int nbYCells = BlkNbYCells[thisBlock];
3096 int nbZCells = BlkNbZCells[thisBlock];
3097 double delX = FastVol.LX / nbXCells;
3098 double delY = FastVol.LY / nbYCells;
3099 double delZ = BlkLZ[thisBlock] / nbZCells;
3100 dz -= (BlkCrnrZ[thisBlock] - CornerZ); // distance from the block corner
3101
3102 if (dbgFn) {
3103 printf("thisBlock: %d\n", thisBlock);
3104 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
3105 nbZCells);
3106 printf("BlkCrnrZ: %lg\n", BlkCrnrZ[thisBlock]);
3107 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
3108 printf("dz: %lg\n", dz);
3109 fflush(stdout);
3110 }
3111
3112 // Find cell in block of basic / staggered volume within which the point lies
3113 int celli = (int)(dx / delX) + 1; // Find cell in which the point lies
3114 if (celli < 1) {
3115 celli = 1;
3116 dx = 0.5 * delX;
3117 neBEMMessage("FastPFAtPoint - celli < 1\n");
3118 }
3119 if (celli > nbXCells) {
3120 celli = nbXCells;
3121 dx = FastVol.LX - 0.5 * delX;
3122 neBEMMessage("FastPFAtPoint - celli > nbXCells\n");
3123 }
3124 int cellj = (int)(dy / delY) + 1;
3125 if (cellj < 1) {
3126 cellj = 1;
3127 dy = 0.5 * delY;
3128 neBEMMessage("FastPFAtPoint - cellj < 1\n");
3129 }
3130 if (cellj > nbYCells) {
3131 cellj = nbYCells;
3132 dy = FastVol.LY - 0.5 * delY;
3133 neBEMMessage("FastPFAtPoint - cellj > nbYCells\n");
3134 }
3135 int cellk = (int)(dz / delZ) + 1;
3136 if (cellk < 1) {
3137 cellk = 1;
3138 dz = 0.5 * delX;
3139 neBEMMessage("FastPFAtPoint - cellk < 1\n");
3140 }
3141 if (cellk > nbZCells) {
3142 cellk = nbZCells;
3143 dz = FastVol.LZ - 0.5 * delZ;
3144 neBEMMessage("FastPFAtPoint - cellk > nbZCells\n");
3145 }
3146 if (dbgFn) printf("Cells in x, y, z: %d, %d, %d\n", celli, cellj, cellk);
3147
3148 // Interpolate potential and field at the point using the corner values of
3149 // of the cell and, if necessary, of the neighbouring cells
3150 // These gradients can also be calculated while computing the potential and
3151 // field at the cells and stored in memory, provided enough memory is
3152 // available
3153
3154 // distances from cell corner
3155 double dxcellcrnr = dx - (double)(celli - 1) * delX;
3156 double dycellcrnr = dy - (double)(cellj - 1) * delY;
3157 double dzcellcrnr = dz - (double)(cellk - 1) * delZ;
3158 if (dbgFn)
3159 printf("cell crnr dx, dy, dz: %g, %g, %g\n", dxcellcrnr, dycellcrnr,
3160 dzcellcrnr);
3161
3162 // normalized distances
3163 double xd = dxcellcrnr / delX; // xd = (x-x0)/(x1-x0)
3164 double yd = dycellcrnr / delY; // etc
3165 double zd = dzcellcrnr / delZ;
3166 if (xd <= 0.0) xd = 0.0;
3167 if (yd <= 0.0) yd = 0.0;
3168 if (zd <= 0.0) zd = 0.0;
3169 if (xd >= 1.0) xd = 1.0;
3170 if (yd >= 1.0) yd = 1.0;
3171 if (zd >= 1.0) zd = 1.0;
3172
3173 // corner values of potential and field
3174 double P000 = FastPot[thisBlock][celli][cellj][cellk]; // lowest corner
3175 double FX000 = FastFX[thisBlock][celli][cellj][cellk];
3176 double FY000 = FastFY[thisBlock][celli][cellj][cellk];
3177 double FZ000 = FastFZ[thisBlock][celli][cellj][cellk];
3178 double P100 = FastPot[thisBlock][celli + 1][cellj][cellk];
3179 double FX100 = FastFX[thisBlock][celli + 1][cellj][cellk];
3180 double FY100 = FastFY[thisBlock][celli + 1][cellj][cellk];
3181 double FZ100 = FastFZ[thisBlock][celli + 1][cellj][cellk];
3182 double P010 = FastPot[thisBlock][celli][cellj + 1][cellk];
3183 double FX010 = FastFX[thisBlock][celli][cellj + 1][cellk];
3184 double FY010 = FastFY[thisBlock][celli][cellj + 1][cellk];
3185 double FZ010 = FastFZ[thisBlock][celli][cellj + 1][cellk];
3186 double P001 = FastPot[thisBlock][celli][cellj][cellk + 1];
3187 double FX001 = FastFX[thisBlock][celli][cellj][cellk + 1];
3188 double FY001 = FastFY[thisBlock][celli][cellj][cellk + 1];
3189 double FZ001 = FastFZ[thisBlock][celli][cellj][cellk + 1];
3190 double P110 = FastPot[thisBlock][celli + 1][cellj + 1][cellk];
3191 double FX110 = FastFX[thisBlock][celli + 1][cellj + 1][cellk];
3192 double FY110 = FastFY[thisBlock][celli + 1][cellj + 1][cellk];
3193 double FZ110 = FastFZ[thisBlock][celli + 1][cellj + 1][cellk];
3194 double P101 = FastPot[thisBlock][celli + 1][cellj][cellk + 1];
3195 double FX101 = FastFX[thisBlock][celli + 1][cellj][cellk + 1];
3196 double FY101 = FastFY[thisBlock][celli + 1][cellj][cellk + 1];
3197 double FZ101 = FastFZ[thisBlock][celli + 1][cellj][cellk + 1];
3198 double P011 = FastPot[thisBlock][celli][cellj + 1][cellk + 1];
3199 double FX011 = FastFX[thisBlock][celli][cellj + 1][cellk + 1];
3200 double FY011 = FastFY[thisBlock][celli][cellj + 1][cellk + 1];
3201 double FZ011 = FastFZ[thisBlock][celli][cellj + 1][cellk + 1];
3202 double P111 = FastPot[thisBlock][celli + 1][cellj + 1][cellk + 1];
3203 double FX111 = FastFX[thisBlock][celli + 1][cellj + 1][cellk + 1];
3204 double FY111 = FastFY[thisBlock][celli + 1][cellj + 1][cellk + 1];
3205 double FZ111 = FastFZ[thisBlock][celli + 1][cellj + 1][cellk + 1];
3206 if (OptStaggerFastVol) {
3207 if (sector == 1) { // nothing to be done
3208 }
3209 if (sector == 2) { // volume shifted up but point not in the staggered part
3210 }
3211 if (sector == 3) { // staggered volume
3212 P000 = FastStgPot[thisBlock][celli][cellj][cellk];
3213 FX000 = FastStgFX[thisBlock][celli][cellj][cellk];
3214 FY000 = FastStgFY[thisBlock][celli][cellj][cellk];
3215 FZ000 = FastStgFZ[thisBlock][celli][cellj][cellk];
3216 P100 = FastStgPot[thisBlock][celli + 1][cellj][cellk];
3217 FX100 = FastStgFX[thisBlock][celli + 1][cellj][cellk];
3218 FY100 = FastStgFY[thisBlock][celli + 1][cellj][cellk];
3219 FZ100 = FastStgFZ[thisBlock][celli + 1][cellj][cellk];
3220 P010 = FastStgPot[thisBlock][celli][cellj + 1][cellk];
3221 FX010 = FastStgFX[thisBlock][celli][cellj + 1][cellk];
3222 FY010 = FastStgFY[thisBlock][celli][cellj + 1][cellk];
3223 FZ010 = FastStgFZ[thisBlock][celli][cellj + 1][cellk];
3224 P001 = FastStgPot[thisBlock][celli][cellj][cellk + 1];
3225 FX001 = FastStgFX[thisBlock][celli][cellj][cellk + 1];
3226 FY001 = FastStgFY[thisBlock][celli][cellj][cellk + 1];
3227 FZ001 = FastStgFZ[thisBlock][celli][cellj][cellk + 1];
3228 P110 = FastStgPot[thisBlock][celli + 1][cellj + 1][cellk];
3229 FX110 = FastStgFX[thisBlock][celli + 1][cellj + 1][cellk];
3230 FY110 = FastStgFY[thisBlock][celli + 1][cellj + 1][cellk];
3231 FZ110 = FastStgFZ[thisBlock][celli + 1][cellj + 1][cellk];
3232 P101 = FastStgPot[thisBlock][celli + 1][cellj][cellk + 1];
3233 FX101 = FastStgFX[thisBlock][celli + 1][cellj][cellk + 1];
3234 FY101 = FastStgFY[thisBlock][celli + 1][cellj][cellk + 1];
3235 FZ101 = FastStgFZ[thisBlock][celli + 1][cellj][cellk + 1];
3236 P011 = FastStgPot[thisBlock][celli][cellj + 1][cellk + 1];
3237 FX011 = FastStgFX[thisBlock][celli][cellj + 1][cellk + 1];
3238 FY011 = FastStgFY[thisBlock][celli][cellj + 1][cellk + 1];
3239 FZ011 = FastStgFZ[thisBlock][celli][cellj + 1][cellk + 1];
3240 P111 = FastStgPot[thisBlock][celli + 1][cellj + 1][cellk + 1];
3241 FX111 = FastStgFX[thisBlock][celli + 1][cellj + 1][cellk + 1];
3242 FY111 = FastStgFY[thisBlock][celli + 1][cellj + 1][cellk + 1];
3243 FZ111 = FastStgFZ[thisBlock][celli + 1][cellj + 1][cellk + 1];
3244 }
3245 if (sector == 4) { // volume shifted down and point in the staggered part
3246 P000 = FastStgPot[thisBlock][celli][cellj][cellk];
3247 FX000 = FastStgFX[thisBlock][celli][cellj][cellk];
3248 FY000 = FastStgFY[thisBlock][celli][cellj][cellk];
3249 FZ000 = FastStgFZ[thisBlock][celli][cellj][cellk];
3250 P100 = FastStgPot[thisBlock][celli + 1][cellj][cellk];
3251 FX100 = FastStgFX[thisBlock][celli + 1][cellj][cellk];
3252 FY100 = FastStgFY[thisBlock][celli + 1][cellj][cellk];
3253 FZ100 = FastStgFZ[thisBlock][celli + 1][cellj][cellk];
3254 P010 = FastStgPot[thisBlock][celli][cellj + 1][cellk];
3255 FX010 = FastStgFX[thisBlock][celli][cellj + 1][cellk];
3256 FY010 = FastStgFY[thisBlock][celli][cellj + 1][cellk];
3257 FZ010 = FastStgFZ[thisBlock][celli][cellj + 1][cellk];
3258 P001 = FastStgPot[thisBlock][celli][cellj][cellk + 1];
3259 FX001 = FastStgFX[thisBlock][celli][cellj][cellk + 1];
3260 FY001 = FastStgFY[thisBlock][celli][cellj][cellk + 1];
3261 FZ001 = FastStgFZ[thisBlock][celli][cellj][cellk + 1];
3262 P110 = FastStgPot[thisBlock][celli + 1][cellj + 1][cellk];
3263 FX110 = FastStgFX[thisBlock][celli + 1][cellj + 1][cellk];
3264 FY110 = FastStgFY[thisBlock][celli + 1][cellj + 1][cellk];
3265 FZ110 = FastStgFZ[thisBlock][celli + 1][cellj + 1][cellk];
3266 P101 = FastStgPot[thisBlock][celli + 1][cellj][cellk + 1];
3267 FX101 = FastStgFX[thisBlock][celli + 1][cellj][cellk + 1];
3268 FY101 = FastStgFY[thisBlock][celli + 1][cellj][cellk + 1];
3269 FZ101 = FastStgFZ[thisBlock][celli + 1][cellj][cellk + 1];
3270 P011 = FastStgPot[thisBlock][celli][cellj + 1][cellk + 1];
3271 FX011 = FastStgFX[thisBlock][celli][cellj + 1][cellk + 1];
3272 FY011 = FastStgFY[thisBlock][celli][cellj + 1][cellk + 1];
3273 FZ011 = FastStgFZ[thisBlock][celli][cellj + 1][cellk + 1];
3274 P111 = FastStgPot[thisBlock][celli + 1][cellj + 1][cellk + 1];
3275 FX111 = FastStgFX[thisBlock][celli + 1][cellj + 1][cellk + 1];
3276 FY111 = FastStgFY[thisBlock][celli + 1][cellj + 1][cellk + 1];
3277 FZ111 = FastStgFZ[thisBlock][celli + 1][cellj + 1][cellk + 1];
3278 }
3279 } // if OptStaggerFastVol
3280
3281 double intP =
3282 TriLin(xd, yd, zd, P000, P100, P010, P001, P110, P101, P011, P111);
3283 double intFX = TriLin(xd, yd, zd, FX000, FX100, FX010, FX001, FX110, FX101,
3284 FX011, FX111);
3285 double intFY = TriLin(xd, yd, zd, FY000, FY100, FY010, FY001, FY110, FY101,
3286 FY011, FY111);
3287 double intFZ = TriLin(xd, yd, zd, FZ000, FZ100, FZ010, FZ001, FZ110, FZ101,
3288 FZ011, FZ111);
3289
3290 *Potential = intP;
3291 globalF->X = intFX;
3292 globalF->Y = intFY;
3293 globalF->Z = intFZ;
3294
3295 if (dbgFn) {
3296 printf("Cell corner values:\n");
3297 printf("Potential: %g, %g, %g, %g\n", P000, P100, P010, P001);
3298 printf("Potential: %g, %g, %g, %g\n", P110, P101, P011, P111);
3299 printf("FastFX: %g, %g, %g, %g\n", FX000, FX100, FX010, FX001);
3300 printf("FastFX: %g, %g, %g, %g\n", FX110, FX101, FX011, FX111);
3301 printf("FastFY: %g, %g, %g, %g\n", FY000, FY100, FY010, FY001);
3302 printf("FastFY: %g, %g, %g, %g\n", FY110, FY101, FY011, FY111);
3303 printf("FastFZ: %g, %g, %g, %g\n", FZ000, FZ100, FZ010, FZ001);
3304 printf("FastFZ: %g, %g, %g, %g\n", FZ110, FZ101, FZ011, FZ111);
3305 printf("Pot, FX, FY, FZ: %g, %g, %g, %g\n", *Potential, globalF->X,
3306 globalF->Y, globalF->Z);
3307 }
3308
3309 if (dbgFn) {
3310 printf("out FastPFAtPoint\n");
3311 fflush(stdout);
3312 }
3313
3314 return 0;
3315} // FastPFAtPoint ends
3316
3317// There could be a function
3318int FastElePFAtPoint(Point3D* /*globalP*/, double* /*Potential*/,
3319 Vector3D* /*globalF*/) {
3320 return 0;
3321} // FastElePFAtPoint ends
3322
3323// Gives three components of the total Potential and flux in the global
3324// coordinate system due to all the known charges using the results stored in
3325// the FAST volume KnCh mesh.
3326int FastKnChPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF) {
3327 int dbgFn = 0;
3328 double Xpt = globalP->X;
3329 double Ypt = globalP->Y;
3330 double Zpt = globalP->Z;
3331 double RptVolLX = FastVol.LX;
3332 double RptVolLY = FastVol.LY;
3333 double RptVolLZ = FastVol.LZ;
3334 double CornerX = FastVol.CrnrX;
3335 double CornerY = FastVol.CrnrY;
3336 double CornerZ = FastVol.CrnrZ;
3337 double TriLin(double xd, double yd, double zd, double c000, double c100,
3338 double c010, double c001, double c110, double c101, double c011,
3339 double c111);
3340
3341 // First of all, check how the point in question should be treated ...
3342
3343 // Check whether the point falls within a volume that is not regarded as
3344 // FastVol
3345 for (int ignore = 1; ignore <= FastVol.NbIgnoreVols; ++ignore) {
3346 if ((Xpt >= (IgnoreVolCrnrX[ignore])) &&
3347 (Xpt <= (IgnoreVolCrnrX[ignore] + IgnoreVolLX[ignore])) &&
3348 (Ypt >= (IgnoreVolCrnrY[ignore])) &&
3349 (Ypt <= (IgnoreVolCrnrY[ignore] + IgnoreVolLY[ignore])) &&
3350 (Zpt >= (IgnoreVolCrnrZ[ignore])) &&
3351 (Zpt <= (IgnoreVolCrnrZ[ignore] + IgnoreVolLZ[ignore]))) {
3352 if (dbgFn)
3353 neBEMMessage("In FastKnChPFAtPoint: point in an ignored volume!\n");
3354
3355 int fstatus = KnChPFAtPoint(globalP, Potential, globalF);
3356 if (fstatus != 0) {
3357 neBEMMessage("wrong KnChPFAtPoint return value in FastVolKnChPF.\n");
3358 return -1;
3359 } else
3360 return 0;
3361 }
3362 } // loop over ignored volumes
3363
3364 // If not ignored, the point qualifies for FastVol evaluation ...
3365
3366 // for a staggered fast volume, the volume repeated in X is larger
3367 if (OptStaggerFastVol) {
3368 RptVolLX += FastVol.LX;
3369 }
3370 if (dbgFn) {
3371 printf("\nin FastKnChPFAtPoint\n");
3372 printf("x, y, z: %g, %g, %g\n", Xpt, Ypt, Zpt);
3373 printf("RptVolLX, RptVolLY, RptVolLZ: %g, %g, %g\n", RptVolLX, RptVolLY,
3374 RptVolLZ);
3375 printf("CornerX, CornerY, CornerZ: %g, %g, %g\n", CornerX, CornerY,
3376 CornerZ);
3377 printf("Nb of blocks: %d\n", FastVol.NbBlocks);
3378 for (int block = 1; block <= FastVol.NbBlocks; ++block) {
3379 printf("NbOfXCells: %d\n", BlkNbXCells[block]);
3380 printf("NbOfYCells: %d\n", BlkNbYCells[block]);
3381 printf("NbOfZCells: %d\n", BlkNbZCells[block]);
3382 printf("LZ: %le\n", BlkLZ[block]);
3383 printf("CornerZ: %le\n", BlkCrnrZ[block]);
3384 }
3385 }
3386
3387 // Find equivalent position inside the basic / staggered volume.
3388 // real distance from volume corner
3389 double dx = Xpt - CornerX;
3390 double dy = Ypt - CornerY;
3391 double dz = Zpt - CornerZ;
3392 if (dbgFn)
3393 printf("real dx, dy, dz from volume corner: %g, %g, %g\n", dx, dy, dz);
3394
3395 int NbFastVolX = (int)(dx / RptVolLX);
3396 if (dx < 0.0) --NbFastVolX;
3397 int NbFastVolY = (int)(dy / RptVolLY);
3398 if (dy < 0.0) --NbFastVolY;
3399 int NbFastVolZ = (int)(dz / RptVolLZ);
3400 if (dz < 0.0) --NbFastVolZ;
3401 if (dbgFn)
3402 printf("Volumes in x, y, z: %d, %d, %d\n", NbFastVolX, NbFastVolY,
3403 NbFastVolZ);
3404
3405 // equivalent distances from fast volume corner
3406 dx -= NbFastVolX * RptVolLX;
3407 dy -= NbFastVolY * RptVolLY;
3408 dz -= NbFastVolZ * RptVolLZ;
3409 // The following conditions should never happen - generate an error message
3410 if (dx < 0.0) {
3411 dx = 0.0;
3412 neBEMMessage("equiv dx < 0.0 - not correct!\n");
3413 }
3414 if (dy < 0.0) {
3415 dy = 0.0;
3416 neBEMMessage("equiv dy < 0.0 - not correct!\n");
3417 }
3418 if (dz < 0.0) {
3419 dz = 0.0;
3420 neBEMMessage("equiv dz < 0.0 - not correct!\n");
3421 }
3422 if (dx > RptVolLX) {
3423 dx = RptVolLX;
3424 neBEMMessage("equiv dx > RptVolLX - not correct!\n");
3425 }
3426 if (dy > RptVolLY) {
3427 dy = RptVolLY;
3428 neBEMMessage("equiv dy > RptVolLY - not correct!\n");
3429 }
3430 if (dz > RptVolLZ) {
3431 dz = RptVolLZ;
3432 neBEMMessage("equiv dz > RptVolLZ - not correct!\n");
3433 }
3434 if (dbgFn)
3435 printf("equivalent dist from corner - dx, dy, dz: %g, %g, %g\n", dx, dy,
3436 dz);
3437
3438 // Take care of possible trouble-makers
3439 if (dx < MINDIST) dx = MINDIST; // -ve dx has already been made equal to 0
3440 if (dy < MINDIST) dy = MINDIST;
3441 if (dz < MINDIST) dz = MINDIST;
3442 if ((RptVolLX - dx) < MINDIST)
3443 dx = RptVolLX - MINDIST; // dx > RptVolLX taken care of
3444 if ((RptVolLY - dy) < MINDIST) dy = RptVolLY - MINDIST;
3445 if ((RptVolLZ - dz) < MINDIST) dz = RptVolLZ - MINDIST;
3446 // For staggered volumes, there is another plane where difficulties may occur
3447 if ((dx <= FastVol.LX) && (FastVol.LX - dx) < MINDIST)
3448 dx = FastVol.LX - MINDIST;
3449 // else if((dx > FastVol.LX) && (fabs(FastVol.LX-dx) < MINDIST))
3450 else if ((dx > FastVol.LX) && (dx - FastVol.LX) < MINDIST) // more inttuitive
3451 dx = FastVol.LX + MINDIST;
3452 if (dbgFn)
3453 printf("equivalent dist adjusted - dx, dy, dz: %g, %g, %g\n", dx, dy, dz);
3454
3455 // If volume is staggered, we have a few more things to do before finalizing
3456 // the values of equivalent distance
3457 // sector identification
3458 // _................__________________
3459 // | . . | Sector 3 |
3460 // | . . | |
3461 // | . | . |
3462 // | | . . |
3463 // | Sector 2 | . . |
3464 // |----------------| . . |
3465 // | | . |
3466 // | . | |
3467 // | . . | |
3468 // | . . |----------------|
3469 // | . . | Sector 4 |
3470 // | . | . |
3471 // | | . . |
3472 // | Sector 1 | . . |
3473 // |----------------|................|
3474
3475 int sector = 1; // kept outside `if' since this is necessary further below
3476 if (OptStaggerFastVol) {
3477 if ((dx >= 0.0) && (dx <= FastVol.LX) && (dy >= 0.0) &&
3478 (dy <= FastVol.LY)) {
3479 // point lies in sector 1, everything remains unchanged
3480 sector = 1;
3481 } else if ((dx >= 0.0) && (dx <= FastVol.LX) && (dy > FastVol.LY) &&
3482 (dy <= FastVol.LY + FastVol.YStagger)) {
3483 // point lies in sector 2, move basic volume one step up
3484 sector = 2;
3485 ++NbFastVolY;
3486 CornerY += FastVol.LY; // repeat length in Y is LY
3487 dy -= FastVol.LY;
3488 } else if ((dx > FastVol.LX) && (dx <= 2.0 * FastVol.LX) &&
3489 (dy >= FastVol.YStagger) &&
3490 (dy <= FastVol.LY + FastVol.YStagger)) {
3491 // point lies in sector 3, pt in staggered vol, change corner coords
3492 sector = 3;
3493 CornerX += FastVol.LX;
3494 CornerY += FastVol.YStagger;
3495 dx -= FastVol.LX;
3496 dy -= FastVol.YStagger;
3497 } else if ((dx > FastVol.LX) && (dx <= 2.0 * FastVol.LX) && (dy >= 0.0) &&
3498 (dy < FastVol.YStagger)) {
3499 // point lies in sector 4, move basic volume one step down and consider
3500 // staggered fast volume
3501 sector = 4;
3502 --NbFastVolY;
3503 CornerX += FastVol.LX; // in the staggered part of the repeated volume
3504 CornerY -= (FastVol.LY - FastVol.YStagger);
3505 dx -= FastVol.LX;
3506 dy += (FastVol.LY - FastVol.YStagger);
3507 } else {
3508 neBEMMessage("FastKnChPFAtPoint: point in none of the sectors!\n");
3509 }
3510 if (dbgFn) printf("stagger modified dx, dy, dz: %g, %g, %g\n", dx, dy, dz);
3511 }
3512
3513 // Take care of possible trouble-makers - once more
3514 if (dx < MINDIST) dx = MINDIST; // -ve dx has already been made equal to 0
3515 if (dy < MINDIST) dy = MINDIST;
3516 if (dz < MINDIST) dz = MINDIST;
3517 if ((RptVolLX - dx) < MINDIST)
3518 dx = RptVolLX - MINDIST; // dx > RptVolLX taken care of
3519 if ((RptVolLY - dy) < MINDIST) dy = RptVolLY - MINDIST;
3520 if ((RptVolLZ - dz) < MINDIST) dz = RptVolLZ - MINDIST;
3521 // For staggered volumes, there is another plane where difficulties may occur
3522 if ((dx <= FastVol.LX) && (FastVol.LX - dx) < MINDIST)
3523 dx = FastVol.LX - MINDIST;
3524 // else if((dx > FastVol.LX) && (fabs(FastVol.LX-dx) < MINDIST))
3525 else if ((dx > FastVol.LX) && (dx - FastVol.LX) < MINDIST) // more intuitive
3526 dx = FastVol.LX + MINDIST;
3527 if (dbgFn)
3528 printf("equivalent dist adjusted for staggered: %g, %g, %g\n", dx, dy, dz);
3529
3530 /*
3531 // Check whether the point falls within a volume that is omitted
3532 for(int omit = 1; omit <= FastVol.NbOmitVols; ++omit)
3533 {
3534 if((dx >= (OmitVolCrnrX[omit]-FastVol.CrnrX))
3535 && (dx <=
3536 (OmitVolCrnrX[omit]+OmitVolLX[omit]-FastVol.CrnrX))
3537 && (dy >= (OmitVolCrnrY[omit]-FastVol.CrnrY))
3538 && (dy <=
3539 (OmitVolCrnrY[omit]+OmitVolLY[omit]-FastVol.CrnrY))
3540 && (dz >= (OmitVolCrnrZ[omit]-FastVol.CrnrZ))
3541 && (dz <=
3542 (OmitVolCrnrZ[omit]+OmitVolLZ[omit]-FastVol.CrnrZ)))
3543 {
3544 neBEMMessage("In FastKnChPFAtPoint: point in an omitted
3545 volume!\n"); *Potential = 0.0; globalF->X = 0.0; globalF->Y = 0.0; globalF->Z
3546 = 0.0;
3547 }
3548 } // loop over omitted volumes
3549
3550 // Find the block in which the point lies
3551 int thisBlock = 1;
3552 if(FastVol.NbBlocks > 1)
3553 {
3554 for(int block = 1; block <= FastVol.NbBlocks; ++block)
3555 {
3556 if(dbgFn)
3557 {
3558 printf("dz,(BlkCrnrZ-CornerZ),(BlkCrnrZ+BlkLZ-CornerZ):
3559 %lg, %lg, %lg\n", dz, (BlkCrnrZ[block]-CornerZ),
3560 (BlkCrnrZ[block]+BlkLZ[block]-CornerZ));
3561 }
3562 if((dz >= (BlkCrnrZ[block]-CornerZ))
3563 && (dz <=
3564 (BlkCrnrZ[block]+BlkLZ[block]-CornerZ)))
3565 {
3566 thisBlock = block;
3567 break;
3568 }
3569 }
3570 } // if NbBlocks > 1
3571 */
3572
3573 int thisBlock = 0;
3574 for (int block = 1; block <= FastVol.NbBlocks; ++block) {
3575 double blkBtmZ = BlkCrnrZ[block] - CornerZ; // since CornerZ has been
3576 double blkTopZ = blkBtmZ + BlkLZ[block]; // subtracted from dz already
3577 if (dbgFn) {
3578 printf("block, dz, blkBtmZ, blkTopZ: %d, %lg, %lg, %lg\n", block, dz,
3579 blkBtmZ, blkTopZ);
3580 }
3581
3582 // take care of difficult situations
3583 if ((dz <= blkBtmZ) && ((blkBtmZ - dz) < MINDIST)) dz = blkBtmZ - MINDIST;
3584 if ((dz >= blkBtmZ) && ((dz - blkBtmZ) < MINDIST)) dz = blkBtmZ + MINDIST;
3585 if ((dz <= blkTopZ) && ((blkTopZ - dz) < MINDIST)) dz = blkTopZ - MINDIST;
3586 if ((dz >= blkTopZ) && ((dz - blkTopZ) < MINDIST)) dz = blkTopZ + MINDIST;
3587
3588 if ((dz >= blkBtmZ) && (dz <= blkTopZ)) {
3589 thisBlock = block;
3590 break;
3591 }
3592 }
3593 if (!thisBlock) {
3594 neBEMMessage("FastKnChPFAtPoint: point in none of the blocks!\n");
3595 }
3596
3597 int nbXCells = BlkNbXCells[thisBlock];
3598 int nbYCells = BlkNbYCells[thisBlock];
3599 int nbZCells = BlkNbZCells[thisBlock];
3600 double delX = FastVol.LX / nbXCells;
3601 double delY = FastVol.LY / nbYCells;
3602 double delZ = BlkLZ[thisBlock] / nbZCells;
3603 dz -= (BlkCrnrZ[thisBlock] - CornerZ); // distance from the block corner
3604
3605 if (dbgFn) {
3606 printf("thisBlock: %d\n", thisBlock);
3607 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
3608 nbZCells);
3609 printf("BlkCrnrZ: %lg\n", BlkCrnrZ[thisBlock]);
3610 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
3611 printf("dz: %lg\n", dz);
3612 fflush(stdout);
3613 }
3614
3615 // Find cell in block of basic / staggered volume within which the point lies
3616 int celli = (int)(dx / delX) + 1; // Find cell in which the point lies
3617 if (celli < 1) {
3618 celli = 1;
3619 dx = 0.5 * delX;
3620 neBEMMessage("FastKnChPFAtPoint - celli < 1\n");
3621 }
3622 if (celli > nbXCells) {
3623 celli = nbXCells;
3624 dx = FastVol.LX - 0.5 * delX;
3625 neBEMMessage("FastKnChPFAtPoint - celli > nbXCells\n");
3626 }
3627 int cellj = (int)(dy / delY) + 1;
3628 if (cellj < 1) {
3629 cellj = 1;
3630 dy = 0.5 * delY;
3631 neBEMMessage("FastKnChPFAtPoint - cellj < 1\n");
3632 }
3633 if (cellj > nbYCells) {
3634 cellj = nbYCells;
3635 dy = FastVol.LY - 0.5 * delY;
3636 neBEMMessage("FastKnChPFAtPoint - cellj > nbYCells\n");
3637 }
3638 int cellk = (int)(dz / delZ) + 1;
3639 if (cellk < 1) {
3640 cellk = 1;
3641 dz = 0.5 * delX;
3642 neBEMMessage("FastKnChPFAtPoint - cellk < 1\n");
3643 }
3644 if (cellk > nbZCells) {
3645 cellk = nbZCells;
3646 dz = FastVol.LZ - 0.5 * delZ;
3647 neBEMMessage("FastKnChPFAtPoint - cellk > nbZCells\n");
3648 }
3649 if (dbgFn) printf("Cells in x, y, z: %d, %d, %d\n", celli, cellj, cellk);
3650
3651 // Interpolate potential and field at the point using the corner values of
3652 // of the cell and, if necessary, of the neighbouring cells
3653 // These gradients can also be calculated while computing the potential and
3654 // field at the cells and stored in memory, provided enough memory is
3655 // available
3656
3657 // distances from cell corner
3658 double dxcellcrnr = dx - (double)(celli - 1) * delX;
3659 double dycellcrnr = dy - (double)(cellj - 1) * delY;
3660 double dzcellcrnr = dz - (double)(cellk - 1) * delZ;
3661 if (dbgFn)
3662 printf("cell crnr dx, dy, dz: %g, %g, %g\n", dxcellcrnr, dycellcrnr,
3663 dzcellcrnr);
3664
3665 // normalized distances
3666 double xd = dxcellcrnr / delX; // xd = (x-x0)/(x1-x0)
3667 double yd = dycellcrnr / delY; // etc
3668 double zd = dzcellcrnr / delZ;
3669 if (xd <= 0.0) xd = 0.0;
3670 if (yd <= 0.0) yd = 0.0;
3671 if (zd <= 0.0) zd = 0.0;
3672 if (xd >= 1.0) xd = 1.0;
3673 if (yd >= 1.0) yd = 1.0;
3674 if (zd >= 1.0) zd = 1.0;
3675
3676 // corner values of potential and field
3677 double P000 = FastPotKnCh[thisBlock][celli][cellj][cellk]; // lowest corner
3678 double FX000 = FastFXKnCh[thisBlock][celli][cellj][cellk];
3679 double FY000 = FastFYKnCh[thisBlock][celli][cellj][cellk];
3680 double FZ000 = FastFZKnCh[thisBlock][celli][cellj][cellk];
3681 double P100 = FastPotKnCh[thisBlock][celli + 1][cellj][cellk];
3682 double FX100 = FastFXKnCh[thisBlock][celli + 1][cellj][cellk];
3683 double FY100 = FastFYKnCh[thisBlock][celli + 1][cellj][cellk];
3684 double FZ100 = FastFZKnCh[thisBlock][celli + 1][cellj][cellk];
3685 double P010 = FastPotKnCh[thisBlock][celli][cellj + 1][cellk];
3686 double FX010 = FastFXKnCh[thisBlock][celli][cellj + 1][cellk];
3687 double FY010 = FastFYKnCh[thisBlock][celli][cellj + 1][cellk];
3688 double FZ010 = FastFZKnCh[thisBlock][celli][cellj + 1][cellk];
3689 double P001 = FastPotKnCh[thisBlock][celli][cellj][cellk + 1];
3690 double FX001 = FastFXKnCh[thisBlock][celli][cellj][cellk + 1];
3691 double FY001 = FastFYKnCh[thisBlock][celli][cellj][cellk + 1];
3692 double FZ001 = FastFZKnCh[thisBlock][celli][cellj][cellk + 1];
3693 double P110 = FastPotKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3694 double FX110 = FastFXKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3695 double FY110 = FastFYKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3696 double FZ110 = FastFZKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3697 double P101 = FastPotKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3698 double FX101 = FastFXKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3699 double FY101 = FastFYKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3700 double FZ101 = FastFZKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3701 double P011 = FastPotKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3702 double FX011 = FastFXKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3703 double FY011 = FastFYKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3704 double FZ011 = FastFZKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3705 double P111 = FastPotKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3706 double FX111 = FastFXKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3707 double FY111 = FastFYKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3708 double FZ111 = FastFZKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3709 if (OptStaggerFastVol) {
3710 if (sector == 1) { // nothing to be done
3711 }
3712 if (sector == 2) { // volume shifted up but point not in the staggered part
3713 }
3714 if (sector == 3) { // staggered volume
3715 P000 = FastStgPotKnCh[thisBlock][celli][cellj][cellk];
3716 FX000 = FastStgFXKnCh[thisBlock][celli][cellj][cellk];
3717 FY000 = FastStgFYKnCh[thisBlock][celli][cellj][cellk];
3718 FZ000 = FastStgFZKnCh[thisBlock][celli][cellj][cellk];
3719 P100 = FastStgPotKnCh[thisBlock][celli + 1][cellj][cellk];
3720 FX100 = FastStgFXKnCh[thisBlock][celli + 1][cellj][cellk];
3721 FY100 = FastStgFYKnCh[thisBlock][celli + 1][cellj][cellk];
3722 FZ100 = FastStgFZKnCh[thisBlock][celli + 1][cellj][cellk];
3723 P010 = FastStgPotKnCh[thisBlock][celli][cellj + 1][cellk];
3724 FX010 = FastStgFXKnCh[thisBlock][celli][cellj + 1][cellk];
3725 FY010 = FastStgFYKnCh[thisBlock][celli][cellj + 1][cellk];
3726 FZ010 = FastStgFZKnCh[thisBlock][celli][cellj + 1][cellk];
3727 P001 = FastStgPotKnCh[thisBlock][celli][cellj][cellk + 1];
3728 FX001 = FastStgFXKnCh[thisBlock][celli][cellj][cellk + 1];
3729 FY001 = FastStgFYKnCh[thisBlock][celli][cellj][cellk + 1];
3730 FZ001 = FastStgFZKnCh[thisBlock][celli][cellj][cellk + 1];
3731 P110 = FastStgPotKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3732 FX110 = FastStgFXKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3733 FY110 = FastStgFYKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3734 FZ110 = FastStgFZKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3735 P101 = FastStgPotKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3736 FX101 = FastStgFXKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3737 FY101 = FastStgFYKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3738 FZ101 = FastStgFZKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3739 P011 = FastStgPotKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3740 FX011 = FastStgFXKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3741 FY011 = FastStgFYKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3742 FZ011 = FastStgFZKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3743 P111 = FastStgPotKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3744 FX111 = FastStgFXKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3745 FY111 = FastStgFYKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3746 FZ111 = FastStgFZKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3747 }
3748 if (sector == 4) { // volume shifted down and point in the staggered part
3749 P000 = FastStgPotKnCh[thisBlock][celli][cellj][cellk];
3750 FX000 = FastStgFXKnCh[thisBlock][celli][cellj][cellk];
3751 FY000 = FastStgFYKnCh[thisBlock][celli][cellj][cellk];
3752 FZ000 = FastStgFZKnCh[thisBlock][celli][cellj][cellk];
3753 P100 = FastStgPotKnCh[thisBlock][celli + 1][cellj][cellk];
3754 FX100 = FastStgFXKnCh[thisBlock][celli + 1][cellj][cellk];
3755 FY100 = FastStgFYKnCh[thisBlock][celli + 1][cellj][cellk];
3756 FZ100 = FastStgFZKnCh[thisBlock][celli + 1][cellj][cellk];
3757 P010 = FastStgPotKnCh[thisBlock][celli][cellj + 1][cellk];
3758 FX010 = FastStgFXKnCh[thisBlock][celli][cellj + 1][cellk];
3759 FY010 = FastStgFYKnCh[thisBlock][celli][cellj + 1][cellk];
3760 FZ010 = FastStgFZKnCh[thisBlock][celli][cellj + 1][cellk];
3761 P001 = FastStgPotKnCh[thisBlock][celli][cellj][cellk + 1];
3762 FX001 = FastStgFXKnCh[thisBlock][celli][cellj][cellk + 1];
3763 FY001 = FastStgFYKnCh[thisBlock][celli][cellj][cellk + 1];
3764 FZ001 = FastStgFZKnCh[thisBlock][celli][cellj][cellk + 1];
3765 P110 = FastStgPotKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3766 FX110 = FastStgFXKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3767 FY110 = FastStgFYKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3768 FZ110 = FastStgFZKnCh[thisBlock][celli + 1][cellj + 1][cellk];
3769 P101 = FastStgPotKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3770 FX101 = FastStgFXKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3771 FY101 = FastStgFYKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3772 FZ101 = FastStgFZKnCh[thisBlock][celli + 1][cellj][cellk + 1];
3773 P011 = FastStgPotKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3774 FX011 = FastStgFXKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3775 FY011 = FastStgFYKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3776 FZ011 = FastStgFZKnCh[thisBlock][celli][cellj + 1][cellk + 1];
3777 P111 = FastStgPotKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3778 FX111 = FastStgFXKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3779 FY111 = FastStgFYKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3780 FZ111 = FastStgFZKnCh[thisBlock][celli + 1][cellj + 1][cellk + 1];
3781 }
3782 } // if OptStaggerFastVol
3783
3784 double intP =
3785 TriLin(xd, yd, zd, P000, P100, P010, P001, P110, P101, P011, P111);
3786 double intFX = TriLin(xd, yd, zd, FX000, FX100, FX010, FX001, FX110, FX101,
3787 FX011, FX111);
3788 double intFY = TriLin(xd, yd, zd, FY000, FY100, FY010, FY001, FY110, FY101,
3789 FY011, FY111);
3790 double intFZ = TriLin(xd, yd, zd, FZ000, FZ100, FZ010, FZ001, FZ110, FZ101,
3791 FZ011, FZ111);
3792
3793 *Potential = intP;
3794 globalF->X = intFX;
3795 globalF->Y = intFY;
3796 globalF->Z = intFZ;
3797
3798 if (dbgFn) {
3799 printf("Cell corner values:\n");
3800 printf("Potential: %g, %g, %g, %g\n", P000, P100, P010, P001);
3801 printf("Potential: %g, %g, %g, %g\n", P110, P101, P011, P111);
3802 printf("FastFX: %g, %g, %g, %g\n", FX000, FX100, FX010, FX001);
3803 printf("FastFX: %g, %g, %g, %g\n", FX110, FX101, FX011, FX111);
3804 printf("FastFY: %g, %g, %g, %g\n", FY000, FY100, FY010, FY001);
3805 printf("FastFY: %g, %g, %g, %g\n", FY110, FY101, FY011, FY111);
3806 printf("FastFZ: %g, %g, %g, %g\n", FZ000, FZ100, FZ010, FZ001);
3807 printf("FastFZ: %g, %g, %g, %g\n", FZ110, FZ101, FZ011, FZ111);
3808 printf("Pot, FX, FY, FZ: %g, %g, %g, %g\n", *Potential, globalF->X,
3809 globalF->Y, globalF->Z);
3810 }
3811
3812 if (dbgFn) {
3813 printf("out FastKnChPFAtPoint\n");
3814 fflush(stdout);
3815 }
3816
3817 return 0;
3818} // FastKnChPFAtPoint ends
3819
3820// Gives three components of the total Potential and flux in the global
3821// coordinate system due to all the elements using the results stored in
3822// the FAST volume mesh. The Fast volume is generated in the normal manner
3823// but by making necessary changes in the boundary conditions. This Fast
3824// volume is then renamed. The same is true for the data in staggered volume.
3825// These names are provided to the code by the neBEMWtFldFastVol.inp
3826int WtFldFastPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF) {
3827 int dbgFn = 0;
3828 double Xpt = globalP->X;
3829 double Ypt = globalP->Y;
3830 double Zpt = globalP->Z;
3831 double RptVolLX = WtFldFastVol.LX;
3832 double RptVolLY = WtFldFastVol.LY;
3833 double RptVolLZ = WtFldFastVol.LZ;
3834 double CornerX = WtFldFastVol.CrnrX;
3835 double CornerY = WtFldFastVol.CrnrY;
3836 double CornerZ = WtFldFastVol.CrnrZ;
3837 double TriLin(double xd, double yd, double zd, double c000, double c100,
3838 double c010, double c001, double c110, double c101, double c011,
3839 double c111);
3840
3841 // First of all, check how the point in question should be treated ...
3842
3843 // Check whether the point falls within a volume that is not regarded as
3844 // FastVol
3845 for (int ignore = 1; ignore <= WtFldFastVol.NbIgnoreVols; ++ignore) {
3846 if ((Xpt >= (WtFldIgnoreVolCrnrX[ignore])) &&
3847 (Xpt <= (WtFldIgnoreVolCrnrX[ignore] + WtFldIgnoreVolLX[ignore])) &&
3848 (Ypt >= (WtFldIgnoreVolCrnrY[ignore])) &&
3849 (Ypt <= (WtFldIgnoreVolCrnrY[ignore] + WtFldIgnoreVolLY[ignore])) &&
3850 (Zpt >= (WtFldIgnoreVolCrnrZ[ignore])) &&
3851 (Zpt <= (WtFldIgnoreVolCrnrZ[ignore] + WtFldIgnoreVolLZ[ignore]))) {
3852 if (dbgFn)
3853 neBEMMessage("In WtFldFastPFAtPoint: point in an ignored volume!\n");
3854
3855 // KnCh does not have any effect
3856 int fstatus = ElePFAtPoint(globalP, Potential, globalF);
3857 if (fstatus != 0) {
3858 neBEMMessage("wrong WtFldPFAtPoint return value in FastVolPF.\n");
3859 return -1;
3860 } else
3861 return 0;
3862 }
3863 } // loop over ignored volumes
3864
3865 // If not ignored, the point qualifies for FastVol evaluation ...
3866
3867 // for a staggered fast volume, the volume repeated in X is larger
3869 RptVolLX += WtFldFastVol.LX;
3870 }
3871 if (dbgFn) {
3872 printf("\nin WtFldFastPFAtPoint\n");
3873 printf("x, y, z: %g, %g, %g\n", Xpt, Ypt, Zpt);
3874 printf("RptVolLX, RptVolLY, RptVolLZ: %g, %g, %g\n", RptVolLX, RptVolLY,
3875 RptVolLZ);
3876 printf("CornerX, CornerY, CornerZ: %g, %g, %g\n", CornerX, CornerY,
3877 CornerZ);
3878 printf("Nb of blocks: %d\n", WtFldFastVol.NbBlocks);
3879 for (int block = 1; block <= WtFldFastVol.NbBlocks; ++block) {
3880 printf("NbOfXCells: %d\n", WtFldBlkNbXCells[block]);
3881 printf("NbOfYCells: %d\n", WtFldBlkNbYCells[block]);
3882 printf("NbOfZCells: %d\n", WtFldBlkNbZCells[block]);
3883 printf("LZ: %le\n", WtFldBlkLZ[block]);
3884 printf("CornerZ: %le\n", WtFldBlkCrnrZ[block]);
3885 }
3886 }
3887
3888 // Find equivalent position inside the basic / staggered volume.
3889 // real distance from volume corner
3890 double dx = Xpt - CornerX;
3891 double dy = Ypt - CornerY;
3892 double dz = Zpt - CornerZ;
3893 if (dbgFn)
3894 printf("real dx, dy, dz from volume corner: %g, %g, %g\n", dx, dy, dz);
3895
3896 int NbFastVolX = (int)(dx / RptVolLX);
3897 if (dx < 0.0) --NbFastVolX;
3898 int NbFastVolY = (int)(dy / RptVolLY);
3899 if (dy < 0.0) --NbFastVolY;
3900 int NbFastVolZ = (int)(dz / RptVolLZ);
3901 if (dz < 0.0) --NbFastVolZ;
3902 if (dbgFn)
3903 printf("Volumes in x, y, z: %d, %d, %d\n", NbFastVolX, NbFastVolY,
3904 NbFastVolZ);
3905
3906 // equivalent distances from fast volume corner
3907 dx -= NbFastVolX * RptVolLX;
3908 dy -= NbFastVolY * RptVolLY;
3909 dz -= NbFastVolZ * RptVolLZ;
3910 // The following conditions should never happen - generate an error message
3911 if (dx < 0.0) {
3912 dx = 0.0;
3913 neBEMMessage("equiv dx < 0.0 - not correct!\n");
3914 }
3915 if (dy < 0.0) {
3916 dy = 0.0;
3917 neBEMMessage("equiv dy < 0.0 - not correct!\n");
3918 }
3919 if (dz < 0.0) {
3920 dz = 0.0;
3921 neBEMMessage("equiv dz < 0.0 - not correct!\n");
3922 }
3923 if (dx > RptVolLX) {
3924 dx = RptVolLX;
3925 neBEMMessage("equiv dx > RptVolLX - not correct!\n");
3926 }
3927 if (dy > RptVolLY) {
3928 dy = RptVolLY;
3929 neBEMMessage("equiv dy > RptVolLY - not correct!\n");
3930 }
3931 if (dz > RptVolLZ) {
3932 dz = RptVolLZ;
3933 neBEMMessage("equiv dz > RptVolLZ - not correct!\n");
3934 }
3935 if (dbgFn)
3936 printf("equivalent dist from corner - dx, dy, dz: %g, %g, %g\n", dx, dy,
3937 dz);
3938
3939 // Take care of possible trouble-makers
3940 if (dx < MINDIST) dx = MINDIST; // -ve dx has already been made equal to 0
3941 if (dy < MINDIST) dy = MINDIST;
3942 if (dz < MINDIST) dz = MINDIST;
3943 if ((RptVolLX - dx) < MINDIST)
3944 dx = RptVolLX - MINDIST; // dx > RptVolLX taken care of
3945 if ((RptVolLY - dy) < MINDIST) dy = RptVolLY - MINDIST;
3946 if ((RptVolLZ - dz) < MINDIST) dz = RptVolLZ - MINDIST;
3947 // For staggered volumes, there is another plane where difficulties may occur
3948 if ((dx <= WtFldFastVol.LX) && (WtFldFastVol.LX - dx) < MINDIST)
3949 dx = WtFldFastVol.LX - MINDIST;
3950 else if ((dx > WtFldFastVol.LX) && (fabs(WtFldFastVol.LX - dx) < MINDIST))
3951 dx = WtFldFastVol.LX + MINDIST;
3952 if (dbgFn)
3953 printf("equivalent dist adjusted - dx, dy, dz: %g, %g, %g\n", dx, dy, dz);
3954
3955 // If volume is staggered, we have a few more things to do before finalizing
3956 // the values of equivalent distance
3957 // sector identification
3958 // _................__________________
3959 // | . . | Sector 3 |
3960 // | . . | |
3961 // | . | . |
3962 // | | . . |
3963 // | Sector 2 | . . |
3964 // |----------------| . . |
3965 // | | . |
3966 // | . | |
3967 // | . . | |
3968 // | . . |----------------|
3969 // | . . | Sector 4 |
3970 // | . | . |
3971 // | | . . |
3972 // | Sector 1 | . . |
3973 // |----------------|................|
3974
3975 int sector = 1; // kept outside `if' since this is necessary further below
3977 if ((dx >= 0.0) && (dx <= WtFldFastVol.LX) && (dy >= 0.0) &&
3978 (dy <= WtFldFastVol.LY)) {
3979 // point lies in sector 1, everything remains unchanged
3980 sector = 1;
3981 } else if ((dx >= 0.0) && (dx <= WtFldFastVol.LX) &&
3982 (dy > WtFldFastVol.LY) &&
3984 // point lies in sector 2, move basic volume one step up
3985 sector = 2;
3986 ++NbFastVolY;
3987 CornerY += WtFldFastVol.LY; // repeat length in Y is LY
3988 dy -= WtFldFastVol.LY;
3989 } else if ((dx > WtFldFastVol.LX) && (dx <= 2.0 * WtFldFastVol.LX) &&
3990 (dy >= WtFldFastVol.YStagger) &&
3992 // point lies in sector 3, pt in staggered vol, change corner coords
3993 sector = 3;
3994 CornerX += WtFldFastVol.LX;
3995 CornerY += WtFldFastVol.YStagger;
3996 dx -= WtFldFastVol.LX;
3997 dy -= WtFldFastVol.YStagger;
3998 } else if ((dx > WtFldFastVol.LX) && (dx <= 2.0 * WtFldFastVol.LX) &&
3999 (dy >= 0.0) && (dy < WtFldFastVol.YStagger)) {
4000 // point lies in sector 4, move basic volume one step down and consider
4001 // staggered fast volume
4002 sector = 4;
4003 --NbFastVolY;
4004 CornerX +=
4005 WtFldFastVol.LX; // in the staggered part of the repeated volume
4006 CornerY -= (WtFldFastVol.LY - WtFldFastVol.YStagger);
4007 dx -= WtFldFastVol.LX;
4009 } else {
4010 neBEMMessage("WtFldFastPFAtPoint: point in none of the sectors!\n");
4011 }
4012 if (dbgFn) printf("stagger modified dx, dy, dz: %g, %g, %g\n", dx, dy, dz);
4013 }
4014
4015 // Take care of possible trouble-makers - once more
4016 if (dx < MINDIST) dx = MINDIST; // -ve dx has already been made equal to 0
4017 if (dy < MINDIST) dy = MINDIST;
4018 if (dz < MINDIST) dz = MINDIST;
4019 if ((RptVolLX - dx) < MINDIST)
4020 dx = RptVolLX - MINDIST; // dx > RptVolLX taken care of
4021 if ((RptVolLY - dy) < MINDIST) dy = RptVolLY - MINDIST;
4022 if ((RptVolLZ - dz) < MINDIST) dz = RptVolLZ - MINDIST;
4023 // For staggered volumes, there is another plane where difficulties may occur
4024 if ((dx <= WtFldFastVol.LX) && (WtFldFastVol.LX - dx) < MINDIST)
4025 dx = WtFldFastVol.LX - MINDIST;
4026 else if ((dx > WtFldFastVol.LX) && (fabs(WtFldFastVol.LX - dx) < MINDIST))
4027 dx = WtFldFastVol.LX + MINDIST;
4028 if (dbgFn)
4029 printf("equivalent dist adjusted for staggered: %g, %g, %g\n", dx, dy, dz);
4030
4031 /*
4032 // Check whether the point falls within a volume that is omitted
4033 for(int omit = 1; omit <= WtFldFastVol.NbOmitVols; ++omit)
4034 {
4035 if((dx >= (WtFldOmitVolCrnrX[omit]-WtFldFastVol.CrnrX))
4036 && (dx <=
4037 (WtFldOmitVolCrnrX[omit]+WtFldOmitVolLX[omit]-WtFldFastVol.CrnrX))
4038 && (dy >=
4039 (WtFldOmitVolCrnrY[omit]-WtFldFastVol.CrnrY))
4040 && (dy <=
4041 (WtFldOmitVolCrnrY[omit]+WtFldOmitVolLY[omit]-WtFldFastVol.CrnrY))
4042 && (dz >=
4043 (WtFldOmitVolCrnrZ[omit]-WtFldFastVol.CrnrZ))
4044 && (dz <=
4045 (WtFldOmitVolCrnrZ[omit]+WtFldOmitVolLZ[omit]-WtFldFastVol.CrnrZ)))
4046 {
4047 neBEMMessage("In FastPFAtPoint: point in an omitted
4048 volume!\n"); *Potential = 0.0; globalF->X = 0.0; globalF->Y = 0.0; globalF->Z
4049 = 0.0;
4050 }
4051 } // loop over omitted volumes
4052 */
4053
4054 // Find the block in which the point lies
4055 /*
4056 int thisBlock = 1;
4057 if(WtFldFastVol.NbBlocks > 1)
4058 {
4059 for(int block = 1; block <= WtFldFastVol.NbBlocks; ++block)
4060 {
4061 if(dbgFn)
4062 {
4063 printf("dz,(WtFldBlkCrnrZ-CornerZ),(WtFldBlkCrnrZ+WtFldBlkLZ-CornerZ):
4064 %lg, %lg, %lg\n", dz, (WtFldBlkCrnrZ[block]-CornerZ),
4065 (WtFldBlkCrnrZ[block]+WtFldBlkLZ[block]-CornerZ));
4066 }
4067 if((dz >= (WtFldBlkCrnrZ[block]-CornerZ))
4068 && (dz <=
4069 (WtFldBlkCrnrZ[block]+WtFldBlkLZ[block]-CornerZ)))
4070 {
4071 thisBlock = block;
4072 break;
4073 }
4074 }
4075 } // if NbBlocks > 1
4076 */
4077
4078 int thisBlock = 0;
4079 for (int block = 1; block <= WtFldFastVol.NbBlocks; ++block) {
4080 double blkBtmZ = WtFldBlkCrnrZ[block] - CornerZ; // since CornerZ has been
4081 double blkTopZ = blkBtmZ + WtFldBlkLZ[block]; // subtracted from dz already
4082 if (dbgFn) {
4083 printf("block, dz, blkBtmZ, blkTopZ: %d, %lg, %lg, %lg\n", block, dz,
4084 blkBtmZ, blkTopZ);
4085 }
4086
4087 // take care of difficult situations
4088 if ((dz <= blkBtmZ) && ((blkBtmZ - dz) < MINDIST)) dz = blkBtmZ - MINDIST;
4089 if ((dz >= blkBtmZ) && ((dz - blkBtmZ) < MINDIST)) dz = blkBtmZ + MINDIST;
4090 if ((dz <= blkTopZ) && ((blkTopZ - dz) < MINDIST)) dz = blkTopZ - MINDIST;
4091 if ((dz >= blkTopZ) && ((dz - blkTopZ) < MINDIST)) dz = blkTopZ + MINDIST;
4092
4093 if ((dz >= blkBtmZ) && (dz <= blkTopZ)) {
4094 thisBlock = block;
4095 break;
4096 }
4097 }
4098 if (!thisBlock) {
4099 neBEMMessage("WtFldFastPFAtPoint: point in none of the blocks!\n");
4100 }
4101
4102 int nbXCells = WtFldBlkNbXCells[thisBlock];
4103 int nbYCells = WtFldBlkNbYCells[thisBlock];
4104 int nbZCells = WtFldBlkNbZCells[thisBlock];
4105 double delX = WtFldFastVol.LX / nbXCells;
4106 double delY = WtFldFastVol.LY / nbYCells;
4107 double delZ = WtFldBlkLZ[thisBlock] / nbZCells;
4108 dz -= (WtFldBlkCrnrZ[thisBlock] - CornerZ); // distance from the block corner
4109
4110 if (dbgFn) {
4111 printf("thisBlock: %d\n", thisBlock);
4112 printf("nbXCells, nbYCells, nbZCells: %d, %d, %d\n", nbXCells, nbYCells,
4113 nbZCells);
4114 printf("WtFldBlkCrnrZ: %lg\n", WtFldBlkCrnrZ[thisBlock]);
4115 printf("delX, delY, delZ: %le, %le, %le\n", delX, delY, delZ);
4116 printf("dz: %lg\n", dz);
4117 fflush(stdout);
4118 }
4119
4120 // Find cell in block of basic / staggered volume within which the point lies
4121 int celli = (int)(dx / delX) + 1; // Find cell in which the point lies
4122 if (celli < 1) {
4123 celli = 1;
4124 dx = 0.5 * delX;
4125 neBEMMessage("WtFldFastPFAtPoint - celli < 1\n");
4126 }
4127 if (celli > nbXCells) {
4128 celli = nbXCells;
4129 dx = WtFldFastVol.LX - 0.5 * delX;
4130 neBEMMessage("WtFldFastPFAtPoint - celli > nbXCells\n");
4131 }
4132 int cellj = (int)(dy / delY) + 1;
4133 if (cellj < 1) {
4134 cellj = 1;
4135 dy = 0.5 * delY;
4136 neBEMMessage("WtFldFastPFAtPoint - cellj < 1\n");
4137 }
4138 if (cellj > nbYCells) {
4139 cellj = nbYCells;
4140 dy = WtFldFastVol.LY - 0.5 * delY;
4141 neBEMMessage("WtFldFastPFAtPoint - cellj > nbYCells\n");
4142 }
4143 int cellk = (int)(dz / delZ) + 1;
4144 if (cellk < 1) {
4145 cellk = 1;
4146 dz = 0.5 * delX;
4147 neBEMMessage("WtFldFastPFAtPoint - cellk < 1\n");
4148 }
4149 if (cellk > nbZCells) {
4150 cellk = nbZCells;
4151 dz = WtFldFastVol.LZ - 0.5 * delZ;
4152 neBEMMessage("WtFldFastPFAtPoint - cellk > nbZCells\n");
4153 }
4154 if (dbgFn) printf("Cells in x, y, z: %d, %d, %d\n", celli, cellj, cellk);
4155
4156 // Interpolate potential and field at the point using the corner values of
4157 // of the cell and, if necessary, of the neighbouring cells
4158 // These gradients can also be calculated while computing the potential and
4159 // field at the cells and stored in memory, provided enough memory is
4160 // available
4161
4162 // distances from cell corner
4163 double dxcellcrnr = dx - (double)(celli - 1) * delX;
4164 double dycellcrnr = dy - (double)(cellj - 1) * delY;
4165 double dzcellcrnr = dz - (double)(cellk - 1) * delZ;
4166 if (dbgFn)
4167 printf("cell crnr dx, dy, dz: %g, %g, %g\n", dxcellcrnr, dycellcrnr,
4168 dzcellcrnr);
4169
4170 // normalized distances
4171 double xd = dxcellcrnr / delX; // xd = (x-x0)/(x1-x0)
4172 double yd = dycellcrnr / delY; // etc
4173 double zd = dzcellcrnr / delZ;
4174 if (xd <= 0.0) xd = 0.0;
4175 if (yd <= 0.0) yd = 0.0;
4176 if (zd <= 0.0) zd = 0.0;
4177 if (xd >= 1.0) xd = 1.0;
4178 if (yd >= 1.0) yd = 1.0;
4179 if (zd >= 1.0) zd = 1.0;
4180
4181 // corner values of potential and field
4182 double P000 = WtFldFastPot[thisBlock][celli][cellj][cellk]; // lowest corner
4183 double FX000 = WtFldFastFX[thisBlock][celli][cellj][cellk];
4184 double FY000 = WtFldFastFY[thisBlock][celli][cellj][cellk];
4185 double FZ000 = WtFldFastFZ[thisBlock][celli][cellj][cellk];
4186 double P100 = WtFldFastPot[thisBlock][celli + 1][cellj][cellk];
4187 double FX100 = WtFldFastFX[thisBlock][celli + 1][cellj][cellk];
4188 double FY100 = WtFldFastFY[thisBlock][celli + 1][cellj][cellk];
4189 double FZ100 = WtFldFastFZ[thisBlock][celli + 1][cellj][cellk];
4190 double P010 = WtFldFastPot[thisBlock][celli][cellj + 1][cellk];
4191 double FX010 = WtFldFastFX[thisBlock][celli][cellj + 1][cellk];
4192 double FY010 = WtFldFastFY[thisBlock][celli][cellj + 1][cellk];
4193 double FZ010 = WtFldFastFZ[thisBlock][celli][cellj + 1][cellk];
4194 double P001 = WtFldFastPot[thisBlock][celli][cellj][cellk + 1];
4195 double FX001 = WtFldFastFX[thisBlock][celli][cellj][cellk + 1];
4196 double FY001 = WtFldFastFY[thisBlock][celli][cellj][cellk + 1];
4197 double FZ001 = WtFldFastFZ[thisBlock][celli][cellj][cellk + 1];
4198 double P110 = WtFldFastPot[thisBlock][celli + 1][cellj + 1][cellk];
4199 double FX110 = WtFldFastFX[thisBlock][celli + 1][cellj + 1][cellk];
4200 double FY110 = WtFldFastFY[thisBlock][celli + 1][cellj + 1][cellk];
4201 double FZ110 = WtFldFastFZ[thisBlock][celli + 1][cellj + 1][cellk];
4202 double P101 = WtFldFastPot[thisBlock][celli + 1][cellj][cellk + 1];
4203 double FX101 = WtFldFastFX[thisBlock][celli + 1][cellj][cellk + 1];
4204 double FY101 = WtFldFastFY[thisBlock][celli + 1][cellj][cellk + 1];
4205 double FZ101 = WtFldFastFZ[thisBlock][celli + 1][cellj][cellk + 1];
4206 double P011 = WtFldFastPot[thisBlock][celli][cellj + 1][cellk + 1];
4207 double FX011 = WtFldFastFX[thisBlock][celli][cellj + 1][cellk + 1];
4208 double FY011 = WtFldFastFY[thisBlock][celli][cellj + 1][cellk + 1];
4209 double FZ011 = WtFldFastFZ[thisBlock][celli][cellj + 1][cellk + 1];
4210 double P111 = WtFldFastPot[thisBlock][celli + 1][cellj + 1][cellk + 1];
4211 double FX111 = WtFldFastFX[thisBlock][celli + 1][cellj + 1][cellk + 1];
4212 double FY111 = WtFldFastFY[thisBlock][celli + 1][cellj + 1][cellk + 1];
4213 double FZ111 = WtFldFastFZ[thisBlock][celli + 1][cellj + 1][cellk + 1];
4215 if (sector == 1) { // nothing to be done
4216 }
4217 if (sector == 2) { // volume shifted up but point not in the staggered part
4218 }
4219 if (sector == 3) { // staggered volume
4220 P000 = WtFldFastStgPot[thisBlock][celli][cellj][cellk];
4221 FX000 = WtFldFastStgFX[thisBlock][celli][cellj][cellk];
4222 FY000 = WtFldFastStgFY[thisBlock][celli][cellj][cellk];
4223 FZ000 = WtFldFastStgFZ[thisBlock][celli][cellj][cellk];
4224 P100 = WtFldFastStgPot[thisBlock][celli + 1][cellj][cellk];
4225 FX100 = WtFldFastStgFX[thisBlock][celli + 1][cellj][cellk];
4226 FY100 = WtFldFastStgFY[thisBlock][celli + 1][cellj][cellk];
4227 FZ100 = WtFldFastStgFZ[thisBlock][celli + 1][cellj][cellk];
4228 P010 = WtFldFastStgPot[thisBlock][celli][cellj + 1][cellk];
4229 FX010 = WtFldFastStgFX[thisBlock][celli][cellj + 1][cellk];
4230 FY010 = WtFldFastStgFY[thisBlock][celli][cellj + 1][cellk];
4231 FZ010 = WtFldFastStgFZ[thisBlock][celli][cellj + 1][cellk];
4232 P001 = WtFldFastStgPot[thisBlock][celli][cellj][cellk + 1];
4233 FX001 = WtFldFastStgFX[thisBlock][celli][cellj][cellk + 1];
4234 FY001 = WtFldFastStgFY[thisBlock][celli][cellj][cellk + 1];
4235 FZ001 = WtFldFastStgFZ[thisBlock][celli][cellj][cellk + 1];
4236 P110 = WtFldFastStgPot[thisBlock][celli + 1][cellj + 1][cellk];
4237 FX110 = WtFldFastStgFX[thisBlock][celli + 1][cellj + 1][cellk];
4238 FY110 = WtFldFastStgFY[thisBlock][celli + 1][cellj + 1][cellk];
4239 FZ110 = WtFldFastStgFZ[thisBlock][celli + 1][cellj + 1][cellk];
4240 P101 = WtFldFastStgPot[thisBlock][celli + 1][cellj][cellk + 1];
4241 FX101 = WtFldFastStgFX[thisBlock][celli + 1][cellj][cellk + 1];
4242 FY101 = WtFldFastStgFY[thisBlock][celli + 1][cellj][cellk + 1];
4243 FZ101 = WtFldFastStgFZ[thisBlock][celli + 1][cellj][cellk + 1];
4244 P011 = WtFldFastStgPot[thisBlock][celli][cellj + 1][cellk + 1];
4245 FX011 = WtFldFastStgFX[thisBlock][celli][cellj + 1][cellk + 1];
4246 FY011 = WtFldFastStgFY[thisBlock][celli][cellj + 1][cellk + 1];
4247 FZ011 = WtFldFastStgFZ[thisBlock][celli][cellj + 1][cellk + 1];
4248 P111 = WtFldFastStgPot[thisBlock][celli + 1][cellj + 1][cellk + 1];
4249 FX111 = WtFldFastStgFX[thisBlock][celli + 1][cellj + 1][cellk + 1];
4250 FY111 = WtFldFastStgFY[thisBlock][celli + 1][cellj + 1][cellk + 1];
4251 FZ111 = WtFldFastStgFZ[thisBlock][celli + 1][cellj + 1][cellk + 1];
4252 }
4253 if (sector == 4) { // volume shifted down and point in the staggered part
4254 P000 = WtFldFastStgPot[thisBlock][celli][cellj][cellk];
4255 FX000 = WtFldFastStgFX[thisBlock][celli][cellj][cellk];
4256 FY000 = WtFldFastStgFY[thisBlock][celli][cellj][cellk];
4257 FZ000 = WtFldFastStgFZ[thisBlock][celli][cellj][cellk];
4258 P100 = WtFldFastStgPot[thisBlock][celli + 1][cellj][cellk];
4259 FX100 = WtFldFastStgFX[thisBlock][celli + 1][cellj][cellk];
4260 FY100 = WtFldFastStgFY[thisBlock][celli + 1][cellj][cellk];
4261 FZ100 = WtFldFastStgFZ[thisBlock][celli + 1][cellj][cellk];
4262 P010 = WtFldFastStgPot[thisBlock][celli][cellj + 1][cellk];
4263 FX010 = WtFldFastStgFX[thisBlock][celli][cellj + 1][cellk];
4264 FY010 = WtFldFastStgFY[thisBlock][celli][cellj + 1][cellk];
4265 FZ010 = WtFldFastStgFZ[thisBlock][celli][cellj + 1][cellk];
4266 P001 = WtFldFastStgPot[thisBlock][celli][cellj][cellk + 1];
4267 FX001 = WtFldFastStgFX[thisBlock][celli][cellj][cellk + 1];
4268 FY001 = WtFldFastStgFY[thisBlock][celli][cellj][cellk + 1];
4269 FZ001 = WtFldFastStgFZ[thisBlock][celli][cellj][cellk + 1];
4270 P110 = WtFldFastStgPot[thisBlock][celli + 1][cellj + 1][cellk];
4271 FX110 = WtFldFastStgFX[thisBlock][celli + 1][cellj + 1][cellk];
4272 FY110 = WtFldFastStgFY[thisBlock][celli + 1][cellj + 1][cellk];
4273 FZ110 = WtFldFastStgFZ[thisBlock][celli + 1][cellj + 1][cellk];
4274 P101 = WtFldFastStgPot[thisBlock][celli + 1][cellj][cellk + 1];
4275 FX101 = WtFldFastStgFX[thisBlock][celli + 1][cellj][cellk + 1];
4276 FY101 = WtFldFastStgFY[thisBlock][celli + 1][cellj][cellk + 1];
4277 FZ101 = WtFldFastStgFZ[thisBlock][celli + 1][cellj][cellk + 1];
4278 P011 = WtFldFastStgPot[thisBlock][celli][cellj + 1][cellk + 1];
4279 FX011 = WtFldFastStgFX[thisBlock][celli][cellj + 1][cellk + 1];
4280 FY011 = WtFldFastStgFY[thisBlock][celli][cellj + 1][cellk + 1];
4281 FZ011 = WtFldFastStgFZ[thisBlock][celli][cellj + 1][cellk + 1];
4282 P111 = WtFldFastStgPot[thisBlock][celli + 1][cellj + 1][cellk + 1];
4283 FX111 = WtFldFastStgFX[thisBlock][celli + 1][cellj + 1][cellk + 1];
4284 FY111 = WtFldFastStgFY[thisBlock][celli + 1][cellj + 1][cellk + 1];
4285 FZ111 = WtFldFastStgFZ[thisBlock][celli + 1][cellj + 1][cellk + 1];
4286 }
4287 }
4288
4289 double intP =
4290 TriLin(xd, yd, zd, P000, P100, P010, P001, P110, P101, P011, P111);
4291 double intFX = TriLin(xd, yd, zd, FX000, FX100, FX010, FX001, FX110, FX101,
4292 FX011, FX111);
4293 double intFY = TriLin(xd, yd, zd, FY000, FY100, FY010, FY001, FY110, FY101,
4294 FY011, FY111);
4295 double intFZ = TriLin(xd, yd, zd, FZ000, FZ100, FZ010, FZ001, FZ110, FZ101,
4296 FZ011, FZ111);
4297
4298 *Potential = intP;
4299 globalF->X = intFX;
4300 globalF->Y = intFY;
4301 globalF->Z = intFZ;
4302
4303 if (dbgFn) {
4304 printf("WtFldCell corner values:\n");
4305 printf("Potential: %g, %g, %g, %g\n", P000, P100, P010, P001);
4306 printf("Potential: %g, %g, %g, %g\n", P110, P101, P011, P111);
4307 printf("FastFX: %g, %g, %g, %g\n", FX000, FX100, FX010, FX001);
4308 printf("FastFX: %g, %g, %g, %g\n", FX110, FX101, FX011, FX111);
4309 printf("FastFY: %g, %g, %g, %g\n", FY000, FY100, FY010, FY001);
4310 printf("FastFY: %g, %g, %g, %g\n", FY110, FY101, FY011, FY111);
4311 printf("FastFZ: %g, %g, %g, %g\n", FZ000, FZ100, FZ010, FZ001);
4312 printf("FastFZ: %g, %g, %g, %g\n", FZ110, FZ101, FZ011, FZ111);
4313 printf("Pot, FX, FY, FZ: %g, %g, %g, %g\n", *Potential, globalF->X,
4314 globalF->Y, globalF->Z);
4315 }
4316
4317 if (dbgFn) {
4318 printf("out WtFldFastPFAtPoint\n");
4319 fflush(stdout);
4320 }
4321
4322 return 0;
4323} // WtFldFastPFAtPoint ends
4324
4325// Potential and flux per unit charge density on an element returned as
4326// Pot, Fx, Fy, Fz components
4327// in the global coordinate system
4328void GetPFGCS(int type, double a, double b, Point3D *localP,
4329 double *Potential, Vector3D *globalF, DirnCosn3D *DirCos) {
4330 Vector3D localF;
4331 const double x = localP->X;
4332 const double y = localP->Y;
4333 const double z = localP->Z;
4334 switch (type) {
4335 case 4: // rectangular element
4336 RecPF(a, b, x, y, z, Potential, &localF);
4337 break;
4338 case 3: // triangular element
4339 TriPF(a, b, x, y, z, Potential, &localF);
4340 break;
4341 case 2: // linear (wire) element
4342 WirePF(a, b, x, y, z, Potential, &localF);
4343 break;
4344 default:
4345 printf("Geometrical type out of range! ... exiting ...\n");
4346 exit(-1);
4347 break; // never comes here
4348 } // switch over gtsrc ends
4349
4350 (*globalF) = RotateVector3D(&localF, DirCos, local2global);
4351} // end of GetPFGCS
4352
4353// Potential and flux per unit charge density on an element returned as
4354// Pot, Fx, Fy, Fz components in the local coordinate system
4355void GetPF(int type, double a, double b, double x, double y, double z,
4356 double *Potential, Vector3D *localF) {
4357 switch (type) {
4358 case 4: // rectangular element
4359 RecPF(a, b, x, y, z, Potential, localF);
4360 break;
4361 case 3: // triangular element
4362 TriPF(a, b, x, y, z, Potential, localF);
4363 break;
4364 case 2: // linear (wire) element
4365 WirePF(a, b, x, y, z, Potential, localF);
4366 break;
4367 default:
4368 printf("Geometrical type out of range! ... exiting ...\n");
4369 exit(-1);
4370 break; // never comes here
4371 } // switch over gtsrc ends
4372} // end of GetPF
4373
4374// Flux per unit charge density on a rectangular element
4375// Are X and Z directions the same as obtained using the direction cosines?
4376void RecPF(double a, double b, double x, double y, double z,
4377 double *Potential, Vector3D *localF) {
4378 const double d2 = x * x + y * y + z * z;
4379 if (d2 >= FarField2 * (a * a + b * b)) {
4380 (*Potential) = a * b / sqrt(d2);
4381 const double f = (*Potential) / d2;
4382 localF->X = x * f;
4383 localF->Y = y * f;
4384 localF->Z = z * f;
4385 } else {
4386 int fstatus =
4387 ExactRecSurf(x / a, y / a, z / a, -0.5, -(b / a) / 2.0,
4388 0.5, (b / a) / 2.0, Potential, localF);
4389 if (fstatus) { // non-zero
4390 printf("problem in RecPF ... \n");
4391 // printf("returning ...\n");
4392 // return -1; void function at present
4393 }
4394 (*Potential) *= a; // rescale - cannot be done outside because of the `if'
4395 }
4396
4397} // end of RecPF
4398
4399// Flux per unit charge density on a triangular element
4400void TriPF(double a, double b, double x, double y, double z,
4401 double *Potential, Vector3D *localF) {
4402 // printf("In TriPF\n");
4403 const double xm = x - a / 3.;
4404 const double zm = z - b / 3.;
4405 const double d2 = xm * xm + y * y + zm * zm;
4406
4407 if (d2 >= FarField2 * (a * a + b * b)) {
4408 (*Potential) = 0.5 * a * b / sqrt(d2);
4409 const double f = (*Potential) / d2;
4410 localF->X = x * f;
4411 localF->Y = y * f;
4412 localF->Z = z * f;
4413 } else {
4414 int fstatus = ExactTriSurf(b / a, x / a, y / a, z / a, Potential, localF);
4415 if (fstatus) { // non-zero
4416 printf("problem in TriPF ... \n");
4417 // printf("returning ...\n");
4418 // return -1; void function at present
4419 }
4420 (*Potential) *= a; // rescale - cannot be done outside because of the `if'
4421 }
4422 // printf("Out of TriPF\n");
4423} // end of TriPF
4424
4425// Flux per unit charge density on a wire element
4426void WirePF(double rW, double lW, double x, double y, double z,
4427 double *Potential, Vector3D *localF) {
4428 const double d2 = x * x + y * y + z * z;
4429 if (d2 >= FarField2 * lW * lW) {
4430 double dA = 2.0 * ST_PI * rW * lW;
4431 const double dist = sqrt(d2);
4432 (*Potential) = dA / dist;
4433 double f = dA / (dist * d2);
4434 localF->X = x * f;
4435 localF->Y = y * f;
4436 localF->Z = z * f;
4437 } else {
4438 if ((fabs(x) < MINDIST) && (fabs(y) < MINDIST)) {
4439 if (fabs(z) < MINDIST)
4440 (*Potential) = ExactCentroidalP_W(rW, lW);
4441 else
4442 (*Potential) = ExactAxialP_W(rW, lW, z);
4443
4444 localF->X = localF->Y = 0.0;
4445 localF->Z = ExactThinFZ_W(rW, lW, x, y, z);
4446 } else {
4447 ExactThinWire(rW, lW, x, y, z, Potential, localF);
4448 }
4449 }
4450} // end of WirePF
4451
4452// Potential and flux per unit charge density on an element returned as
4453// Pot, Fx, Fy, Fz components
4454// in the global coordiante system
4455void GetPrimPFGCS(int prim, Point3D *localP, double *Potential,
4456 Vector3D *globalF, DirnCosn3D *DirCos) {
4457 Vector3D localF;
4458
4459 switch (PrimType[prim]) {
4460 case 4: // rectangular primitive
4461 RecPrimPF(prim, localP, Potential, &localF);
4462 break;
4463 case 3: // triangular primitive
4464 TriPrimPF(prim, localP, Potential, &localF);
4465 break;
4466 case 2: // linear (wire) primitive
4467 WirePrimPF(prim, localP, Potential, &localF);
4468 break;
4469 default:
4470 printf("Geometrical type out of range! ... exiting ...\n");
4471 exit(-1);
4472 break; // never comes here
4473 } // switch over gtsrc ends
4474
4475 (*globalF) = RotateVector3D(&localF, DirCos, local2global);
4476} // end of GetPrimPFGCS
4477
4478// Potential and flux per unit charge density on an element returned as
4479// Pot, Fx, Fy, Fz components in the local coordinate system
4480void GetPrimPF(int prim, Point3D *localP, double *Potential, Vector3D *localF) {
4481 switch (PrimType[prim]) {
4482 case 4: // rectangular primitive
4483 RecPrimPF(prim, localP, Potential, localF);
4484 break;
4485 case 3: // triangular primitive
4486 TriPrimPF(prim, localP, Potential, localF);
4487 break;
4488 case 2: // linear (wire) primitive
4489 WirePrimPF(prim, localP, Potential, localF);
4490 break;
4491 default:
4492 printf("Geometrical type out of range! ... exiting ...\n");
4493 exit(-1);
4494 break; // never comes here
4495 } // switch over gtsrc ends
4496} // end of GetPrimPF
4497
4498// Flux per unit charge density on a rectangular primitive
4499void RecPrimPF(int prim, Point3D *localP, double *Potential, Vector3D *localF) {
4500 double xpt = localP->X;
4501 double ypt = localP->Y;
4502 double zpt = localP->Z;
4503 double dist = sqrt(xpt * xpt + ypt * ypt + zpt * zpt);
4504
4505 double a = PrimLX[prim];
4506 double b = PrimLZ[prim];
4507 double diag = sqrt(a * a + b * b); // diagonal
4508
4509 if (dist >= FarField * diag) {
4510 double dA = a * b; // area
4511 (*Potential) = dA / dist;
4512 const double f = dA / (dist * dist * dist);
4513 localF->X = xpt * f;
4514 localF->Y = ypt * f;
4515 localF->Z = zpt * f;
4516 } else {
4517 int fstatus =
4518 ExactRecSurf(xpt / a, ypt / a, zpt / a, -0.5, -(b / a) / 2.0,
4519 0.5, (b / a) / 2.0, Potential, localF);
4520 if (fstatus) { // non-zero
4521 printf("problem in RecPrimPF ... \n");
4522 // printf("returning ...\n");
4523 // return -1; void function at present
4524 }
4525 (*Potential) *= a; // rescale - cannot be done outside because of the `if'
4526 }
4527
4528} // end of RecPrimPF
4529
4530// Flux per unit charge density on a triangluar primitive
4531// Note that vertex[1] is the right angle corner
4532void TriPrimPF(int prim, Point3D *localP, double *Potential, Vector3D *localF) {
4533 double xpt = localP->X;
4534 double ypt = localP->Y;
4535 double zpt = localP->Z;
4536 double a = PrimLX[prim];
4537 double b = PrimLZ[prim];
4538 // longest side (hypotenuse)
4539 double diag = sqrt(a * a + b * b);
4540 const double xm = xpt - a / 3.;
4541 const double zm = zpt - b / 3.;
4542 double dist = sqrt(xm * xm + ypt * ypt + zm * zm);
4543
4544 if (dist >= FarField * diag) {
4545 double dA = 0.5 * a * b; // area
4546 (*Potential) = dA / dist;
4547 double f = dA / (dist * dist * dist);
4548 localF->X = xpt * f;
4549 localF->Y = ypt * f;
4550 localF->Z = zpt * f;
4551 } else {
4552 int fstatus =
4553 ExactTriSurf(b / a, xpt / a, ypt / a, zpt / a, Potential, localF);
4554 if (fstatus) // non-zero
4555 {
4556 printf("problem in TriPrimPF ... \n");
4557 }
4558 (*Potential) *= a; // rescale - cannot be done outside because of the `if'
4559 }
4560
4561 // printf("Out of TriPrimPF\n");
4562} // end of TriPrimPF
4563
4564// Flux per unit charge density on a wire primitive
4565void WirePrimPF(int prim, Point3D *localP, double *Potential,
4566 Vector3D *localF) {
4567 double xpt = localP->X;
4568 double ypt = localP->Y;
4569 double zpt = localP->Z;
4570 double rW = Radius[prim];
4571 double lW = PrimLZ[prim];
4572 double dist =
4573 sqrt(xpt * xpt + ypt * ypt + zpt * zpt); // fld pt from ele cntrd
4574
4575 if (dist >= FarField * lW) // all are distances and, hence, +ve
4576 {
4577 double dA = 2.0 * ST_PI * rW * lW;
4578 (*Potential) = dA / dist;
4579 double f = dA / (dist * dist * dist);
4580 localF->X = xpt * f;
4581 localF->Y = ypt * f;
4582 localF->Z = zpt * f;
4583 } else {
4584 if ((fabs(xpt) < MINDIST) && (fabs(ypt) < MINDIST)) {
4585 if (fabs(zpt) < MINDIST)
4586 (*Potential) = ExactCentroidalP_W(rW, lW);
4587 else
4588 (*Potential) = ExactAxialP_W(rW, lW, zpt);
4589
4590 localF->X = localF->Y = 0.0;
4591 localF->Z = ExactThinFZ_W(rW, lW, xpt, ypt, zpt);
4592 } else {
4593 ExactThinWire(rW, lW, xpt, ypt, zpt, Potential, localF);
4594 }
4595 }
4596} // end of WirePrimPF
4597
4598// Gives three components of weighting field in the global coordinate system
4599// due to all the elements
4600// Note that local evaluation of influence and additional influences have not
4601// been incorporated here. Iff local evaluation show a substantial advantage
4602// over the cleaner function call, we'll implement the former in this function.
4603// This function should be merged with PFAtPoint since the only change is in
4604// the use of weighting field charge density instead of the physical charge
4605// denstiy. However, care should be taken to check the last to points mentioned
4606// in this function - VSystemChargeZero and effects of known charge densities.
4607// Multi-threading implemented in the following routine.
4608// Gives three components of the total Potential and flux in the global
4609// coordinate system due to all the elements
4610int WtPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF,
4611 int IdWtField) {
4612 int dbgFn = 0;
4613
4614 const double xfld = globalP->X;
4615 const double yfld = globalP->Y;
4616 const double zfld = globalP->Z;
4617
4618 // Compute Potential and field at different locations
4619 *Potential = globalF->X = globalF->Y = globalF->Z = 0.0;
4620
4621 // Effects due to base primitives and their repetitions are considered in the
4622 // local coordinate system of the primitive (or element), while effects due to
4623 // mirror elements and their repetitions are considered in the global
4624 // coordinate system (GCS). This works because the direction cosines of a
4625 // primitive (and its elements) and those of its repetitions are the same.
4626 // As a result, we can do just one transformation from local to global at the
4627 // end of calculations related to a primitive. This can save substantial
4628 // computation if a discretized version of the primitive is being used since
4629 // we avoid one unnecessary transformation for each element that comprises a
4630 // primitive.
4631 // Begin with primitive description of the device
4632
4633 // Scope in OpenMP: Variables in the global data space are accessible to all
4634 // threads, while variables in a thread's private space is accessible to the
4635 // thread only (there are several variations - copying outside region etc)
4636 // Field point remains the same - kept outside private
4637 // source point changes with change in primitive - private
4638 // TransformationMatrix changes - kept within private (Note: matrices with
4639 // fixed dimensions can be maintained, but those with dynamic allocation
4640 // can not).
4641 double *pPot = dvector(1, NbPrimitives);
4642 double *plFx = dvector(1, NbPrimitives); // field components in LCS
4643 double *plFy = dvector(1, NbPrimitives); // for a primitive
4644 double *plFz = dvector(1, NbPrimitives); // and its other incarnations
4645
4646 for (int prim = 1; prim <= NbPrimitives; ++prim) {
4647 pPot[prim] = plFx[prim] = plFy[prim] = plFz[prim] = 0.0;
4648 }
4649
4650#ifdef _OPENMP
4651 int tid = 0, nthreads = 1;
4652 #pragma omp parallel private(tid, nthreads)
4653#endif
4654 {
4655
4656#ifdef _OPENMP
4657 if (dbgFn) {
4658 tid = omp_get_thread_num();
4659 if (tid == 0) {
4660 nthreads = omp_get_num_threads();
4661 printf("PFAtPoint computation with %d threads\n", nthreads);
4662 }
4663 }
4664#endif
4665// by default, nested parallelization is off in C
4666#ifdef _OPENMP
4667#pragma omp for
4668#endif
4669 for (int primsrc = 1; primsrc <= NbPrimitives; ++primsrc) {
4670 if (dbgFn) {
4671 printf("Evaluating effect of primsrc %d using on %lg, %lg, %lg\n",
4672 primsrc, xfld, yfld, zfld);
4673 fflush(stdout);
4674 }
4675
4676 const double xpsrc = PrimOriginX[primsrc];
4677 const double ypsrc = PrimOriginY[primsrc];
4678 const double zpsrc = PrimOriginZ[primsrc];
4679
4680 // Field in the local frame.
4681 double lFx = 0.;
4682 double lFy = 0.;
4683 double lFz = 0.;
4684
4685 // Set up transform matrix for this primitive, which is also the same
4686 // for all the elements belonging to this primitive.
4687 double TransformationMatrix[3][3];
4688 TransformationMatrix[0][0] = PrimDC[primsrc].XUnit.X;
4689 TransformationMatrix[0][1] = PrimDC[primsrc].XUnit.Y;
4690 TransformationMatrix[0][2] = PrimDC[primsrc].XUnit.Z;
4691 TransformationMatrix[1][0] = PrimDC[primsrc].YUnit.X;
4692 TransformationMatrix[1][1] = PrimDC[primsrc].YUnit.Y;
4693 TransformationMatrix[1][2] = PrimDC[primsrc].YUnit.Z;
4694 TransformationMatrix[2][0] = PrimDC[primsrc].ZUnit.X;
4695 TransformationMatrix[2][1] = PrimDC[primsrc].ZUnit.Y;
4696 TransformationMatrix[2][2] = PrimDC[primsrc].ZUnit.Z;
4697
4698 // The total influence is due to primitives on the basic device and due to
4699 // virtual primitives arising out of repetition, reflection etc and not
4700 // residing on the basic device
4701
4702 { // basic primitive
4703 // point translated to the ECS origin, but axes direction global
4704 Point3D localPP;
4705 { // Rotate point from global to local system
4706 double InitialVector[3] = {xfld - xpsrc, yfld - ypsrc, zfld - zpsrc};
4707 double FinalVector[3] = {0., 0., 0.};
4708 for (int i = 0; i < 3; ++i) {
4709 for (int j = 0; j < 3; ++j) {
4710 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
4711 }
4712 }
4713 localPP.X = FinalVector[0];
4714 localPP.Y = FinalVector[1];
4715 localPP.Z = FinalVector[2];
4716 } // Point3D rotated
4717
4718 // evaluate possibility whether primitive influence is accurate enough
4719 // This could be based on localPP and the subtended solid angle
4720 // If 1, then only primitive influence will be considered
4721 int PrimOK = 0;
4722 if (PrimOK) {
4723 // Potential and flux (local system) due to base primitive
4724 double tmpPot;
4725 Vector3D tmpF;
4726 GetPrimPF(primsrc, &localPP, &tmpPot, &tmpF);
4727 const double qpr = AvWtChDen[IdWtField][primsrc];
4728 pPot[primsrc] += qpr * tmpPot;
4729 lFx += qpr * tmpF.X;
4730 lFy += qpr * tmpF.Y;
4731 lFz += qpr * tmpF.Z;
4732 // if(DebugLevel == 301)
4733 if (dbgFn) {
4734 printf("PFAtPoint base primitive =>\n");
4735 printf("primsrc: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n",
4736 primsrc, localPP.X, localPP.Y, localPP.Z);
4737 printf("primsrc: %d, Pot: %lg, Fx: %lg, Fx: %lg, Fz: %lg\n",
4738 primsrc, tmpPot, tmpF.X, tmpF.Y, tmpF.Z);
4739 printf("primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: %lg\n",
4740 primsrc, pPot[primsrc], lFx, lFy, lFz);
4741 fflush(stdout);
4742 // exit(-1);
4743 }
4744 } else {
4745 // element influence
4746 double tPot;
4747 Vector3D tF;
4748 double ePot = 0.;
4749 Vector3D eF;
4750 eF.X = 0.0;
4751 eF.Y = 0.0;
4752 eF.Z = 0.0;
4753
4754 const int eleMin = ElementBgn[primsrc];
4755 const int eleMax = ElementEnd[primsrc];
4756 for (int ele = eleMin; ele <= eleMax; ++ele) {
4757 const double xsrc = (EleArr + ele - 1)->G.Origin.X;
4758 const double ysrc = (EleArr + ele - 1)->G.Origin.Y;
4759 const double zsrc = (EleArr + ele - 1)->G.Origin.Z;
4760 // Rotate vector from global to local system; matrix as for
4761 // primitive
4762 double vG[3] = {xfld - xsrc, yfld - ysrc, zfld - zsrc};
4763 double vL[3] = {0., 0., 0.};
4764 for (int i = 0; i < 3; ++i) {
4765 for (int j = 0; j < 3; ++j) {
4766 vL[i] += TransformationMatrix[i][j] * vG[j];
4767 }
4768 }
4769 // Potential and flux (local system) due to base primitive
4770 const int type = (EleArr + ele - 1)->G.Type;
4771 const double a = (EleArr + ele - 1)->G.LX;
4772 const double b = (EleArr + ele - 1)->G.LZ;
4773 GetPF(type, a, b, vL[0], vL[1], vL[2], &tPot, &tF);
4774 const double qel = WtFieldChDen[IdWtField][ele];
4775 ePot += qel * tPot;
4776 eF.X += qel * tF.X;
4777 eF.Y += qel * tF.Y;
4778 eF.Z += qel * tF.Z;
4779 // if(DebugLevel == 301)
4780 if (dbgFn) {
4781 printf("PFAtPoint base primitive:%d\n", primsrc);
4782 printf("ele: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n", ele,
4783 vL[0], vL[1], vL[2]);
4784 printf(
4785 "ele: %d, tPot: %lg, tFx: %lg, tFy: %lg, tFz: %lg, Solution: "
4786 "%g\n",
4787 ele, tPot, tF.X, tF.Y, tF.Z, qel);
4788 printf("ele: %d, ePot: %lg, eFx: %lg, eFy: %lg, eFz: %lg\n", ele,
4789 ePot, eF.X, eF.Y, eF.Z);
4790 fflush(stdout);
4791 }
4792 } // for all the elements on this primsrc primitive
4793
4794 pPot[primsrc] += ePot;
4795 lFx += eF.X;
4796 lFy += eF.Y;
4797 lFz += eF.Z;
4798 if (dbgFn) {
4799 printf(
4800 "prim%d, ePot: %lg, eFx: %lg, eFy: %lg, eFz: %lg\n",
4801 primsrc, ePot, eF.X, eF.Y, eF.Z);
4802 printf("prim%d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: %lg\n", primsrc,
4803 pPot[primsrc], lFx, lFy, lFz);
4804 fflush(stdout);
4805 }
4806 } // else elements influence
4807
4808 // if(DebugLevel == 301)
4809 if (dbgFn) {
4810 printf("basic primtive\n");
4811 printf("primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: %lg\n",
4812 primsrc, pPot[primsrc], lFx, lFy, lFz);
4813 fflush(stdout);
4814 }
4815 } // basic primitive ends
4816
4817 if (MirrorTypeX[primsrc] || MirrorTypeY[primsrc] ||
4818 MirrorTypeZ[primsrc]) { // Mirror effect of base primitives
4819 printf("Mirror may not be correctly implemented ...\n");
4820 exit(0);
4821 } // Mirror effect ends
4822
4823 // Flux due to repeated primitives
4824 if ((PeriodicTypeX[primsrc] == 1) || (PeriodicTypeY[primsrc] == 1) ||
4825 (PeriodicTypeZ[primsrc] == 1)) {
4826 const int perx = PeriodicInX[primsrc];
4827 const int pery = PeriodicInY[primsrc];
4828 const int perz = PeriodicInZ[primsrc];
4829 if (perx || pery || perz) {
4830 for (int xrpt = -perx; xrpt <= perx; ++xrpt) {
4831 const double xShift = XPeriod[primsrc] * (double)xrpt;
4832 double XPOfRpt = xpsrc + xShift;
4833 for (int yrpt = -pery; yrpt <= pery; ++yrpt) {
4834 const double yShift = YPeriod[primsrc] * (double)yrpt;
4835 double YPOfRpt = ypsrc + yShift;
4836 for (int zrpt = -perz; zrpt <= perz; ++zrpt) {
4837 const double zShift = ZPeriod[primsrc] * (double)zrpt;
4838 double ZPOfRpt = zpsrc + zShift;
4839 // Skip the base device.
4840 if ((xrpt == 0) && (yrpt == 0) && (zrpt == 0)) continue;
4841 { // basic primitive repeated
4842 Point3D localPPR;
4843 { // Rotate point from global to local system
4844 double InitialVector[3] = {xfld - XPOfRpt, yfld - YPOfRpt, zfld - ZPOfRpt};
4845 double FinalVector[3] = {0., 0., 0.};
4846 for (int i = 0; i < 3; ++i) {
4847 for (int j = 0; j < 3; ++j) {
4848 FinalVector[i] +=
4849 TransformationMatrix[i][j] * InitialVector[j];
4850 }
4851 }
4852 localPPR.X = FinalVector[0];
4853 localPPR.Y = FinalVector[1];
4854 localPPR.Z = FinalVector[2];
4855 } // Point3D rotated
4856
4857 int PrimOK = 0;
4858
4859 // consider primitive representation accurate enough if it is
4860 // repeated and beyond PrimAfter repetitions.
4861 if (PrimAfter == 0) {
4862 // If PrimAfter is zero, PrimOK is always zero
4863 PrimOK = 0;
4864 } else if ((abs(xrpt) > PrimAfter) && (abs(yrpt) > PrimAfter)) {
4865 PrimOK = 1;
4866 }
4867 if (PrimOK) { // use primitive representation
4868 // Potential and flux (local system) due to repeated
4869 // primitive
4870 double tmpPot;
4871 Vector3D tmpF;
4872 GetPrimPF(primsrc, &localPPR, &tmpPot, &tmpF);
4873 const double qpr = AvWtChDen[IdWtField][primsrc];
4874 pPot[primsrc] += qpr * tmpPot;
4875 lFx += qpr * tmpF.X;
4876 lFy += qpr * tmpF.Y;
4877 lFz += qpr * tmpF.Z;
4878 // if(DebugLevel == 301)
4879 if (dbgFn) {
4880 printf(
4881 "primsrc: %d, xlocal: %lg, ylocal: %lg, zlocal: "
4882 "%lg\n",
4883 primsrc, localPPR.X, localPPR.Y, localPPR.Z);
4884 printf(
4885 "primsrc: %d, Pot: %lg, Fx: %lg, Fy: %lg, Fz: %lg\n",
4886 primsrc, tmpPot * qpr, tmpF.X * qpr, tmpF.Y * qpr,
4887 tmpF.Z * qpr);
4888 printf(
4889 "primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: "
4890 "%lg\n",
4891 primsrc, pPot[primsrc], lFx, lFy, lFz);
4892 fflush(stdout);
4893 }
4894 } else {
4895 // use discretized representation of a repeated primitive
4896 double tPot;
4897 Vector3D tF;
4898 double erPot = 0.;
4899 Vector3D erF;
4900 erF.X = 0.0;
4901 erF.Y = 0.0;
4902 erF.Z = 0.0;
4903
4904 const int eleMin = ElementBgn[primsrc];
4905 const int eleMax = ElementEnd[primsrc];
4906 for (int ele = eleMin; ele <= eleMax; ++ele) {
4907 const double xrsrc = (EleArr + ele - 1)->G.Origin.X;
4908 const double yrsrc = (EleArr + ele - 1)->G.Origin.Y;
4909 const double zrsrc = (EleArr + ele - 1)->G.Origin.Z;
4910
4911 const double XEOfRpt = xrsrc + xShift;
4912 const double YEOfRpt = yrsrc + yShift;
4913 const double ZEOfRpt = zrsrc + zShift;
4914
4915 // Rotate point from global to local system.
4916 double vG[3] = {xfld - XEOfRpt, yfld - YEOfRpt, zfld - ZEOfRpt};
4917 double vL[3] = {0., 0., 0.};
4918 for (int i = 0; i < 3; ++i) {
4919 for (int j = 0; j < 3; ++j) {
4920 vL[i] += TransformationMatrix[i][j] * vG[j];
4921 }
4922 }
4923 // Allowed, because all the local coordinates have the
4924 // same orientations. Only the origins are mutually
4925 // displaced along a line.
4926 const int type = (EleArr + ele - 1)->G.Type;
4927 const double a = (EleArr + ele - 1)->G.LX;
4928 const double b = (EleArr + ele - 1)->G.LZ;
4929 GetPF(type, a, b, vL[0], vL[1], vL[2], &tPot, &tF);
4930 const double qel = WtFieldChDen[IdWtField][ele];
4931 erPot += qel * tPot;
4932 erF.X += qel * tF.X;
4933 erF.Y += qel * tF.Y;
4934 erF.Z += qel * tF.Z;
4935 // if(DebugLevel == 301)
4936 if (dbgFn) {
4937 printf("PFAtPoint base primitive:%d\n", primsrc);
4938 printf(
4939 "ele: %d, xlocal: %lg, ylocal: %lg, zlocal %lg\n",
4940 ele, vL[0], vL[1], vL[2]);
4941 printf(
4942 "ele: %d, tPot: %lg, tFx: %lg, tFy: %lg, tFz: %lg, "
4943 "Solution: %g\n",
4944 ele, tPot, tF.X, tF.Y, tF.Z, qel);
4945 printf(
4946 "ele: %d, ePot: %lg, eFx: %lg, eFy: %lg, eFz: "
4947 "%lg\n",
4948 ele, erPot, erF.X, erF.Y, erF.Z);
4949 fflush(stdout);
4950 }
4951 } // for all the elements on this primsrc repeated
4952 // primitive
4953
4954 pPot[primsrc] += erPot;
4955 lFx += erF.X;
4956 lFy += erF.Y;
4957 lFz += erF.Z;
4958 } // else discretized representation of this primitive
4959
4960 // if(DebugLevel == 301)
4961 if (dbgFn) {
4962 printf("basic repeated xrpt: %d. yrpt: %d, zrpt: %d\n",
4963 xrpt, yrpt, zrpt);
4964 printf(
4965 "primsrc: %d, pPot: %lg, lFx: %lg, lFy: %lg, lFz: "
4966 "%lg\n",
4967 primsrc, pPot[primsrc], lFx, lFy, lFz);
4968 fflush(stdout);
4969 }
4970 } // repetition of basic primitive
4971
4972 if (MirrorTypeX[primsrc] || MirrorTypeY[primsrc] ||
4973 MirrorTypeZ[primsrc]) {
4974 // Mirror effect of repeated primitives - not parallelized
4975 printf(
4976 "Mirror not correctly implemented in this version of "
4977 "neBEM ...\n");
4978 exit(0);
4979 } // Mirror effect for repeated primitives ends
4980
4981 } // for zrpt
4982 } // for yrpt
4983 } // for xrpt
4984 } // PeriodicInX || PeriodicInY || PeriodicInZ
4985 } // PeriodicType == 1
4986 Vector3D localF;
4987 localF.X = lFx;
4988 localF.Y = lFy;
4989 localF.Z = lFz;
4990 Vector3D tmpF = RotateVector3D(&localF, &PrimDC[primsrc], local2global);
4991 plFx[primsrc] = tmpF.X; // local fluxes lFx, lFy, lFz in GCS
4992 plFy[primsrc] = tmpF.Y;
4993 plFz[primsrc] = tmpF.Z;
4994 } // for all primitives: basic device, mirror reflections and repetitions
4995 } // pragma omp parallel
4996
4997 double totPot = 0.0;
4998 Vector3D totF;
4999 totF.X = totF.Y = totF.Z = 0.0;
5000 for (int prim = 1; prim <= NbPrimitives; ++prim) {
5001 totPot += pPot[prim];
5002 totF.X += plFx[prim];
5003 totF.Y += plFy[prim];
5004 totF.Z += plFz[prim];
5005 }
5006
5007 // This should be done at the end of the function - before freeing memory
5008#ifdef __cplusplus
5009 *Potential = totPot * InvFourPiEps0;
5010 globalF->X = totF.X * InvFourPiEps0;
5011 globalF->Y = totF.Y * InvFourPiEps0;
5012 globalF->Z = totF.Z * InvFourPiEps0;
5013#else
5014 *Potential = totPot / MyFACTOR;
5015 globalF->X = totF.X / MyFACTOR;
5016 globalF->Y = totF.Y / MyFACTOR;
5017 globalF->Z = totF.Z / MyFACTOR;
5018#endif
5019 /* for weighting field, effect of KnCh is possibly zero.
5020 double tmpPot; Vector3D tmpF;
5021 // ExactPointP and ExactPointF should also have an ExactPointPF
5022 // Similarly for area and volume element related functions
5023 // since there is no intermediate function that interfaces ExactPointP etc
5024 // division by MyFACTOR is necessary
5025 // Do parallelize before using these known charges - points or distributions
5026 for (int point = 1; point <= NbPtsKnCh; ++point) {
5027 tmpPot = ExactPointP(&(PtKnChArr+point-1)->P, globalP);
5028 (*Potential) += (PtKnChArr+point-1)->Assigned * tmpPot / MyFACTOR;
5029 ExactPointF(&(PtKnChArr+point-1)->P, globalP, &tmpF);
5030 globalF->X += (PtKnChArr+point-1)->Assigned * tmpF.X / MyFACTOR;
5031 globalF->Y += (PtKnChArr+point-1)->Assigned * tmpF.Y / MyFACTOR;
5032 globalF->Z += (PtKnChArr+point-1)->Assigned * tmpF.Z / MyFACTOR;
5033 } // for all points
5034
5035 for (int line = 1; line <= NbLinesKnCh; ++line) {
5036 (*Potential) += 0.0;
5037 globalF->X += 0.0;
5038 globalF->Y += 0.0;
5039 globalF->Z += 0.0;
5040 } // for all lines
5041
5042 for (int area = 1; area <= NbAreasKnCh; ++area) {
5043 (*Potential) += 0.0;
5044 globalF->X += 0.0;
5045 globalF->Y += 0.0;
5046 globalF->Z += 0.0;
5047 } // for all areas
5048
5049 for (int vol = 1; vol <= NbVolsKnCh; ++vol) {
5050 (*Potential) += 0.0;
5051 globalF->X += 0.0;
5052 globalF->Y += 0.0;
5053 globalF->Z += 0.0;
5054 } // for all volumes
5055
5056 // This should be the final position
5057 // *Potential = totPot;
5058 // globalF->X = totF.X;
5059 // globalF->Y = totF.Y;
5060 // globalF->Z = totF.Z;
5061 // effect of KnCh is possibly zero on weighting field
5062 */
5063
5064 // (*Potential) += VSystemChargeZero; // respect total system charge constraint
5065
5066 if (dbgFn) {
5067 printf("Final values due to all primitives and other influences: ");
5068 // printf("xfld\tyfld\tzfld\tPot\tFx\tFy\tFz\n"); // refer, do not
5069 // uncomment
5070 printf("%lg\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n\n", xfld, yfld, zfld,
5071 (*Potential), globalF->X, globalF->Y, globalF->Z);
5072 fflush(stdout);
5073 }
5074
5075 free_dvector(pPot, 1, NbPrimitives);
5076 free_dvector(plFx, 1, NbPrimitives);
5077 free_dvector(plFy, 1, NbPrimitives);
5078 free_dvector(plFz, 1, NbPrimitives);
5079
5080 return (0);
5081} // end of WtPFAtPoint
5082
5083double TriLin(double xd, double yd, double zd, double c000, double c100,
5084 double c010, double c001, double c110, double c101, double c011,
5085 double c111) {
5086 double c00 = c000 * (1.0 - xd) + c100 * xd;
5087 double c10 = c010 * (1.0 - xd) + c110 * xd;
5088 double c01 = c001 * (1.0 - xd) + c101 * xd;
5089 double c11 = c011 * (1.0 - xd) + c111 * xd;
5090 double c0 = c00 * (1.0 - yd) + c10 * yd;
5091 double c1 = c01 * (1.0 - yd) + c11 * yd;
5092 return (c0 * (1.0 - zd) + c1 * zd);
5093}
5094
5095#ifdef __cplusplus
5096} // namespace
5097#endif
int KnChPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF)
int FastVolPF(void)
int VoxelFPR(void)
int FastVolElePF(void)
void GetFlux(int ele, Point3D *localP, Vector3D *localF)
double GetPotential(int ele, Point3D *localP)
int FastPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF)
void WirePrimPF(int prim, Point3D *localP, double *Potential, Vector3D *localF)
int FastKnChPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF)
double TriPot(int ele, Point3D *localP)
void RecPrimPF(int prim, Point3D *localP, double *Potential, Vector3D *localF)
double WirePot(int ele, Point3D *localP)
void TriFlux(int ele, Point3D *localP, Vector3D *localF)
void RecFlux(int ele, Point3D *localP, Vector3D *localF)
void GetPrimPFGCS(int prim, Point3D *localP, double *Potential, Vector3D *globalF, DirnCosn3D *DirCos)
double RecPot(int ele, Point3D *localP)
int WtPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF, int IdWtField)
void WireFlux(int ele, Point3D *localP, Vector3D *localF)
void RecPF(double a, double b, double x, double y, double z, double *Potential, Vector3D *localF)
int ElePFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF)
void TriPF(double a, double b, double x, double y, double z, double *Potential, Vector3D *localF)
void GetPFGCS(int type, double a, double b, Point3D *localP, double *Potential, Vector3D *globalF, DirnCosn3D *DirCos)
int PFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF)
int FastElePFAtPoint(Point3D *, double *, Vector3D *)
int MapFPR(void)
double TriLin(double xd, double yd, double zd, double c000, double c100, double c010, double c001, double c110, double c101, double c011, double c111)
void TriPrimPF(int prim, Point3D *localP, double *Potential, Vector3D *localF)
void WirePF(double rW, double lW, double x, double y, double z, double *Potential, Vector3D *localF)
void GetPrimPF(int prim, Point3D *localP, double *Potential, Vector3D *localF)
void GetPF(int type, double a, double b, double x, double y, double z, double *Potential, Vector3D *localF)
void GetFluxGCS(int ele, Point3D *localP, Vector3D *globalF)
int WtFldFastPFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF)
double ExactThinFX_W(double rW, double lW, double X, double Y, double Z)
Definition: Isles.c:2103
double ExactCentroidalP_W(double rW, double lW)
Definition: Isles.c:1779
double ExactThinFY_W(double rW, double lW, double X, double Y, double Z)
Definition: Isles.c:2121
double ExactAxialP_W(double rW, double lW, double Z)
Definition: Isles.c:1789
int ExactThinWire(double rW, double lW, double X, double Y, double Z, double *potential, Vector3D *Flux)
Definition: Isles.c:2155
double ExactThinFZ_W(double rW, double lW, double X, double Y, double Z)
Definition: Isles.c:2139
double LineKnChPF(Point3D LineStart, Point3D LineStop, double radius, Point3D FieldPt, Vector3D *globalF)
Definition: Isles.c:2199
int ExactRecSurf(double X, double Y, double Z, double xlo, double zlo, double xhi, double zhi, double *Potential, Vector3D *Flux)
Definition: Isles.c:40
int ExactTriSurf(double zMax, double X, double Y, double Z, double *Potential, Vector3D *Flux)
Definition: Isles.c:784
double ExactThinP_W(double rW, double lW, double X, double Y, double Z)
Definition: Isles.c:2088
double AreaKnChPF(int NbVertices, Point3D *Vertex, Point3D FieldPt, Vector3D *globalF)
Definition: Isles.c:2350
double PointKnChPF(Point3D SourcePt, Point3D FieldPt, Vector3D *globalF)
Definition: Isles.c:2177
double VolumeKnChPF(int, Point3D *, Point3D, Vector3D *globalF)
Definition: Isles.c:2491
#define FarField2
Definition: Isles.h:22
#define ST_PI
Definition: Isles.h:24
#define FarField
Definition: Isles.h:21
#define MINDIST
Definition: Isles.h:17
Vector3D RotateVector3D(Vector3D *A, DirnCosn3D *DC, int Sense)
Definition: Vector.c:397
#define local2global
Definition: Vector.h:14
int neBEMMessage(const char *message)
INTFACEGLOBAL int neBEMVolumePoint(double x, double y, double z)
Point3D ReflectPrimitiveOnMirror(char Axis, int primsrc, Point3D srcpt, Point3D fldpt, double distance, DirnCosn3D *MirroredDC)
Definition: neBEM.c:3742
Point3D ReflectOnMirror(char Axis, int elesrc, Point3D srcpt, Point3D fldpt, double distance, DirnCosn3D *MirroredDC)
Definition: neBEM.c:3831
neBEMGLOBAL Element * EleArr
Definition: neBEM.h:169
neBEMGLOBAL double **** FastFY
Definition: neBEM.h:444
neBEMGLOBAL int DebugLevel
Definition: neBEM.h:235
neBEMGLOBAL int * PeriodicInY
Definition: neBEM.h:79
neBEMGLOBAL int OptStaggerFastVol
Definition: neBEM.h:404
neBEMGLOBAL double **** FastFZ
Definition: neBEM.h:444
neBEMGLOBAL double **** WtFldFastStgFZ
Definition: neBEM.h:515
neBEMGLOBAL double **** WtFldFastFZ
Definition: neBEM.h:513
neBEMGLOBAL double **** FastStgFZ
Definition: neBEM.h:446
neBEMGLOBAL int * MirrorTypeZ
Definition: neBEM.h:81
neBEMGLOBAL double **** FastStgPot
Definition: neBEM.h:445
neBEMGLOBAL double * OmitVolCrnrZ
Definition: neBEM.h:434
neBEMGLOBAL double * MirrorDistYFromOrigin
Definition: neBEM.h:82
neBEMGLOBAL double **** FastStgFXKnCh
Definition: neBEM.h:450
neBEMGLOBAL int * WtFldBlkNbYCells
Definition: neBEM.h:494
neBEMGLOBAL double **** WtFldFastFX
Definition: neBEM.h:513
neBEMGLOBAL MapVol Map
Definition: neBEM.h:396
neBEMGLOBAL double * ZPeriod
Definition: neBEM.h:80
neBEMGLOBAL PointKnCh * PointKnChArr
Definition: neBEM.h:181
neBEMGLOBAL double * OmitVolLX
Definition: neBEM.h:429
neBEMGLOBAL VolumeKnCh * VolumeKnChArr
Definition: neBEM.h:216
neBEMGLOBAL int OptStaggerMap
Definition: neBEM.h:379
neBEMGLOBAL double **** WtFldFastPot
Definition: neBEM.h:512
neBEMGLOBAL double **** FastFYKnCh
Definition: neBEM.h:448
neBEMGLOBAL double VSystemChargeZero
Definition: neBEM.h:122
neBEMGLOBAL int * WtFldBlkNbXCells
Definition: neBEM.h:493
neBEMGLOBAL double * WtFldIgnoreVolCrnrX
Definition: neBEM.h:507
neBEMGLOBAL double * PrimOriginZ
Definition: neBEM.h:73
neBEMGLOBAL double * BlkCrnrZ
Definition: neBEM.h:428
neBEMGLOBAL int NbPrimitives
Definition: neBEM.h:57
neBEMGLOBAL double **** FastStgFY
Definition: neBEM.h:446
neBEMGLOBAL int * NbVertices
Definition: neBEM.h:70
neBEMGLOBAL int * PeriodicTypeX
Definition: neBEM.h:78
neBEMGLOBAL int * PeriodicTypeY
Definition: neBEM.h:78
neBEMGLOBAL int NbPointsKnCh
Definition: neBEM.h:172
neBEMGLOBAL int OptWtFldStaggerFastVol
Definition: neBEM.h:473
neBEMGLOBAL FastAlgoVol FastVol
Definition: neBEM.h:422
neBEMGLOBAL double * PrimOriginY
Definition: neBEM.h:73
neBEMGLOBAL double * MirrorDistZFromOrigin
Definition: neBEM.h:83
neBEMGLOBAL AreaKnCh * AreaKnChArr
Definition: neBEM.h:204
neBEMGLOBAL double **** WtFldFastStgPot
Definition: neBEM.h:514
neBEMGLOBAL DirnCosn3D * PrimDC
Definition: neBEM.h:74
neBEMGLOBAL int PrimAfter
Definition: neBEM.h:351
neBEMGLOBAL double * BlkLZ
Definition: neBEM.h:427
neBEMGLOBAL double * OmitVolCrnrX
Definition: neBEM.h:432
neBEMGLOBAL int NbLinesKnCh
Definition: neBEM.h:172
neBEMGLOBAL double * OmitVolLZ
Definition: neBEM.h:431
neBEMGLOBAL int NbStgPtSkip
Definition: neBEM.h:408
neBEMGLOBAL double * XPeriod
Definition: neBEM.h:80
neBEMGLOBAL int NbVolumesKnCh
Definition: neBEM.h:172
neBEMGLOBAL double * AvAsgndChDen
Definition: neBEM.h:90
neBEMGLOBAL double * IgnoreVolCrnrY
Definition: neBEM.h:439
neBEMGLOBAL char MapVersion[10]
Definition: neBEM.h:380
neBEMGLOBAL int NbPtSkip
Definition: neBEM.h:407
neBEMGLOBAL double * WtFldIgnoreVolLZ
Definition: neBEM.h:506
neBEMGLOBAL int OptMap
Definition: neBEM.h:378
neBEMGLOBAL WtFldFastAlgoVol WtFldFastVol
Definition: neBEM.h:491
neBEMGLOBAL double * OmitVolCrnrY
Definition: neBEM.h:433
neBEMGLOBAL int * MirrorTypeY
Definition: neBEM.h:81
neBEMGLOBAL double **** FastFX
Definition: neBEM.h:444
neBEMGLOBAL int NbAreasKnCh
Definition: neBEM.h:172
neBEMGLOBAL int * ElementEnd
Definition: neBEM.h:94
neBEMGLOBAL double **** WtFldFastFY
Definition: neBEM.h:513
neBEMGLOBAL double * AvChDen
Definition: neBEM.h:90
neBEMGLOBAL double * WtFldBlkLZ
Definition: neBEM.h:496
neBEMGLOBAL double * WtFldBlkCrnrZ
Definition: neBEM.h:497
neBEMGLOBAL double **** WtFldFastStgFY
Definition: neBEM.h:515
neBEMGLOBAL double **** FastStgFX
Definition: neBEM.h:446
neBEMGLOBAL double * Radius
Definition: neBEM.h:72
neBEMGLOBAL int * MirrorTypeX
Definition: neBEM.h:81
neBEMGLOBAL double * OmitVolLY
Definition: neBEM.h:430
neBEMGLOBAL int * BlkNbXCells
Definition: neBEM.h:424
neBEMGLOBAL int * PrimType
Definition: neBEM.h:67
neBEMGLOBAL int OptReadFastPF
Definition: neBEM.h:406
neBEMGLOBAL double * PrimLX
Definition: neBEM.h:72
neBEMGLOBAL int * BlkNbZCells
Definition: neBEM.h:426
neBEMGLOBAL int * WtFldBlkNbZCells
Definition: neBEM.h:495
neBEMGLOBAL double * Solution
Definition: neBEM.h:237
neBEMGLOBAL int * ElementBgn
Definition: neBEM.h:94
neBEMGLOBAL double * PrimOriginX
Definition: neBEM.h:73
neBEMGLOBAL double ** AvWtChDen
Definition: neBEM.h:333
neBEMGLOBAL double * IgnoreVolLY
Definition: neBEM.h:436
neBEMGLOBAL double * WtFldIgnoreVolCrnrY
Definition: neBEM.h:508
neBEMGLOBAL double * IgnoreVolLX
Definition: neBEM.h:435
neBEMGLOBAL int * PeriodicInZ
Definition: neBEM.h:79
neBEMGLOBAL int * PeriodicInX
Definition: neBEM.h:79
neBEMGLOBAL double * WtFldIgnoreVolCrnrZ
Definition: neBEM.h:509
neBEMGLOBAL double * WtFldIgnoreVolLY
Definition: neBEM.h:505
neBEMGLOBAL double **** FastFXKnCh
Definition: neBEM.h:448
neBEMGLOBAL double LengthScale
Definition: neBEM.h:238
neBEMGLOBAL double * IgnoreVolLZ
Definition: neBEM.h:437
neBEMGLOBAL double **** FastFZKnCh
Definition: neBEM.h:448
neBEMGLOBAL double **** WtFldFastStgFX
Definition: neBEM.h:515
neBEMGLOBAL VoxelVol Voxel
Definition: neBEM.h:371
neBEMGLOBAL double **** FastStgFYKnCh
Definition: neBEM.h:450
neBEMGLOBAL double ** WtFieldChDen
Definition: neBEM.h:333
neBEMGLOBAL double * WtFldIgnoreVolLX
Definition: neBEM.h:504
neBEMGLOBAL int * PeriodicTypeZ
Definition: neBEM.h:78
neBEMGLOBAL LineKnCh * LineKnChArr
Definition: neBEM.h:192
neBEMGLOBAL double **** FastPot
Definition: neBEM.h:443
neBEMGLOBAL int OptKnCh
Definition: neBEM.h:52
neBEMGLOBAL double **** FastPotKnCh
Definition: neBEM.h:447
#define MyFACTOR
Definition: neBEM.h:21
neBEMGLOBAL double * IgnoreVolCrnrX
Definition: neBEM.h:438
neBEMGLOBAL char BCOutDir[256]
Definition: neBEM.h:263
neBEMGLOBAL double * YPeriod
Definition: neBEM.h:80
neBEMGLOBAL double * PrimLZ
Definition: neBEM.h:72
neBEMGLOBAL double * MirrorDistXFromOrigin
Definition: neBEM.h:82
neBEMGLOBAL double **** FastStgPotKnCh
Definition: neBEM.h:449
neBEMGLOBAL double **** FastStgFZKnCh
Definition: neBEM.h:450
neBEMGLOBAL double * IgnoreVolCrnrZ
Definition: neBEM.h:440
neBEMGLOBAL int * BlkNbYCells
Definition: neBEM.h:425
void free_dvector(double *v, long nl, long)
Definition: nrutil.c:470
double * dvector(long nl, long nh)
Definition: nrutil.c:63
Vector3D ZUnit
Definition: Vector.h:38
Vector3D YUnit
Definition: Vector.h:37
Vector3D XUnit
Definition: Vector.h:36
double CrnrX
Definition: neBEM.h:414
int NbBlocks
Definition: neBEM.h:418
double CrnrZ
Definition: neBEM.h:416
double CrnrY
Definition: neBEM.h:415
double LZ
Definition: neBEM.h:413
int NbOmitVols
Definition: neBEM.h:419
int NbIgnoreVols
Definition: neBEM.h:420
double YStagger
Definition: neBEM.h:417
double LY
Definition: neBEM.h:412
double LX
Definition: neBEM.h:411
int NbYCells
Definition: neBEM.h:393
double Ymax
Definition: neBEM.h:386
double YStagger
Definition: neBEM.h:390
double Zmax
Definition: neBEM.h:388
double ZStagger
Definition: neBEM.h:391
int NbZCells
Definition: neBEM.h:394
double Xmax
Definition: neBEM.h:384
double Xmin
Definition: neBEM.h:383
double XStagger
Definition: neBEM.h:389
double Zmin
Definition: neBEM.h:387
int NbXCells
Definition: neBEM.h:392
double Ymin
Definition: neBEM.h:385
Definition: Vector.h:21
double X
Definition: Vector.h:22
double Z
Definition: Vector.h:24
double Y
Definition: Vector.h:23
double Z
Definition: Vector.h:31
double Y
Definition: Vector.h:30
double X
Definition: Vector.h:29
double Zmax
Definition: neBEM.h:363
double Xmax
Definition: neBEM.h:359
int NbXCells
Definition: neBEM.h:367
double Ymax
Definition: neBEM.h:361
double Zmin
Definition: neBEM.h:362
int NbZCells
Definition: neBEM.h:369
int NbYCells
Definition: neBEM.h:368
double Xmin
Definition: neBEM.h:358
double Ymin
Definition: neBEM.h:360
int NbIgnoreVols
Definition: neBEM.h:489
double LZ
Definition: neBEM.h:482
double YStagger
Definition: neBEM.h:486
double LY
Definition: neBEM.h:481
double LX
Definition: neBEM.h:480
double CrnrY
Definition: neBEM.h:484
double CrnrX
Definition: neBEM.h:483
double CrnrZ
Definition: neBEM.h:485