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