Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
neBEM.c
Go to the documentation of this file.
1/*
2(c) 2005, Supratik Mukhopadhayay, Nayana Majumdar
3*/
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <time.h>
9#include <unistd.h>
10
11#ifdef _OPENMP
12#include <omp.h>
13#endif
14
15#include "Isles.h"
16#include "NR.h"
17#include "Vector.h"
18
19#include <gsl/gsl_cblas.h>
20#include <gsl/gsl_linalg.h>
21#include <gsl/gsl_matrix.h>
22
23#include "neBEMInterface.h"
24#include "neBEM.h"
25
26#ifdef __cplusplus
27namespace neBEM {
28#endif
29
31
32// At the end of this function, one should have the charge density distribution
33// This function is not called when only post-processing is being carried out,
34// i.e., when NewModel == NewMesh == NewBC == 0.
35// In such an event, the solution is directly read using ReadSolution
36int ComputeSolution(void) {
37 int LHMatrix(void), RHVector(void), Solve(void);
38 int InvertMatrix(void);
39 int ReadInvertedMatrix(void);
40#ifdef _OPENMP
41 double time_begin = 0., time_end = 0.;
42#endif
43 printf(
44 "----------------------------------------------------------------\n\n");
45 printf("ComputeSolution: neBEM solution begins ...\n");
46 printf(" TimeStep: %d\n", TimeStep);
47 printf(" NewModel: %d, NewMesh: %d, NewBC: %d, NewPP: %d\n",
49 printf(
50 " ModelCntr: %d, MeshCntr: %d, BCCntr: %d, PPCntr: %d\n",
52 fflush(stdout);
53 DebugISLES = 0; // an integer declared in Isles header file
54
56
57 switch (OptInvMatProc) {
58 case 0:
59 OptLU = 1;
60 OptSVD = 0;
61 OptGSL = 0;
62 break;
63 case 1:
64 OptLU = 0;
65 OptSVD = 1;
66 OptGSL = 0;
67 break;
68 case 2:
69 OptLU = 0;
70 OptSVD = 0;
71 OptGSL = 1;
72 break;
73 default:
74 OptLU = 1;
75 OptSVD = 0;
76 OptGSL = 0;
77 }
78 if ((OptSVD == 0) && (OptLU == 0) && (OptGSL == 0)) {
79 printf("Cannot proceed with OptSVD, OptLU and OptGSL zero.\n");
80 printf("Assuming the safer option OptSVD = 1.\n");
81 OptLU = 0;
82 OptSVD = 1;
83 OptGSL = 0;
84 }
85 if ((OptSVD == 1) && (OptLU == 1) && (OptGSL == 1)) {
86 printf("Cannot proceed with all OptSVD, OptLU and OptGSL one.\n");
87 printf("Assuming the safer option OptSVD = 1.\n");
88 OptLU = 0;
89 OptSVD = 1;
90 OptGSL = 0;
91 }
92
93 NbConstraints = 0;
95 printf(
96 "ComputeSolution: Simultaneous presence of OptSystemChargeZero && "
97 "NbFloatingConductors!\n");
98 printf(" Returning ...\n");
99 return (-1);
100 }
101 if (OptSystemChargeZero) // Constraint making total charge on the sysyem,
102 // zero
103 {
108 NbUnknowns; // which equation & unknown relates to this
109 } // constraint
110 if (NbFloatingConductors) // Number of floating conductors now restricted to
111 // one
112 {
113 if (NbFloatingConductors > 1) {
114 printf("Number of floating conductors > 1! ... not yet implemented.\n");
115 printf("Returning\n");
116 return -1;
117 }
121 NbFloatCon = NbUnknowns; // which equation and unknown relates to this
122 } // floating conductor
123
124 if (NewModel || NewMesh) {
127 } else {
129 }
130 // Computation of the influence coefficient matrix and inversion of the same
131 // is necessary only when we are considering a NewModel, and / or a NewMesh,
132 // i.e., InfluenceMatrixFlag is true.
133 // When OptChargingUp is true, then influence matrix, if not already
134 // available, is computed in the EffectChargingUp function. For an existing
135 // model and unchanged mesh, we can simply read in the relevant inverted
136 // matrix.
137 if (TimeStep == 1) {
139 startClock = clock();
140 printf("ComputeSolution: LHMatrix ... ");
141 fflush(stdout);
142#ifdef _OPENMP
143 time_begin = omp_get_wtime();
144#endif
145 int fstatus = LHMatrix();
146#ifdef _OPENMP
147 time_end = omp_get_wtime();
148 printf("Elapsed time: %lg\n", time_end - time_begin);
149#endif
150 if (fstatus != 0) {
151 neBEMMessage("ComputeSolution - LHMatrix");
152 return -1;
153 }
154 printf("ComputeSolution: LHMatrix done!\n");
155 fflush(stdout);
156 stopClock = clock();
158 printf("to setup influence matrix.\n");
159
160 startClock = clock();
161 printf("ComputeSolution: Inverting influence matrix ...\n");
162 fflush(stdout);
163 fstatus = InvertMatrix();
164 if (fstatus != 0) {
165 neBEMMessage("ComputeSolution - InvertMatrix");
166 return -1;
167 }
168 printf("ComputeSolution: Matrix inversion over.\n");
169 stopClock = clock();
171 printf("to invert influence matrix.\n");
172 } // if InfluenceMatrixFlag
173
174 if ((!InfluenceMatrixFlag) && NewBC) {
175 if (OptStoreInvMatrix) {
176 startClock = clock();
177 printf(
178 "ComputeSolution: Reading inverted matrix ... will take time ...");
179 int fstatus = ReadInvertedMatrix();
180 if (fstatus != 0) {
181 neBEMMessage("ComputeSolution - ReadInvertedMatrix");
182 return -1;
183 }
184 printf(" done!\n");
185 stopClock = clock();
187 printf("to read inverted influence matrix.\n");
188 } else {
189 neBEMMessage("ComputeSolution - NewBC but no InvMat ... ");
190 neBEMMessage("don't know how to proceed!\n");
191 return -1;
192 }
193 } // if (!InfluenceMatrixFlag) && NewBC
194 } // if TimeStep == 1
195
196 // If TimeStep > 1, use the Infl (LHS) and InvMat existing in memory
197
198 int fstatus = 0;
199
200 // Known charges
201 startClock = clock();
202 printf("ComputeSolution: neBEMKnownCharges ... ");
203 fflush(stdout);
204 fstatus = neBEMKnownCharges();
205 if (fstatus != 0) {
206 neBEMMessage("ComputeSolution - neBEMKnownCharges");
207 return -1;
208 }
209 printf("ComputeSolution: neBEMKnownCharges done!\n");
210 fflush(stdout);
211 stopClock = clock();
213 printf("to set up neBEMKnownCharges.\n");
214
215 // Charging up
216 startClock = clock();
217 printf("ComputeSolution: neBEMChargingUp ... ");
218 fflush(stdout);
220 if (fstatus != 0) {
221 neBEMMessage("ComputeSolution - neBEMChargingUp");
222 return -1;
223 }
224 printf("ComputeSolution: neBEMChargingUp done!\n");
225 fflush(stdout);
226 stopClock = clock();
228 printf("to set up neBEMChargingUp.\n");
229
230 // RHS
231 startClock = clock();
232 printf("ComputeSolution: RHVector ... ");
233 fflush(stdout);
234 fstatus = RHVector();
235 if (fstatus != 0) {
236 neBEMMessage("ComputeSolution - RHVector");
237 return -1;
238 }
239 printf("ComputeSolution: RHVector done!\n");
240 fflush(stdout);
241 stopClock = clock();
243 printf("to set up RH vector.\n");
244
245 // Solve
246 // The Solve routine simply involves the matrix
247 // multiplication of inverted matrix and the current RHVector.
248 startClock = clock();
249 printf("ComputeSolution: Solve ... ");
250 fflush(stdout);
251#ifdef _OPENMP
252 time_begin = omp_get_wtime();
253#endif
254 fstatus = Solve();
255#ifdef _OPENMP
256 time_end = omp_get_wtime();
257 printf("Elapsed time: %lg\n", time_end - time_begin);
258#endif
259 if (fstatus != 0) {
260 neBEMMessage("ComputeSolution - Solve");
261 return -1;
262 }
263 printf("ComputeSolution: Solve done!\n");
264 fflush(stdout);
265 stopClock = clock();
267 printf("to compute solution.\n");
268
269 // The other locations where this matrix is freed is in
270 // InvertMatrix (if OptValidateSolution is false!),
271 // or in
272 // Solve (due to a combination of OptValidateSolution true and
273 // InfluenceMatrixFlag false)
274 // due to RepeatLHMatrix
275 // or OptStoreInflMatrix.
278
279 printf("ComputeSolution: neBEM solution ends ...\a\n");
280 fflush(stdout);
281 return (0);
282} // end of neBEM
283
284// The coordinates of and distances from the barycentre of the source element
285// have been included in the computations and are being passed as parameters
286// of the ComputeInfluence (and to several successivey called functions).
287// This is because, while the influence of triangular elements are computed
288// based on a local coordinate system that has its origin at the right-angle
289// corner of the triangle, the approximate influence of these elements needs
290// to be computed based on a bary-centric co-ordinate system of the source
291// element. This additional computation and extra burden of passing parameters
292// can be reduced if the exact influence due to triangular elements can be
293// computed based on a bary-centric co-ordinate system.
294// Note that the co-ordinate transformations, that require the direction
295// cosines of the local co-ordinate system is always the one already defined
296// for the element. This implies that the directions cosines are assumed to
297// remain unchanged when shifted from the right-corner of the triangle to its
298// bary-centre.
299// The problem does not arise for a rectangular element since the exact
300// influence due to a rectangular element is always computed in terms of its
301// centroidal co-ordinate system.
302// The same is true for wire elements - origin of the LCS and the centroid are
303// collocated.
304int LHMatrix(void) {
305#ifdef _OPENMP
306 int dbgFn = 0;
307#endif
308 printf(
309 "\nLHMatrix: The size of the Influence coefficient matrix is %d X %d\n",
311 fflush(stdout);
312
313 // The influence coefficient matrix is created only when the
314 // InfluenceMatrixFlag
315 // is true. The other eventualities when this can get created is when
316 // this flag is false but the OptValidateSolution flag is true (through
317 // RepeatLHMatrix (here!)
318 // or1s
319 // OptStoreInflMatrix (in function Solve)).
320 Inf = dmatrix(1, NbEqns, 1, NbUnknowns);
321
322 // Influence coefficient matrix
323 // For each field point where the boundary condition is known (collocation
324 // point), influence from all the source elements needs to be summed up
325 // The field points are followed using elefld (field counter) and the
326 // source elements are followed using elesrc (source counter)
327 // printf("field point: "); // do not remove
328 printf("Computing influence coefficient matrix ... will take time ...\n");
329
330#ifdef _OPENMP
331 int nthreads = 1, tid = 0;
332 #pragma omp parallel private(nthreads, tid)
333#endif
334 {
335#ifdef _OPENMP
336 if (dbgFn) {
337 tid = omp_get_thread_num();
338 if (tid == 0) {
339 nthreads = omp_get_num_threads();
340 printf("Starting influence matrix computation with %d threads\n",
341 nthreads);
342 }
343 }
344#endif
345 // printf("Field point:");
346 // fflush(stdout);
347
348 for (int elefld = 1; elefld <= NbElements; ++elefld) {
349 // printf("%6d", elefld);
350 // fflush(stdout); // do not remove
351
352 // Retrieve element properties at the field point
353 // boundary condn applied at collocation point
354 const double xfld = (EleArr + elefld - 1)->BC.CollPt.X;
355 const double yfld = (EleArr + elefld - 1)->BC.CollPt.Y;
356 const double zfld = (EleArr + elefld - 1)->BC.CollPt.Z;
357
358#ifdef _OPENMP
359 #pragma omp for
360#endif
361 for (int elesrc = 1; elesrc <= NbElements; ++elesrc) {
362 if (DebugLevel == 301) {
363 printf("\n\nelefld: %d, elesrc: %d\n", elefld, elesrc);
364 }
365
366 // Retrieve element properties at the field point
367 const int primsrc = (EleArr + elesrc - 1)->PrimitiveNb;
368 const double xsrc = (EleArr + elesrc - 1)->G.Origin.X;
369 const double ysrc = (EleArr + elesrc - 1)->G.Origin.Y;
370 const double zsrc = (EleArr + elesrc - 1)->G.Origin.Z;
371
372 if ((EleArr + elesrc - 1)->E.Type == 0) {
373 printf(
374 "LHMatrix: Wrong EType for elesrc %d element %d on %dth "
375 "primitive!\n",
376 elesrc, (EleArr + elesrc - 1)->Id, primsrc);
377 exit(-1);
378 }
379
380 // The total influence is due to elements on the basic device and due to
381 // virtual elements arising out of repetition, reflection etc and not
382 // residing on the basic device
383
384 // Influence due to elements belonging to the basic device
385 {
386 Point3D localP;
387 // Through InitialVector[], field point gets translated to ECS origin
388 // Axes direction are, however, still global which when rotated to ECS
389 // system, yields FinalVector[].
390 { // Rotate point3D from global to local system
391 double TransformationMatrix[3][3] = {{0.0, 0.0, 0.0},
392 {0.0, 0.0, 0.0},
393 {0.0, 0.0, 0.0}};
394 DirnCosn3D *DirCos = &(EleArr + elesrc - 1)->G.DC;
395
396 TransformationMatrix[0][0] = DirCos->XUnit.X;
397 TransformationMatrix[0][1] = DirCos->XUnit.Y;
398 TransformationMatrix[0][2] = DirCos->XUnit.Z;
399 TransformationMatrix[1][0] = DirCos->YUnit.X;
400 TransformationMatrix[1][1] = DirCos->YUnit.Y;
401 TransformationMatrix[1][2] = DirCos->YUnit.Z;
402 TransformationMatrix[2][0] = DirCos->ZUnit.X;
403 TransformationMatrix[2][1] = DirCos->ZUnit.Y;
404 TransformationMatrix[2][2] = DirCos->ZUnit.Z;
405
406 double InitialVector[3] = {xfld - xsrc, yfld - ysrc, zfld - zsrc};
407 double FinalVector[3] = {0., 0., 0.};
408 for (int i = 0; i < 3; ++i) {
409 for (int j = 0; j < 3; ++j) {
410 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
411 }
412 }
413
414 localP.X = FinalVector[0];
415 localP.Y = FinalVector[1];
416 localP.Z = FinalVector[2];
417 }
418
419 // Initiate debugging, if necessary
420 if ((elefld == 0) && (elesrc == 0))
421 DebugISLES = 1;
422 else
423 DebugISLES = 0;
424
425 Inf[elefld][elesrc] = ComputeInfluence(elefld, elesrc, &localP,
426 &(EleArr + elesrc - 1)->G.DC);
427 if (DebugLevel == 301) {
428 printf("elefld: %d, elesrc: %d, Influence: %.16lg\n", elefld,
429 elesrc, Inf[elefld][elesrc]);
430 }
431
432 // Take care of reflections of basic device
433 // At present, reflection on a single mirror is allowed
434
435 if (MirrorTypeX[primsrc] || MirrorTypeY[primsrc] ||
436 MirrorTypeZ[primsrc]) {
437 printf(
438 "Mirror not correctly implemented in this version of neBEM "
439 "...\n");
440 exit(0);
441 } // reflections of basic device, taken care of
442
443 DebugISLES =
444 0; // Stop beyond basic device - may need changes. CHECK!
445 } // end of influence due to elements belonging to the basic device
446
447 { // Influence due to virtual elements
448
449 // If the source element is repeated due to periodicity (the field
450 // points remain unchanged), the influence at the field point will
451 // change due to additional influence of the extra elements. The
452 // repeated elements have properties identical to the real element
453 // (including the solved value of charge density - otherwise we would
454 // not be able to simply add up the influence at the field point!),
455 // except that its location is determined by direction of periodicty
456 // (at present assumed to be along one of the coordinate axes, but
457 // this constraint can be easily relaxed later - we can have a
458 // direction cosine along which the elements may be repeated) and the
459 // distance of repeatition. Thus, for each repeated element, we need
460 // to compute its position and the rest remains identical as above.
461 // The influence, evaluated as a temporary double, can be added to the
462 // base value computed above. PeriodicInX etc are either zero or +ve
463
464 if ((PeriodicTypeX[primsrc] == 1) || (PeriodicTypeY[primsrc] == 1) ||
465 (PeriodicTypeZ[primsrc] == 1)) {
466 if (PeriodicInX[primsrc] || PeriodicInY[primsrc] ||
467 PeriodicInZ[primsrc]) {
468 for (int xrpt = -PeriodicInX[primsrc];
469 xrpt <= PeriodicInX[primsrc]; ++xrpt) {
470 double XOfRpt = xsrc + XPeriod[primsrc] * (double)xrpt;
471
472 for (int yrpt = -PeriodicInY[primsrc];
473 yrpt <= PeriodicInY[primsrc]; ++yrpt) {
474 double YOfRpt = ysrc + YPeriod[primsrc] * (double)yrpt;
475
476 for (int zrpt = -PeriodicInZ[primsrc];
477 zrpt <= PeriodicInZ[primsrc]; ++zrpt) {
478 double ZOfRpt = zsrc + ZPeriod[primsrc] * (double)zrpt;
479
480 if ((xrpt == 0) && (yrpt == 0) && (zrpt == 0))
481 continue; // this is the base device
482
483 Point3D localP;
484 // axis direction in the global system
485 { // Rotate point3D from global to local system
486 double TransformationMatrix[3][3] = {
487 {0.0, 0.0, 0.0},
488 {0.0, 0.0, 0.0},
489 {0.0, 0.0, 0.0}};
490 DirnCosn3D *DirCos = &(EleArr + elesrc - 1)->G.DC;
491
492 TransformationMatrix[0][0] = DirCos->XUnit.X;
493 TransformationMatrix[0][1] = DirCos->XUnit.Y;
494 TransformationMatrix[0][2] = DirCos->XUnit.Z;
495 TransformationMatrix[1][0] = DirCos->YUnit.X;
496 TransformationMatrix[1][1] = DirCos->YUnit.Y;
497 TransformationMatrix[1][2] = DirCos->YUnit.Z;
498 TransformationMatrix[2][0] = DirCos->ZUnit.X;
499 TransformationMatrix[2][1] = DirCos->ZUnit.Y;
500 TransformationMatrix[2][2] = DirCos->ZUnit.Z;
501
502 // Vector in the GCS
503 double InitialVector[3] = {xfld - XOfRpt, yfld - YOfRpt, zfld - ZOfRpt};
504 double FinalVector[3] = {0., 0., 0.};
505 for (int i = 0; i < 3; ++i) {
506 for (int j = 0; j < 3; ++j) {
507 FinalVector[i] +=
508 TransformationMatrix[i][j] * InitialVector[j];
509 }
510 }
511
512 localP.X = FinalVector[0]; // Vector in the ECS
513 localP.Y = FinalVector[1];
514 localP.Z = FinalVector[2];
515 } // Point3D rotated
516
517 // Direction cosines remain unchanged for a regular
518 // repetition
519 double AddnalInfl = ComputeInfluence(elefld, elesrc, &localP,
520 &(EleArr + elesrc - 1)->G.DC);
521 Inf[elefld][elesrc] += AddnalInfl;
522
523 if (DebugLevel == 301) {
524 printf("REPEATED\n");
525 printf("elefld: %d, elesrc: %d\n", elefld, elesrc);
526 printf("xsrc: %lg, ysrc: %lg, zsrc: %lg\n", xsrc, ysrc,
527 zsrc);
528 printf("xrpt: %d, yrpt: %d, zrpt: %d\n", xrpt, yrpt,
529 zrpt);
530 printf("XOfRpt: %lg, YOfRpt: %lg, ZOfRpt: %lg\n", XOfRpt,
531 YOfRpt, ZOfRpt);
532 printf("AddnalInfl: %lg\n", AddnalInfl);
533 printf("Inf: %lg\n", Inf[elefld][elesrc]);
534 }
535
536 // Take care of reflections of repetitions
537 // At present, reflection on a single mirror is allowed
538 if (MirrorTypeX[primsrc] || MirrorTypeY[primsrc] ||
539 MirrorTypeZ[primsrc]) {
540 printf(
541 "Mirror not correctly implemented in this version of "
542 "neBEM ...\n");
543 exit(0);
544
545 Point3D fldpt, srcpt;
546 DirnCosn3D DirCos;
547
548 fldpt.X = xfld;
549 fldpt.Y = yfld;
550 fldpt.Z = zfld;
551 srcpt.X = XOfRpt;
552 srcpt.Y = YOfRpt;
553 srcpt.Z = ZOfRpt;
554
555 if (MirrorTypeX[primsrc]) {
556 MirrorTypeY[primsrc] = 0;
557 MirrorTypeZ[primsrc] = 0;
558 }
559 if (MirrorTypeY[primsrc]) MirrorTypeZ[primsrc] = 0;
560
561 if (MirrorTypeX[primsrc]) {
562 localP = ReflectOnMirror('X', elesrc, srcpt, fldpt,
563 MirrorDistXFromOrigin[primsrc],
564 &DirCos);
565 AddnalInfl =
566 ComputeInfluence(elefld, elesrc, &localP, &DirCos);
567
568 if (MirrorTypeX[primsrc] ==
569 1) // opposite charge density
570 Inf[elefld][elesrc] -=
571 AddnalInfl; // classical image charge
572 if (MirrorTypeX[primsrc] == 2) // same charge density
573 Inf[elefld][elesrc] += AddnalInfl;
574 }
575
576 if (MirrorTypeY[primsrc]) {
577 localP = ReflectOnMirror('Y', elesrc, srcpt, fldpt,
578 MirrorDistYFromOrigin[primsrc],
579 &DirCos);
580 AddnalInfl =
581 ComputeInfluence(elefld, elesrc, &localP, &DirCos);
582
583 if (MirrorTypeY[primsrc] ==
584 1) // opposite charge density
585 Inf[elefld][elesrc] -=
586 AddnalInfl; // classical image charge
587 if (MirrorTypeY[primsrc] == 2) // same charge density
588 Inf[elefld][elesrc] += AddnalInfl;
589 }
590
591 if (MirrorTypeZ[primsrc]) {
592 localP = ReflectOnMirror('Z', elesrc, srcpt, fldpt,
593 MirrorDistZFromOrigin[primsrc],
594 &DirCos);
595 AddnalInfl =
596 ComputeInfluence(elefld, elesrc, &localP, &DirCos);
597
598 if (MirrorTypeZ[primsrc] ==
599 1) // opposite charge density
600 Inf[elefld][elesrc] -=
601 AddnalInfl; // classical image charge
602 if (MirrorTypeZ[primsrc] == 2) // same charge density
603 Inf[elefld][elesrc] += AddnalInfl;
604 }
605
606 if (DebugLevel == 301) {
607 printf("REPEATED and reflected\n");
608 printf("elefld: %d, elesrc: %d\n", elefld, elesrc);
609 printf("xsrc: %lg, ysrc: %lg, zsrc: %lg\n", xsrc, ysrc,
610 zsrc);
611 printf("xrpt: %d, yrpt: %d, zrpt: %d\n", xrpt, yrpt,
612 zrpt);
613 printf("XOfRpt: %lg, YOfRpt: %lg, ZOfRpt: %lg\n",
614 XOfRpt, YOfRpt, ZOfRpt);
615 printf("AddnalInfl: %lg\n", AddnalInfl);
616 printf("Inf: %lg\n", Inf[elefld][elesrc]);
617 }
618 } // reflections of repetitions taken care of
619
620 } // for zrpt
621 } // for yrpt
622 } // for xrpt
623 } // PeriodicInX || PeriodicInY || PeriodicInZ
624 } // PeriodicType == 1
625 } // end of influence due to virtual elements
626
627 } // loop for elesrc, source element (influencing)
628
629 // printf("\b\b\b\b\b\b");
630 } // loop for elefld, field element (influenced)
631 } // pragma omp parallel
632
633 // Enforce total charge on the system to be zero.
634 // All the voltages in the system need to be shifted by an unknown amount
635 // V_shift
636 // V_shift is obtained by introducing one additional row and column and
637 // impposing the constraint that the sum of all the charges in the system is
638 // zero.
639 // Please note that charge = Element Charge Density * Element Area
641 // an additional column
642 for (int row = 1; row <= NbEqns; ++row) {
643 if (((EleArr + row - 1)->E.Type == 1) ||
644 ((EleArr + row - 1)->E.Type == 3)) // The
645 Inf[row][NbUnknowns] = 1.0; // VSystemChargeZero is subtracted only
646 else // from potentials
647 Inf[row][NbUnknowns] = 0.0;
648 }
649
650 // an additional row
651 for (int col = 1; col <= NbUnknowns; ++col)
652 Inf[NbEqns][col] =
653 (EleArr + col - 1)->G.dA; // if charge density is computed
654 // Inf[NbEqns][col] = 1.0; // if charge is computed
655
656 // the last element
657 Inf[NbEqns][NbUnknowns] = 0.0;
658 } // if(OptSystemChargeZero)
659 else {
660 VSystemChargeZero = 0.0;
661 }
662
663 if (NbFloatingConductors) // assume only one floating conductor
664 {
665 // an additional column
666 for (int row = 1; row <= NbEqns; ++row) {
667 int etfld = (EleArr + row - 1)->E.Type;
668 if (etfld == 3) // element of a floating conductor
669 Inf[row][NbUnknowns] = -1.0;
670 else
671 Inf[row][NbUnknowns] = 0.0;
672 } // additional column
673
674 // an additional row
675 for (int col = 1; col <= NbUnknowns; ++col) {
676 int etfld = (EleArr + col - 1)->E.Type;
677 if (etfld == 3) // element of a floating conductor
678 {
679 Inf[NbEqns][col] =
680 (EleArr + col - 1)->G.dA; // if charge density is computed
681 // Inf[NbEqns][col] = 1.0; // if charge is computed
682 } else {
683 Inf[NbEqns][col] = 0.0; // if charge density is computed
684 // Inf[NbEqns][col] = 0.0; // if charge is computed
685 }
686 } // additional row
687
688 // the last element
689 Inf[NbEqns][NbUnknowns] = 0.0;
690 } // if NbFloatingConductors
691
693 printf("storing the influence matrix in a formatted file ...\n");
694 fflush(stdout);
695
696 char InflFile[256];
697 strcpy(InflFile, MeshOutDir);
698 strcat(InflFile, "/Infl.out");
699 FILE *fInf = fopen(InflFile, "w+");
700 if (fInf == NULL) {
701 neBEMMessage("LHMatrix - InflFile");
702 return -1;
703 }
704 fprintf(fInf, "%d %d\n", NbEqns, NbUnknowns);
705
706 for (int elefld = 1; elefld <= NbEqns; ++elefld) {
707 for (int elesrc = 1; elesrc <= NbUnknowns; ++elesrc)
708 fprintf(fInf, "%.16lg\n", Inf[elefld][elesrc]);
709 fprintf(fInf, "\n");
710 }
711
712 fclose(fInf);
713 } // if OptStoreInflMatrix && OptFormattedFile
714
715 if (OptStoreInflMatrix &&
716 OptUnformattedFile) // Raw cannot be implemented now.
717 { // It may be because of the memory allocation using the NR routines -
719 "LHMatrix - Binary write of Infl matrix not implemented yet.\n");
720 return -1;
721
722 char InflFile[256];
723 strcpy(InflFile, MeshOutDir);
724 strcat(InflFile, "/RawInfl.out");
725 FILE *fInf = fopen(InflFile, "wb");
726 if (fInf == NULL) {
727 neBEMMessage("LHMatrix - RawInflFile");
728 return -1;
729 }
730 printf("\nfInf: %p\n", (void *)fInf);
731 int rfw = fwrite(Inf, sizeof(double), NbEqns * NbUnknowns, fInf);
732 fclose(fInf);
733 printf("\nNb of items successfully written in raw mode in %s is %d\n",
734 InflFile, rfw);
735
736 /* following block used to check raw reading from a file written in raw
737 double **RawInf;
738 RawInf = dmatrix(1,NbEqns,1,NbUnknowns);
739 strcpy(InflFile, MeshOutDir); strcat(InflFile, "/RawInfl.out");
740 fInf = fopen(InflFile, "rb");
741 // assert(fInf != NULL);
742 if(fInf == NULL)
743 {
744 neBEMMessage("LHMatrix - RawInflFile");
745 return -1;
746 }
747 rfw = fread(RawInf, sizeof(double), NbEqns*NbUnknowns, fInf);
748 fclose(fInf);
749 printf("Nb of items successfully read in raw mode from %s is %d\n",
750 InflFile, rfw);
751 for(int unknown = 1; unknown <= NbUnknowns; ++unknown)
752 for(int eqn = 1; eqn <= NbEqns; ++eqn)
753 printf("Unknown:%d, Eqn:%d => diff Inf: %lg, RawInf: %lg is
754 %lg\n", unknown, eqn, Inf[unknown][eqn], RawInf[unknown][eqn],
755 fabs(Inf[unknown][eqn] -
756 RawInf[unknown][eqn])); Please do not delete */
757 } // if OptStoreInflMatrix && OptUnformattedFile
758
759 neBEMState = 6;
760
761 return (0);
762} // end of LHMatrix
763
764/* To be tried later
765// Generate a row vector of influence (in terms of potential or continutity) due
766to all the elements at a given field point
767// This row vector, when multiplied by the charge density on all the elements
768(how about non-elemental charges?) gives rise to the
769// total potential, or field (normal component for a given coordinate system) at
770that point
771// If no specific direction is provided, the GCS is used as default
772Vector1D* InflVec(Point3D fldpt, DirnCosn3D *fldDC, int Pot0Cont1) {
773 int dbgFn = 0;
774 int primsrc;
775 double xsrc, ysrc, zsrc;
776 Point3D localP;
777
778 printf("\nLHMatrix: The size of the Influence coefficient vector is %d\n",
779 NbUnknowns); fflush(stdout);
780
781 // Influence coefficient vector
782 // For each field point influences from all the source elements
783 // need to be summed up.
784 // The source elements are followed using elesrc (source counter)
785 printf("Computing influence coefficient vector ... will take some time ...\n");
786
787 int nthreads = 1, tid = 0;
788#pragma omp parallel private(nthreads, tid)
789 {
790 if(dbgFn) {
791 tid = omp_get_thread_num();
792 if (tid == 0) {
793 nthreads = omp_get_num_threads();
794 printf("Starting influence matrix computation with %d threads\n",
795 nthreads);
796 }
797 }
798
799 double xfld = fldpt.X;
800 double yfld = fldpt.Y;
801 double zfld = fldpt.Z;
802
803#pragma omp for private(primsrc, xsrc, ysrc, zsrc, localP)
804 for (int elesrc = 1; elesrc <= NbElements; ++elesrc) {
805 if (DebugLevel == 301) {
806 printf("\n\nelesrc: %d\n", elesrc);
807 }
808
809 // Retrieve element properties at the field point
810 int primsrc = (EleArr+elesrc-1)->PrimitiveNb;
811 double xsrc = (EleArr+elesrc-1)->G.Origin.X;
812 double ysrc = (EleArr+elesrc-1)->G.Origin.Y;
813 double zsrc = (EleArr+elesrc-1)->G.Origin.Z;
814
815 // The total influence is due to elements on the basic device
816and due to
817 // virtual elements arising out of repetition, reflection etc
818and not
819 // residing on the basic device
820
821 // Influence due to elements belonging to the basic device
822 {
823 // point translated to the ECS origin, but axes direction global
824 { // Rotate point3D from global to local system
825 double InitialVector[4];
826 double TransformationMatrix[4][4] = {{0.0, 0.0, 0.0, 0.0},
827 {0.0, 0.0, 0.0, 0.0},
828 {0.0, 0.0, 0.0, 0.0},
829 {0.0, 0.0, 0.0, 1.0}};
830 DirnCosn3D *DirCos = &(EleArr+elesrc-1)->G.DC;
831 double FinalVector[4];
832
833 InitialVector[0] = xfld - xsrc; InitialVector[1] = yfld - ysrc;
834 InitialVector[2] = zfld - zsrc; InitialVector[3] = 1.0;
835
836 TransformationMatrix[0][0] = DirCos->XUnit.X;
837 TransformationMatrix[0][1] = DirCos->XUnit.Y;
838 TransformationMatrix[0][2] = DirCos->XUnit.Z;
839 TransformationMatrix[1][0] = DirCos->YUnit.X;
840 TransformationMatrix[1][1] = DirCos->YUnit.Y;
841 TransformationMatrix[1][2] = DirCos->YUnit.Z;
842 TransformationMatrix[2][0] = DirCos->ZUnit.X;
843 TransformationMatrix[2][1] = DirCos->ZUnit.Y;
844 TransformationMatrix[2][2] = DirCos->ZUnit.Z;
845
846 for(int i = 0; i < 4; ++i)
847 {
848 FinalVector[i] = 0.0;
849 for(int j = 0 ; j < 4; ++j)
850 {
851 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
852 }
853 }
854
855 localP.X = FinalVector[0];
856 localP.Y = FinalVector[1];
857 localP.Z = FinalVector[2];
858 } // Point3D rotated
859
860 // Initiate debugging, if necessary
861 if(elesrc == 0)
862 DebugISLES = 1;
863 else
864 DebugISLES = 0;
865
866 InfVec[elesrc] = ComputeEleInf(Pot0Cont1, elesrc, &localP,
867&(EleArr+elesrc-1)->G.DC); if(DebugLevel == 301)
868 {
869 printf("elesrc: %d, Influence: %.16lg\n", elesrc,
870InfVec[elesrc]);
871 }
872
873 // Take care of reflections of basic device
874 // At present, reflection on a single mirror is allowed
875
876 if(MirrorTypeX[primsrc] || MirrorTypeY[primsrc] ||
877MirrorTypeZ[primsrc])
878 {
879 printf("Mirror not correctly implemented in this version of neBEM ...\n");
880 exit(0);
881
882 Point3D srcpt;
883 DirnCosn3D DirCos;
884
885 srcpt.X = xsrc; srcpt.Y = ysrc; srcpt.Z = zsrc;
886
887 if(MirrorTypeX[primsrc])
888 { MirrorTypeY[primsrc] = 0; MirrorTypeZ[primsrc] = 0; }
889 if(MirrorTypeY[primsrc]) // no point checking MirrorTypeX
890 MirrorTypeZ[primsrc] = 0;
891
892 // If the reflection is other than that of an element (a known
893space charge,
894 // for example), elesrc should be 0 and no question of
895reflection of DC
896 // would arise. However, if the space charge is itself
897distributed on a
898 // surface or in a volume, reflection of DC etc will be
899important. What
900 // happens when reflection of an wire is considered?
901 // At a later stage, reflection and periodicity should become a
902property
903 // of an element and should be computed through a single call of
904 // ComputeInfluence
905 if(MirrorTypeX[primsrc])
906 {
907 localP = ReflectOnMirror('X', elesrc, srcpt, fldpt,
908 MirrorDistXFromOrigin[primsrc], &DirCos);
909 double AddnalInfl = ComputeEleInf(Pot0Cont1, elesrc,
910&localP, &DirCos);
911
912 if(MirrorTypeX[primsrc] == 1) // element having
913opposite charge density Inf[elefld][elesrc] -= AddnalInfl; // classical
914image charge if(MirrorTypeX[primsrc] == 2) // element having same charge
915density Inf[elefld][elesrc] += AddnalInfl;
916 }
917
918 if(MirrorTypeY[primsrc])
919 {
920 localP = ReflectOnMirror('Y', elesrc, srcpt, fldpt,
921 MirrorDistYFromOrigin[primsrc], &DirCos);
922 double AddnalInfl = ComputeEleInf(Pot0Cont1, elesrc,
923&localP, &DirCos);
924
925 if(MirrorTypeY[primsrc] == 1) // element having
926opposite charge density Inf[elefld][elesrc] -= AddnalInfl; // classical
927image charge if(MirrorTypeY[primsrc] == 2) // element having same charge
928density Inf[elefld][elesrc] += AddnalInfl;
929 }
930
931 if(MirrorTypeZ[primsrc])
932 {
933 localP = ReflectOnMirror('Z', elesrc, srcpt, fldpt,
934 MirrorDistZFromOrigin[primsrc], &DirCos);
935 double AddnalInfl = ComputeEleInf(Pot0Cont1, elesrc,
936&localP, &DirCos);
937
938 if(MirrorTypeZ[primsrc] == 1) // element having
939opposite charge density InfVec[elesrc] -= AddnalInfl; // classical image
940charge if(MirrorTypeZ[primsrc] == 2) // element having same charge density
941 InfVec[elesrc] += AddnalInfl;
942 }
943
944 if(DebugLevel == 301)
945 {
946 printf("After reflection of basic device =>\n");
947 printf("elesrc: %d, Influence: %.16lg\n", elesrc,
948InfVec[elesrc]);
949 }
950 } // reflections of basic device, taken care of
951
952 DebugISLES = 0; // Stop beyond basic device - may need changes.
953CHECK! } // end of influence due to elements belonging to the basic
954device
955
956 { // Influence due to virtual elements
957
958 // If the source element is repeated due to periodicity (the
959field points
960 // remain unchanged), the influence at the field point will
961change due to
962 // additional influence of the extra elements. The repeated
963elements
964 // have properties identical to the real element (including the
965solved
966 // value of charge density - otherwise we would not be able to
967simply add
968 // up the influence at the field point!), except that its
969location is
970 // determined by direction of periodicty (at present assumed to
971be along
972 // one of the coordinate axes, but this constraint can be easily
973relaxed
974 // later - we can have a direction cosine along which the
975elements may be
976 // repeated) and the distance of repeatition. Thus, for each
977repeated
978 // element, we need to compute its position and the rest remains
979identical
980 // as above. The influence, evaluated as a temporary double, can
981be added
982 // to the base value computed above.
983 // PeriodicInX etc are either zero or +ve
984
985 if((PeriodicTypeX[primsrc] == 1) || (PeriodicTypeY[primsrc] ==
9861)
987 || (PeriodicTypeZ[primsrc] == 1))
988 {
989 if(PeriodicInX[primsrc] || PeriodicInY[primsrc] ||
990PeriodicInZ[primsrc])
991 {
992 double AddnalInfl=0.0,
993 XOfRpt, YOfRpt,
994ZOfRpt;
995
996 for(int xrpt = -PeriodicInX[primsrc];
997 xrpt <=
998PeriodicInX[primsrc]; ++xrpt)
999 {
1000 XOfRpt = xsrc + XPeriod[primsrc] *
1001(double)xrpt;
1002
1003 for(int yrpt = -PeriodicInY[primsrc];
1004 yrpt <=
1005PeriodicInY[primsrc]; ++yrpt)
1006 {
1007 YOfRpt = ysrc + YPeriod[primsrc]
1008* (double)yrpt;
1009
1010 for(int zrpt =
1011-PeriodicInZ[primsrc]; zrpt <= PeriodicInZ[primsrc]; ++zrpt)
1012 {
1013 ZOfRpt = zsrc +
1014ZPeriod[primsrc] * (double)zrpt;
1015
1016 if( (xrpt == 0) && (yrpt
1017== 0) && (zrpt == 0) ) continue; // this is the base device
1018
1019 // axis direction in the
1020global system { // Rotate point3D from global to local system double
1021InitialVector[4]; double TransformationMatrix[4][4] = {{0.0, 0.0, 0.0, 0.0},
1022 {0.0, 0.0, 0.0, 0.0},
1023 {0.0, 0.0, 0.0, 0.0},
1024 {0.0, 0.0, 0.0, 1.0}};
1025 DirnCosn3D *DirCos =
1026&(EleArr+elesrc-1)->G.DC; double FinalVector[4];
1027
1028 InitialVector[0] = xfld - XOfRpt;
1029// Vector in the GCS InitialVector[1] = yfld - YOfRpt; InitialVector[2] = zfld -
1030ZOfRpt; InitialVector[3] = 1.0;
1031
1032 TransformationMatrix[0][0] =
1033DirCos->XUnit.X; TransformationMatrix[0][1] = DirCos->XUnit.Y;
1034 TransformationMatrix[0][2] =
1035DirCos->XUnit.Z; TransformationMatrix[1][0] = DirCos->YUnit.X;
1036 TransformationMatrix[1][1] =
1037DirCos->YUnit.Y; TransformationMatrix[1][2] = DirCos->YUnit.Z;
1038 TransformationMatrix[2][0] =
1039DirCos->ZUnit.X; TransformationMatrix[2][1] = DirCos->ZUnit.Y;
1040 TransformationMatrix[2][2] =
1041DirCos->ZUnit.Z;
1042
1043 for(int i = 0; i < 4; ++i)
1044 {
1045 FinalVector[i] = 0.0;
1046 for(int j = 0 ; j < 4; ++j)
1047 {
1048 FinalVector[i] +=
1049TransformationMatrix[i][j]
1050 * InitialVector[j];
1051 }
1052 }
1053
1054 localP.X = FinalVector[0];
1055// Vector in the ECS localP.Y = FinalVector[1]; localP.Z = FinalVector[2]; } //
1056Point3D rotated
1057
1058 // Direction cosines
1059remain unchanged for a regular repetition AddnalInfl = ComputeEleInf(Pot0Cont1,
1060elesrc, &localP, &(EleArr+elesrc-1)->G.DC); InfVec[elesrc] += AddnalInfl;
1061
1062 if(DebugLevel == 301)
1063 {
1064 printf("REPEATED\n");
1065 printf("elesrc:
1066%d\n", elefld, elesrc); printf("xsrc: %lg, ysrc: %lg, zsrc: %lg\n", xsrc, ysrc,
1067zsrc); printf("xrpt: %d, yrpt: %d, zrpt: %d\n", xrpt, yrpt, zrpt);
1068 printf("XOfRpt:
1069%lg, YOfRpt: %lg, ZOfRpt: %lg\n", XOfRpt, YOfRpt, ZOfRpt); printf("AddnalInfl:
1070%lg\n", AddnalInfl); printf("InfVec: %lg\n", InfVec[elesrc]);
1071 }
1072
1073 // Take care of
1074reflections of repetitions
1075 // At present,
1076reflection on a single mirror is allowed if(MirrorTypeX[primsrc] ||
1077MirrorTypeY[primsrc]
1078 ||
1079MirrorTypeZ[primsrc])
1080 {
1081 printf("Mirror not correctly implemented
1082in this version of neBEM ...\n"); exit(0);
1083
1084 Point3D srcpt;
1085 DirnCosn3D DirCos;
1086
1087 srcpt.X = XOfRpt;
1088srcpt.Y = YOfRpt; srcpt.Z = ZOfRpt;
1089
1090 if(MirrorTypeX[primsrc])
1091 {
1092MirrorTypeY[primsrc] = 0; MirrorTypeZ[primsrc] = 0; } if(MirrorTypeY[primsrc])
1093MirrorTypeZ [primsrc]= 0;
1094
1095 if(MirrorTypeX[primsrc])
1096 {
1097 localP =
1098ReflectOnMirror('X', elesrc, srcpt, fldpt, MirrorDistXFromOrigin[primsrc],
1099 &DirCos);
1100 AddnalInfl =
1101ComputeEleInf(Pot0Cont1, elesrc, &localP, &DirCos);
1102
1103 if(MirrorTypeX[primsrc]
1104== 1) // opposite charge density InfVec[elesrc] -= AddnalInfl; //
1105classical image charge if(MirrorTypeX[primsrc] == 2) // same charge density
1106 InfVec[elesrc]
1107+= AddnalInfl;
1108 }
1109
1110 if(MirrorTypeY[primsrc])
1111 {
1112 localP =
1113ReflectOnMirror('Y', elesrc, srcpt, fldpt, MirrorDistYFromOrigin[primsrc],
1114 &DirCos);
1115 AddnalInfl =
1116ComputeEleInf(Pot0Cont1, elesrc, &localP, &DirCos);
1117
1118 if(MirrorTypeY[primsrc]
1119== 1) // opposite charge density InfVec[elesrc] -= AddnalInfl; //
1120classical image charge if(MirrorTypeY[primsrc] == 2) // same charge density
1121 InfVec[elesrc]
1122+= AddnalInfl;
1123 }
1124
1125 if(MirrorTypeZ[primsrc])
1126 {
1127 localP =
1128ReflectOnMirror('Z', elesrc, srcpt, fldpt, MirrorDistZFromOrigin[primsrc],
1129 &DirCos);
1130 AddnalInfl =
1131ComputeEleInf(Pot0Cont1, elesrc, &localP, &DirCos);
1132
1133 if(MirrorTypeZ[primsrc]
1134== 1) // opposite charge density InfVec[elesrc] -= AddnalInfl; //
1135classical image charge if(MirrorTypeZ[primsrc] == 2) // same charge density
1136 InfVec[elesrc]
1137+= AddnalInfl;
1138 }
1139
1140 if(DebugLevel == 301)
1141 {
1142 printf("REPEATED
1143and reflected\n"); printf("elesrc: %d\n", elesrc); printf("xsrc: %lg, ysrc: %lg,
1144zsrc: %lg\n", xsrc, ysrc, zsrc); printf("xrpt: %d, yrpt: %d, zrpt: %d\n", xrpt,
1145yrpt, zrpt); printf("XOfRpt: %lg, YOfRpt: %lg, ZOfRpt: %lg\n", XOfRpt, YOfRpt,
1146ZOfRpt); printf("AddnalInfl: %lg\n", AddnalInfl); printf("InfVec: %lg\n",
1147InfVec[elesrc]);
1148 }
1149 } // reflections
1150of repetitions taken care of
1151
1152 } // for zrpt
1153 } // for yrpt
1154 } // for xrpt
1155 } // PeriodicInX || PeriodicInY ||
1156PeriodicInZ } // PeriodicType == 1 } // end of influence due to virtual
1157elements
1158
1159 } // loop for elesrc, source element (influencing)
1160
1161 // printf("\b\b\b\b\b\b");
1162} // pragma omp parallel
1163
1164if(OptStoreInfVec && OptFormattedFile)
1165 {
1166 printf("storing the influence matrix in a formatted file ...\n");
1167 fflush(stdout);
1168
1169 char InfVecFile[256];
1170 strcpy(InfVecFile, MeshOutDir); strcat(InfVecFile, "/InfVec.out");
1171 FILE *fInfVec = fopen(InfVecFile, "w+");
1172 if(fInfVec == NULL)
1173 {
1174 neBEMMessage("InfluenceVector - InfVecFile");
1175 return -1;
1176 }
1177 fprintf(fInfVec, "%d\n", NbUnknowns);
1178
1179 for(int elesrc = 1; elesrc <= NbUnknowns; ++elesrc)
1180 fprintf(fInfVec, "%.16lg\n", InfVec[elesrc]);
1181 fprintf(fInfVec, "\n");
1182
1183 fclose(fInfVec);
1184 } // if OptStoreInflMatrix && OptFormattedFile
1185
1186if(OptStoreInfVec && OptUnformattedFile) // Raw cannot be implemented
1187now.
1188 { // It may be because of the memory allocation using the NR
1189routines - neBEMMessage("LHMatrix - Binary write of Infl matrix not implemented
1190yet.\n"); return -1;
1191
1192 char InfVecFile[256];
1193 strcpy(InfVecFile, MeshOutDir); strcat(InfVecFile, "/RawInfVec.out");
1194 FILE *fInfVec = fopen(InfVecFile, "wb");
1195 if(fInfVec == NULL)
1196 {
1197 neBEMMessage("InfluenceVector - RawInfVecFile");
1198 return -1;
1199 }
1200 printf("\nfInfVec: %p\n", fInfVec);
1201 int rfw = fwrite(InfVec, sizeof(double), NbUnknowns, fInfVec);
1202 fclose(fInfVec);
1203 printf("\nNb of items successfully written in raw mode in %s is %d\n",
1204 InfVecFile, rfw);
1205
1206 SLASH-STAR following block used to check raw reading from a file written in
1207raw double **RawInf; RawInf = dmatrix(1,NbEqns,1,NbUnknowns); strcpy(InflFile,
1208MeshOutDir); strcat(InflFile, "/RawInfl.out"); fInf = fopen(InflFile, "rb");
1209 // assert(fInf != NULL);
1210 if(fInf == NULL)
1211 {
1212 neBEMMessage("LHMatrix - RawInflFile");
1213 return -1;
1214 }
1215 rfw = fread(RawInf, sizeof(double), NbEqns*NbUnknowns, fInf);
1216 fclose(fInf);
1217 printf("Nb of items successfully read in raw mode from %s is %d\n",
1218 InflFile, rfw);
1219 for(int unknown = 1; unknown <= NbUnknowns; ++unknown)
1220 for(int eqn = 1; eqn <= NbEqns; ++eqn)
1221 printf("Unknown:%d, Eqn:%d => diff Inf: %lg, RawInf: %lg is
1222%lg\n", unknown, eqn, Inf[unknown][eqn], RawInf[unknown][eqn],
1223 fabs(Inf[unknown][eqn] -
1224RawInf[unknown][eqn])); Please do not delete STAR-SLASH } // if
1225OptStoreInflMatrix && OptUnformattedFile
1226
1227neBEMState = 6;
1228
1229return(0);
1230} // end of Influence
1231To be tried later */
1232
1233// Invert a matrix of size NEquations X NbUnknowns
1234// Note that slightly modified influence coefficient matrix can be solved
1235// without going for a fresh re-inversion
1236int InvertMatrix(void) {
1237 int DecomposeMatrixSVD(double **SVDInf, double *SVDw, double **SVDv);
1238
1239 InvMat = dmatrix(1, NbUnknowns, 1, NbEqns);
1240
1241 if (OptGSL) {
1242 printf("InvertMatrix: matrix decomposition using GSL ... ");
1243 printf("no OpenMP implementation ...");
1244 fflush(stdout);
1245
1246 int s; // signum for LU decomposition
1247
1248 gsl_matrix *m = gsl_matrix_alloc(NbUnknowns, NbEqns);
1249 gsl_matrix *inverse = gsl_matrix_alloc(NbUnknowns, NbEqns);
1250 gsl_permutation *perm = gsl_permutation_alloc(NbUnknowns);
1251
1252 for (int i = 0; i < NbUnknowns; ++i)
1253 for (int j = 0; j < NbEqns; ++j)
1254 gsl_matrix_set(m, i, j, Inf[i + 1][j + 1]);
1255
1256 // Make LU decomposition of matrix m
1257 gsl_linalg_LU_decomp(m, perm, &s);
1258
1259 // Invert the matrix m
1260 gsl_linalg_LU_invert(m, perm, inverse);
1261
1262 for (int i = 0; i < NbUnknowns; ++i)
1263 for (int j = 0; j < NbEqns; ++j)
1264 InvMat[i + 1][j + 1] = gsl_matrix_get(inverse, i, j);
1265
1266 gsl_matrix_free(m);
1267 gsl_matrix_free(inverse);
1268 printf("InvertMatrix: ... completed using GSL\n");
1269 } // if OptGSL
1270
1271 if (OptSVD) {
1272 printf("InvertMatrix: matrix decomposition using SVD ... ");
1273 printf("no OpenMP implementation ...");
1274 fflush(stdout);
1275
1276 clock_t SVDstartClock = clock();
1277 printf("ComputeSolution: Decomposing influence matrix ...\n");
1278 fflush(stdout);
1279
1280 // These may as well be declared in neBEM.h because a signicant amount
1281 // of information can be extracted from them in a later version.
1282 double **SVDInf, *SVDw, **SVDv;
1283 SVDInf = dmatrix(1, NbEqns, 1, NbUnknowns);
1284 SVDw = dvector(1, NbUnknowns);
1285 SVDv = dmatrix(1, NbUnknowns, 1, NbUnknowns); // a square matrix!
1286
1287 // Keep the original Inf[] safe
1288 for (int i = 1; i <= NbEqns; i++) {
1289 int j;
1290#ifdef _OPENMP
1291 #pragma omp parallel for private(j)
1292#endif
1293 for (j = 1; j <= NbUnknowns; j++)
1294 SVDInf[i][j] = Inf[i][j]; // end of omp parallel for
1295 }
1296
1297 int fstatus = DecomposeMatrixSVD(SVDInf, SVDw, SVDv);
1298 if (fstatus != 0) {
1299 neBEMMessage("ComputeSolution - DecomposeMatrixSVD");
1300 return -1;
1301 }
1302 printf("ComputeSolution: Matrix decomposition over.\n");
1303 clock_t SVDstopClock = clock();
1304 neBEMTimeElapsed(SVDstartClock, SVDstopClock);
1305 printf("to singular value decompose the influence matrix.\n");
1306
1307 // Find the pseudo-inverse of the influence coefficient matrix
1308 double **tmpmat;
1309 tmpmat = dmatrix(1, NbEqns, 1, NbUnknowns);
1310
1311 // calculate w+ (transpose)u
1312 for (int j = 1; j <= NbUnknowns;
1313 j++) { // w+ is obtained by replacing every non-zero diagonal entry of
1314 // [W]
1315 int i;
1316#ifdef _OPENMP
1317 #pragma omp parallel for private(i)
1318#endif
1319 for (i = 1; i <= NbEqns; i++) // (note W, not w) by its reciprocal and
1320 { // transposing the resulting matrix
1321 if (SVDw[j]) // nonzero result only if w[i] is nonzero
1322 {
1323 tmpmat[j][i] = SVDInf[i][j] / SVDw[j];
1324 } else {
1325 tmpmat[j][i] = 0.0;
1326 }
1327 } // end of omp parallel for
1328 }
1329
1330 // multiply by [V] to get answer
1331 for (int i = 1; i <= NbUnknowns; i++)
1332 for (int j = 1; j <= NbEqns; j++) {
1333 InvMat[i][j] = 0.0;
1334
1335 int k;
1336 double sum = 0.0;
1337#ifdef _OPENMP
1338#pragma omp parallel for private(k) reduction(+ : sum)
1339#endif
1340 for (k = 1; k <= NbUnknowns; k++)
1341 sum += SVDv[i][k] * tmpmat[k][j]; // end of omp parallel for
1342
1343 InvMat[i][j] = sum;
1344 }
1345
1346 free_dmatrix(tmpmat, 1, NbEqns, 1, NbUnknowns);
1347 // free SVD matrices? may need to be manitained for later use
1348 free_dmatrix(SVDInf, 1, NbEqns, 1, NbUnknowns);
1349 free_dvector(SVDw, 1, NbUnknowns);
1350 free_dmatrix(SVDv, 1, NbUnknowns, 1, NbUnknowns);
1351 printf("InvertMatrix: completed using SVD ...\n");
1352 fflush(stdout);
1353 } // if OptSVD
1354
1355 if (OptLU) {
1356 int *index;
1357 double d, *col, **y;
1358 y = dmatrix(1, NbUnknowns, 1, NbUnknowns);
1359 col = dvector(1, NbUnknowns);
1360 index = ivector(1, NbUnknowns);
1361
1362 double **tmpInf; // temporary influence matrix necessary for ludcmp
1363 tmpInf = dmatrix(1, NbEqns, 1, NbUnknowns);
1364 for (int i = 1; i <= NbEqns; i++) // Keep original Inf[] safe
1365 {
1366 int j;
1367#ifdef _OPENMP
1368 #pragma omp parallel for private(j)
1369#endif
1370 for (j = 1; j <= NbUnknowns; j++)
1371 tmpInf[i][j] = Inf[i][j]; // end of omp parallel for
1372 }
1373
1374 printf("InvertMatrix: matrix decomposition using LU ... ");
1375 fflush(stdout);
1376 ludcmp(tmpInf, NbUnknowns, index, &d); // The tmpInf matrix over-written
1377
1378 for (int j = 1; j <= NbUnknowns; j++) // Find inverse by columns.
1379 {
1380 int i;
1381#ifdef _OPENMP
1382 #pragma omp parallel for private(i)
1383#endif
1384 for (i = 1; i <= NbUnknowns; i++)
1385 col[i] = 0.0; // end of omp parallel for
1386
1387 col[j] = 1.0;
1388
1389 lubksb(tmpInf, NbUnknowns, index, col); // changed avatar of tmpInf used
1390#ifdef _OPENMP
1391 #pragma omp parallel for private(i)
1392#endif
1393 for (i = 1; i <= NbEqns; i++) {
1394 y[i][j] = col[i];
1395 InvMat[i][j] = y[i][j];
1396 } // end of omp parallel for
1397 // printf("\b\b\b\b\b\b");
1398 }
1399
1400 free_ivector(index, 1, NbUnknowns);
1401 free_dvector(col, 1, NbUnknowns);
1403 free_dmatrix(tmpInf, 1, NbEqns, 1, NbUnknowns);
1404
1405 printf("InvertMatrix: completed using LU ...\n");
1406 fflush(stdout);
1407 } // if OptLU
1408
1409 // Since this is occurring within the InvertMatrix function, it is obvious
1410 // that the InfluenceMatrixFlag is true and the LHMatrix has already been
1411 // computed giving rise to a valid Inf[].
1412 // Free Inf[] if validation is not opted for, despite going through a fresh
1413 // solution attempt - highly deprecated!
1415
1416 // It is necessary to write this file always if we want to avoid
1417 // matrix inversion for analyzing the same device with a different BC
1418 printf("OptStoreInvMatrix: %d, OptFormattedFile: %d\n", OptStoreInvMatrix,
1420
1422 printf("storing the inverted matrix in a formatted file ...\n");
1423 fflush(stdout);
1424
1425 FILE *fInv; // can be a very large file - change to raw and zipped format
1426 char InvMFile[256];
1427 strcpy(InvMFile, MeshOutDir);
1428 strcat(InvMFile, "/InvMat.out");
1429 fInv = fopen(InvMFile, "w");
1430
1431 // following line may be removed after the dimension issue is resolved.
1432 fprintf(fInv, "%d %d\n", NbEqns, NbUnknowns);
1433 for (int i = 1; i <= NbEqns; i++)
1434 for (int j = 1; j <= NbUnknowns; j++)
1435 fprintf(fInv, "%.16le\n", InvMat[i][j]);
1436
1437 fclose(fInv);
1438 } // if OptStoreInvMatrix && OptFormattedFile
1439
1441 // not implemented yet
1442 // not implemented
1443 neBEMMessage("InvertMatrix - Binary write not yet implemented.");
1444 return (-1);
1445 }
1446
1447 neBEMState = 7;
1448
1449 return (0);
1450} // end of InvertMatrix
1451
1452// Decompose a matrix of size NbEqns X NbUnknowns using SVD
1453// NbEqns has to be equal to or greater than NbUnknowns for SVD to work.
1454int DecomposeMatrixSVD(double **SVDInf, double *SVDw, double **SVDv) {
1455 // The following needs optimization - wmin, wmax etc.
1456 double wmin, wmax;
1457
1458 printf("DecomposeMatrix: matrix decomposition using SVD ... ");
1459 fflush(stdout);
1460 svdcmp(SVDInf, NbEqns, NbUnknowns, SVDw, SVDv); // SVDInf matrix over-written
1461 printf("DecomposeMatrix: decomposition completed ...\n");
1462 fflush(stdout);
1463
1464 wmax = SVDw[1]; // Will be the maximum singular value obtained - changed 0.0
1465#ifdef _OPENMP
1466 #pragma omp parallel
1467#endif
1468 {
1469 int j;
1470#ifdef _OPENMP
1471 #pragma omp for private(j)
1472#endif
1473 for (j = 1; j <= NbUnknowns; j++) {
1474 if (SVDw[j] > wmax) wmax = SVDw[j];
1475 }
1476 } // omp parallel
1477
1478 // This is where we set the threshold for singular values allowed to be
1479 // nonzero. The constant is typical, but not universal. You have to experiment
1480 // with your own application.
1481 wmin = wmax * 1.0e-12;
1482#ifdef _OPENMP
1483 #pragma omp parallel
1484#endif
1485 {
1486 int j;
1487#ifdef _OPENMP
1488 #pragma omp for private(j)
1489#endif
1490 for (j = 1; j <= NbUnknowns; j++) {
1491 if (SVDw[j] < wmin) SVDw[j] = 0.0;
1492 }
1493 } // omp parallel
1494 // printf("wmin: %le, wmax: %le\n", wmin, wmax);
1495
1496 neBEMState = 7;
1497
1498 return (0);
1499} // end of DecomposeMatrixSVD
1500
1501// Read an inverted matrix of size NbEquations X NbUnknowns
1502// Called only when OptStoreInvMatrix is true. Hence, no need to check the
1503// same all over again.
1505 // Computation of solution using LU only in this version
1507 // InvMat = dmatrix(1,NbEqns,1,NbUnknowns); // may be reinstated after
1508 // the dimension issue is resolvedint ReadInvertedMatrix(void)
1509 } else {
1510 printf(
1511 "ReadInvertedMatrix: OptFormattedFile and OptUnformattedFile, both are "
1512 "false ... ");
1513 printf(
1514 " Can not read inverted matrix ... returning ...\n");
1515 return (-1);
1516 }
1517
1518 // We need to provide two inputs to implement this
1519 // 1. The fact that we are only changing the BC; MotherInputFile and object
1520 // files should be the same as the original - in such an event, it is
1521 // obvious where the following file is to be found.
1522 // 2. The new set of BCs and the new output file - can be a subdirectory
1523 // of the original (may be default-ed to BC0).
1524 // 3. BC0, if existing, should never be overwritten / removed by the code.
1525 // If at all, it should be removed manually.
1526
1527 if (OptFormattedFile) {
1528 FILE *fInv; // can be a very large file - change to raw and zipped format
1529
1530 char InvMFile[256];
1531 strcpy(InvMFile, MeshOutDir);
1532 strcat(InvMFile, "/InvMat.out");
1533 fInv = fopen(InvMFile, "r");
1534 // assert(fInv != NULL);
1535 if (fInv == NULL) {
1536 neBEMMessage("ReadInvertedMatrix - inverted matrix not found.");
1537 return (-1);
1538 }
1539
1540 // Retrieve the dimensions and create matrix
1541 // These lines may be removed once the dimension issue is resolved
1542 // Better still, these numbers can be used to cross-check that there is
1543 // a possibility we are reading the correct inverted matrix - at least the
1544 // dimensions match!
1545 int chkNbEqns, chkNbUnknowns;
1546 fscanf(fInv, "%d %d\n", &chkNbEqns, &chkNbUnknowns);
1547 if ((chkNbEqns != NbEqns) || (chkNbUnknowns != NbUnknowns)) {
1549 "ReadInvertedMatrix - inverted matrix imension do not match!");
1550 return (-1);
1551 }
1552
1553 printf("ReadInvertedMatrix: Matrix dimensions: %d equations, %d unknowns\n",
1555 InvMat = dmatrix(1, NbEqns, 1, NbUnknowns);
1556
1557 for (int i = 1; i <= NbEqns; i++) {
1558 printf("%6d", i); // fflush(stdout);
1559 for (int j = 1; j <= NbUnknowns; j++) {
1560 fscanf(fInv, "%le\n", &InvMat[i][j]);
1561 }
1562 printf("\b\b\b\b\b\b");
1563 }
1564
1565 fclose(fInv);
1566 } // if OptFormattedFile
1567 else if (OptUnformattedFile) // both can not be true!
1568 {
1569 // not implemented
1570 neBEMMessage("ReadInvertedMatrix - Binary read not yet implemented.");
1571 return (-1);
1572 }
1573
1574 neBEMState = 7;
1575
1576 return (0);
1577} // end of ReadInvertedMatrix
1578
1579double ComputeInfluence(int elefld, int elesrc, Point3D *localP,
1580 DirnCosn3D *DirCos) {
1581 if (DebugLevel == 301) {
1582 printf("In ComputeInfluence ...\n");
1583 }
1584
1585 double value; // influence coefficient
1586
1587 if (0) {
1588 printf("\nContinuity satisfaction using following parameters ...\n");
1589 printf("gtsrc: %d, lxsrc: %lg, lzsrc% lg, dA: %lg\n",
1590 (EleArr + elesrc - 1)->G.Type, (EleArr + elesrc - 1)->G.LX,
1591 (EleArr + elesrc - 1)->G.LZ, (EleArr + elesrc - 1)->G.dA);
1592 printf("xlocal: %lg, ylocal: %lg, zlocal: %lg\n", localP->X, localP->Y,
1593 localP->Z);
1594 }
1595
1596 switch ((EleArr + elefld - 1)
1597 ->E.Type) // depending on the etype at the field point
1598 { // different boundary conditions need to be applied
1599 case 1: // conductor with known potential
1600 value = SatisfyValue(elesrc, localP);
1601 return (value);
1602 break;
1603
1604 case 2: // Conductor with a specified charge - has to have a BC as well!
1605 printf("Conductors with specific charge not implemented yet.\n");
1606 return -1; // The potential has to be the same for the complete
1607 // component.
1608 break; // If the value of pot is known, the situation is same as above.
1609 // if not, it is similar to a floating conductor.
1610
1611 case 3: // floating conductor
1612 value = SatisfyValue(elesrc, localP);
1613 return (value);
1614 // printf("Floating conductors not implemented yet.\n");
1615 // return -1;
1616 break;
1617
1618 // normal component of the displacement vector is continuous across each
1619 // dielectric-to-dielectric interface
1620 case 4: // DD interface
1621 value = SatisfyContinuity(elefld, elesrc, localP, DirCos);
1622 return (value);
1623 break;
1624
1625 case 5: // Dielectric with surface charge density known; same as above BC?
1626 value = SatisfyContinuity(elefld, elesrc, localP, DirCos);
1627 return (value);
1628 // The BC has to be the same and some part of the charge
1629 break; // density necessary to satisfy the BC needs to be solved for.
1630
1631 case 6: // Symmetry boundary, E parallel
1632 printf("Symmetry boundary, E parallel not implemented yet. \n");
1633 return -1;
1634 break;
1635
1636 case 7: // Symmetry boundary, E perpendicular (not likely to be used)
1637 printf("Symmetry boundary, E perpendicular not implemented yet. \n");
1638 return -1;
1639 break;
1640
1641 default:
1642 printf("Electric type %d out of range! ... exiting.\n",
1643 (EleArr + elefld - 1)->E.Type);
1644 return (-1);
1645 break; // unreachable
1646 } // switch on etfld ends
1647} // end of ComputeInfluence
1648
1649/* To be tried later
1650// Compute influence at a point due to a source element / known charged entities
1651// Pot0Cont1 should better be replaced by (EleArr+elefld-1)->E.Type
1652double ComputeEleInf(int srcEle, DirnCosn3D *srcDirCos, Point3D *fldPt,
1653DirnCosn3D *fldDirCos, int Pot0Cont1)
1654{
1655if(DebugLevel == 301) { printf("In ComputeEleInf ...\n"); }
1656
1657double value; // influence coefficient
1658
1659if(0)
1660 {
1661 printf("\nContinuity satisfaction using following parameters ...\n");
1662 printf("gtsrc: %d, lxsrc: %lg, lzsrc% lg, dA: %lg\n",
1663 (EleArr+srcEle-1)->G.Type,
1664(EleArr+srcEle-1)->G.LX, (EleArr+srcEle-1)->G.LZ, (EleArr+srcEle-1)->G.dA);
1665 printf("xlocal: %lg, ylocal: %lg, zlocal: %lg\n",
1666 localP->X, localP->Y, localP->Z);
1667 }
1668
1669switch(Pot0Cont1) // depending on the etype at the field point
1670 { // different boundary conditions need to be
1671applied case 0: // conductor with known potential value =
1672EleSatisfyValue(srcEle, fldPt); return(value); break;
1673
1674// normal component of the displacement vector is continuous across each
1675// dielectric-to-dielectric interface
1676 case 1: // DD interface
1677 value = EleSatisfyContinuity(srcEle, srcDirCos, fldPt,
1678fldDirCos); return(value); break;
1679
1680 default:
1681 } // switch on Pot0Cont1 ends
1682} // end of ComputeEleInf
1683To be tried later */
1684
1685// Satisfy Dirichlet condition
1686double SatisfyValue(int elesrc, Point3D *localP) {
1687 if (DebugLevel == 301) {
1688 printf("In SatisfyValue ...\n");
1689 }
1690
1691 double value;
1692
1693 switch ((EleArr + elesrc - 1)->G.Type) {
1694 case 4: // rectangular element
1695 value = RecPot(elesrc, localP);
1696 return (value);
1697 // return(value/dA);
1698 break;
1699 case 3: // triangular element
1700 value = TriPot(elesrc, localP);
1701 return (value);
1702 // return(value/dA);
1703 break;
1704 case 2: // linear (wire) element
1705 value = WirePot(elesrc, localP);
1706 return (value);
1707 // return(value/dA);
1708 break;
1709 default:
1710 printf("Geometrical type out of range! ... exiting ...\n");
1711 return (-1);
1712 break; // never comes here
1713 } // switch over gtsrc ends
1714} // end of SatisfyValue
1715
1716// Satisfy Neumann condition.
1717// Normal displacement field is continuous across the interface.
1718// The potential is also continuous, implying continuity of the tangential
1719// field, but that is not explicitly imposed.
1720// Slightly modified in V1.8 in comparison to previous versions
1721// Further modification in V1.8.3:
1722// Check equation (18) in Bardhan's paper. Note that the D* operator is
1723// single-layer negative electric field operator (equation 12)
1724double SatisfyContinuity(int elefld, int elesrc, Point3D *localP,
1725 DirnCosn3D *DirCos) {
1726 if (DebugLevel == 301) {
1727 printf("In SatisfyContinuity ...\n");
1728 }
1729
1730 double value = 0.0;
1731 Vector3D localF, globalF;
1732
1733 // For self-influence, lmsrc is equal to lmfld which allows the following.
1734 // Additional conditions on distances ensure that periodic copies are not
1735 // treated as `self'.
1736 // Here, we have the additional problem of correctly treating the
1737 // self-influence of traingular elements for which the co-ordinate origin
1738 // does not coincide with the barycentre and thus elesrc and elefld
1739 // are separated from each other by lx/3 and lz/3 in X and Z,
1740 // respectively. The Y coordinates match, however, since the element
1741 // local coordinate system has the Y=0 plane coinciding with the element
1742 // on which the element is lying.
1743 // Since elefld and elesrc are the same for self-influence, etsrc can either
1744 // be 4 or 5. So, the check on the value of etsrc is superfluous, and two
1745 // separate if blocks are merged into one.
1746 // Check for other "special" cases!
1747 if ((elefld == elesrc) &&
1748 (fabs(localP->X) < (EleArr + elesrc - 1)->G.LX / 2.0) &&
1749 (fabs(localP->Y) < MINDIST) &&
1750 (fabs(localP->Z) <
1751 (EleArr + elesrc - 1)->G.LZ / 2.0)) // self-inf for DD intrfc
1752 { // consistent with eqn 18 of Bardhan's paper where lmsrc is inverse
1753 value = 1.0 / (2.0 * EPS0 * (EleArr + elesrc - 1)->E.Lambda);
1754 } // of the multiplying factor of roe(r). EPS0 arises due to electrostatics.
1755 else {
1756 value = 0.0;
1757 // Following fluxes in the influencing ECS
1758 switch ((EleArr + elesrc - 1)->G.Type) {
1759 case 4: // rectangular element
1760 RecFlux(elesrc, localP, &localF);
1761 break;
1762 case 3: // triangular element
1763 TriFlux(elesrc, localP, &localF);
1764 break;
1765 case 2: // linear (wire) element
1766 WireFlux(elesrc, localP, &localF);
1767 break;
1768 default:
1769 printf("Geometrical type out of range! ... exiting ...\n");
1770 exit(-1);
1771 break; // never comes here
1772 } // switch over gtsrc ends
1773
1774 // flux in the global co-ordinate system
1775 // globalF = RotateVector3D(&localF, &(EleArr+elesrc-1)->G.DC,
1776 // local2global);
1777 globalF = RotateVector3D(&localF, DirCos, local2global);
1778
1779 // Fluxes in the influenced ECS co-ordinate system
1780 localF =
1781 RotateVector3D(&globalF, &(EleArr + elefld - 1)->G.DC, global2local);
1782
1783 value = -localF.Y;
1784 // normal derivative of Green's function is - normal force
1785 // (changed from -Fy to +Fy on 02/11/11 - CHECK!!!);
1786 // From = to +=, further change on 04/11/11; Reverted + to - on 05/11/11
1787 } // else self-influence
1788
1789 return (value);
1790} // end of SatisfyContinuity
1791
1792/* Two functions to be tried later
1793// Satisfy Dirichlet condition due to a source element at an arbitraty field
1794point double EleSatisfyValue(int srcEle, Point3D *fldPt)
1795{
1796if(DebugLevel == 301) { printf("In EleSatisfyValue ...\n"); }
1797
1798double value;
1799
1800switch((EleArr+srcEle-1)->G.Type)
1801 {
1802 case 4: // rectangular element
1803 value = RecPot(srcEle, fldPt);
1804 return(value);
1805 // return(value/dA);
1806 break;
1807 case 3: // triangular element
1808 value = TriPot(srcEle, fldPt);
1809 return(value);
1810 // return(value/dA);
1811 break;
1812 case 2: // linear (wire) element
1813 value = WirePot(srcEle, fldPt);
1814 return(value);
1815 // return(value/dA);
1816 break;
1817 default:
1818 printf("Geometrical type out of range! ... exiting ...\n");
1819 return(-1);
1820 break; // never comes here
1821 } // switch over gtsrc ends
1822} // end of EleSatisfyValue
1823
1824
1825// Satisfy Neumann condition due to a source element at an arbitrary field point
1826// Normal displacement field is continuous across the interface.
1827// The potential is also continuous, implying continuity of the tangential
1828// field, but that is not explicitly imposed.
1829// Slightly modified in V1.8 in comparison to previous versions
1830// Further modification in V1.8.3:
1831// Check equation (18) in Bardhan's paper. Note that the D* operator is
1832// single-layer negative electric field operator (equation 12)
1833double EleSatisfyContinuity(int srcEle, DirnCosn3D *eleDirCos, Point3D *fldPt,
1834DirnCosn3D *fldDirCos)
1835{
1836if(DebugLevel == 301) { printf("In SatisfyContinuity ...\n"); }
1837
1838double value = 0.0;
1839Vector3D localF, globalF;
1840
1841// For self-influence, lmsrc is equal to lmfld which allows the following.
1842// Additional conditions on distances ensure that periodic copies are not
1843// treated as `self'.
1844// Here, we have the additional problem of correctly treating the
1845// self-influence of traingular elements for which the co-ordinate origin
1846// does not coincide with the barycentre and thus srcEle and elefld
1847// are separated from each other by lx/3 and lz/3 in X and Z,
1848// respectively. The Y coordinates match, however, since the element
1849// local coordinate system has the Y=0 plane coinciding with the element
1850// on which the element is lying.
1851// Since elefld and srcEle are the same for self-influence, etsrc can either be
1852// 4 or 5. So, the check on the value of etsrc is superfluous, and two
1853// separate if blocks are merged into one.
1854// Check for other "special" cases!
1855if((fabs(fldPt->X) < (EleArr+srcEle-1)->G.LX/2.0)
1856 && (fabs(fldPt->Y) < MINDIST)
1857 && (fabs(fldPt->Z) < (EleArr+srcEle-1)->G.LZ/2.0))// self-inf
1858for DD intrfc { // consistent with eqn 18 of Bardhan's paper where lmsrc is
1859inverse value = 1.0 / (2.0*EPS0*(EleArr+srcEle-1)->E.Lambda); } // of the
1860multiplying factor of roe(r). EPS0 arises due to electrostatics. else
1861 {
1862 value = 0.0;
1863 // Following fluxes in the influencing ECS
1864 switch((EleArr+srcEle-1)->G.Type)
1865 {
1866 case 4: // rectangular element
1867 RecFlux(srcEle, fldPt, &localF);
1868 break;
1869 case 3: // triangular element
1870 TriFlux(srcEle, fldPt, &localF);
1871 break;
1872 case 2: // linear (wire) element
1873 WireFlux(srcEle, fldPt, &localF);
1874 break;
1875 default:
1876 printf("Geometrical type out of range! ... exiting
1877...\n"); exit(-1); break; // never comes here } // switch over gtsrc
1878ends
1879
1880 // flux in the global co-ordinate system
1881 // globalF = RotateVector3D(&localF, &(EleArr+srcEle-1)->G.DC,
1882local2global); globalF = RotateVector3D(&localF, srcDirCos, local2global);
1883
1884 // Fluxes in the influenced ECS co-ordinate system
1885 localF = RotateVector3D(&globalF, fldDirCos, global2local);
1886
1887 value = -localF.Y;
1888 // normal derivative of Green's function is - normal force
1889 // (changed from -Fy to +Fy on 02/11/11 - CHECK!!!);
1890 // From = to +=, further change on 04/11/11; Reverted + to - on 05/11/11
1891 } // else self-influence
1892
1893return(value);
1894} // end of EleSatisfyContinuity
1895Two functions to be tried later */
1896
1897// The RHVector is specified by the boundary conditions at the field points
1898// Ideally, there should be a flag related to the presence of known charges.
1899// If no known charges are there, it is not necessary to try out functions
1900// ValueKnCh and ContinuityKnCh. These functions are not being used now.
1901// At present,EffectChUp is being used, assuming availability of the influence
1902// coefficient matrix which makes the computation much faster.
1903int RHVector(void) {
1904 double value, valueKnCh, valueChUp;
1905
1906 if (TimeStep == 1) RHS = dvector(1, NbEqns);
1907 char outfile[256];
1908 strcpy(outfile, BCOutDir);
1909 strcat(outfile, "/BCondns.out");
1910 FILE *fout = fopen(outfile, "w");
1911 fprintf(fout, "#BCondn Vector\n");
1912 fprintf(fout, "#elefld\tAssigned\tBC\tKnCh\tChUp\tRHValue\n");
1913
1914 printf("created BCondns.out file ...\n");
1915 fflush(stdout);
1916
1917 for (int elefld = 1; elefld <= NbElements; ++elefld) {
1918 value = valueKnCh = valueChUp = 0.0;
1919 switch ((EleArr + elefld - 1)->E.Type) {
1920 case 1: // Conducting surfaces
1921 value = (EleArr + elefld - 1)->BC.Value;
1922 if (OptKnCh)
1923 valueKnCh = EffectKnCh(elefld); // effect of all known charges
1924 if (OptChargingUp) valueChUp = EffectChUp(elefld);
1925 RHS[elefld] = value - valueKnCh - valueChUp;
1926 break;
1927 case 2: // Conducting surfaces with known charge
1928 printf("Conducting surface with charge not implemented.\n");
1929 return -1;
1930 break; // NOTE: no RHVector
1931 case 3: // Floating conducting surfaces
1932 if (OptKnCh)
1933 valueKnCh = EffectKnCh(elefld); // effect of all known charges
1934 if (OptChargingUp) valueChUp = EffectChUp(elefld);
1935 RHS[elefld] = value - valueKnCh - valueChUp;
1936 break;
1937 case 4: // Dielectric interfaces
1938 if (OptKnCh)
1939 valueKnCh =
1940 EffectKnCh(elefld); // CONTINUITY effect of known charges???
1941 if (OptChargingUp) valueChUp = EffectChUp(elefld);
1942 RHS[elefld] = value - valueKnCh - valueChUp;
1943 RHS[elefld] +=
1944 (EleArr + elefld - 1)->Assigned; // effect due to charging up
1945 break;
1946 case 5: // Dielectric interfaces with known charge
1947 if (OptKnCh)
1948 valueKnCh = EffectKnCh(elefld); // effect of all known charges
1949 if (OptChargingUp) valueChUp = EffectChUp(elefld);
1950 RHS[elefld] = value - valueKnCh - valueChUp; // Check Bardhan's eqn 16
1951 RHS[elefld] +=
1952 (EleArr + elefld - 1)->Assigned; // effect due to assigned
1953 // charge; what happens when assigned elements are charged up in
1954 // addition?
1955 break;
1956 case 6: // E parallel symmetry boundary
1957 printf("Symmetry boundary, E parallel not implemented yet.\n");
1958 return -1;
1959 break;
1960 case 7: // E perpendicular symmetry boundary
1961 printf("Symmetry boundary, E perpendicular not implemented yet.\n");
1962 return -1;
1963 break;
1964 default:
1965 printf("elefld in RHVector out of range ... returning\n");
1966 return -1;
1967 }
1968 fprintf(fout, "%d\t%le\t%le\t%le\t%le\t%le\n", elefld,
1969 (EleArr + elefld - 1)->Assigned, value, valueKnCh, valueChUp,
1970 RHS[elefld]);
1971 } // for elefld ends
1972
1973 if (NbConstraints) {
1974 for (int eqn = NbElements + 1; eqn <= NbEqns; ++eqn) {
1975 if (eqn ==
1976 NbSystemChargeZero) // if row corresponds to zero-charge condition
1977 {
1978 double assigned, dA, SumAssigned = 0.0;
1979 // can be parallelized
1980 for (int ele = 1; ele <= NbElements; ++ele) {
1981 assigned = (EleArr + ele - 1)->Assigned;
1982 dA = (EleArr + ele - 1)->G.dA;
1983 SumAssigned += assigned * dA; // charge density * element area
1984 }
1985 RHS[eqn] =
1986 -SumAssigned; // applied charge considered - too small change
1987 RHS[eqn] =
1988 0.0; // applied charge not considered while meeting constraint
1989 } // if eqn == NbSystemChargeZero
1990 else {
1991 RHS[eqn] = 0.0;
1992 }
1993 }
1994 } // if NbConstraints
1995
1996 printf("computations for RHVector completed ...\n");
1997 fflush(stdout);
1998
1999 fclose(fout);
2000
2001 neBEMState = 5;
2002
2003 return (0);
2004} // RHVector
2005
2006// Effect of known charges on the right hand vector
2007/* This is what we need finally
2008
2009double EffectKnCh(int caseid, int elefld)
2010{
2011switch(caseid)
2012 {
2013 case 1:
2014 return(ValueKnCh(elefld);
2015 break;
2016 case 2:
2017 return(ContinuityKnCh(elefld);
2018 break;
2019 default:
2020 printf("not an allowed configuration in EffectKnCh ...
2021returning\n"); return(-1);
2022 }
2023} // EffectKnCh ends
2024*/
2025
2026// At present it is assumed that all the effects of known charges modify the
2027// Dirichlet boundary condition only.
2028double EffectKnCh(int elefld) { return (ValueKnCh(elefld)); }
2029
2030// Dirichlet contribution due to known charge distributions.
2031// For the following two to work, all the geometrical attributes (repetitions,
2032// reflections etc.) need to be considered. This is true for the point, line
2033// and surface charges, as well. But can these known charges be assumed to
2034// repeat at all?
2035double ValueKnCh(int elefld) {
2036 int dbgFn = 0;
2037
2038 double value = 0.0;
2039 double xfld = (EleArr + elefld - 1)->BC.CollPt.X;
2040 double yfld = (EleArr + elefld - 1)->BC.CollPt.Y;
2041 double zfld = (EleArr + elefld - 1)->BC.CollPt.Z;
2042
2043 // Retrieve element properties at the field point
2044 // Location needed for Dirichlet (potential)
2045 Point3D localP, globalP; // globalP is useful here
2046
2047 // OMPCheck - parallelize
2048
2049 // Effect of known charges on the interface elements
2050 for (int elesrc = 1; elesrc <= NbElements; ++elesrc) {
2051 double assigned = (EleArr + elesrc - 1)->Assigned;
2052 if (fabs(assigned) <= 1.0e-16) continue;
2053
2054 // Retrieve element properties from the structure
2055 if ((EleArr + elesrc - 1)->E.Type == 0) {
2056 printf("Wrong EType for elesrc %d element %d on %dth primitive!\n",
2057 elesrc, (EleArr + elesrc - 1)->Id,
2058 (EleArr + elesrc - 1)->PrimitiveNb);
2059 exit(-1);
2060 }
2061
2062 Point3D *pOrigin = &(EleArr + elesrc - 1)->G.Origin;
2063
2064 // translated to local origin but axes direction as in GCS
2065 globalP.X = xfld - pOrigin->X; // used later
2066 globalP.Y = yfld - pOrigin->Y;
2067 globalP.Z = zfld - pOrigin->Z;
2068
2069 { // Rotate point3D from global to local system
2070 double TransformationMatrix[3][3] = {{0.0, 0.0, 0.0},
2071 {0.0, 0.0, 0.0},
2072 {0.0, 0.0, 0.0}};
2073 DirnCosn3D *DirCos = &(EleArr + elesrc - 1)->G.DC;
2074
2075 TransformationMatrix[0][0] = DirCos->XUnit.X;
2076 TransformationMatrix[0][1] = DirCos->XUnit.Y;
2077 TransformationMatrix[0][2] = DirCos->XUnit.Z;
2078 TransformationMatrix[1][0] = DirCos->YUnit.X;
2079 TransformationMatrix[1][1] = DirCos->YUnit.Y;
2080 TransformationMatrix[1][2] = DirCos->YUnit.Z;
2081 TransformationMatrix[2][0] = DirCos->ZUnit.X;
2082 TransformationMatrix[2][1] = DirCos->ZUnit.Y;
2083 TransformationMatrix[2][2] = DirCos->ZUnit.Z;
2084
2085 double InitialVector[3] = {xfld - pOrigin->X, yfld - pOrigin->Y, zfld - pOrigin->Z};
2086 double FinalVector[3] = {0., 0., 0.};
2087 for (int i = 0; i < 3; ++i) {
2088 for (int j = 0; j < 3; ++j) {
2089 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
2090 }
2091 }
2092
2093 localP.X = FinalVector[0];
2094 localP.Y = FinalVector[1];
2095 localP.Z = FinalVector[2];
2096 } // Point3D rotated
2097
2098 switch ((EleArr + elesrc - 1)->G.Type) {
2099 case 4: // rectangular element
2100 value += assigned * RecPot(elesrc, &localP);
2101 // return(value/dA);
2102 break;
2103 case 3: // triangular element
2104 value += assigned * TriPot(elesrc, &localP);
2105 // return(value/dA);
2106 break;
2107 case 2: // linear (wire) element
2108 value += assigned * WirePot(elesrc, &localP);
2109 // return(value/dA);
2110 break;
2111 default:
2112 printf("Geometrical type out of range! ... exiting ...\n");
2113 exit(-1);
2114 break; // never comes here
2115 } // switch over gtsrc ends
2116 } // for all source elements - elesrc
2117
2118 if (dbgFn) {
2119 printf("value after known charges on elements: %g\n", value);
2120 }
2121
2122 // Contribution due to known point charges
2123 Vector3D tmpglobalF; // flux not being used to evaluate Dirichlet value.
2124 for (int point = 1; point <= NbPointsKnCh; ++point) {
2125 value += (PointKnChArr + point - 1)->Assigned *
2126 PointKnChPF((PointKnChArr + point - 1)->P, globalP, &tmpglobalF) /
2127 MyFACTOR;
2128 } // for all points
2129 if (dbgFn) {
2130 printf("value after known charges at points: %g\n", value);
2131 }
2132
2133 // Contribution due to known line charges
2134 for (int line = 1; line <= NbLinesKnCh; ++line) {
2135 value +=
2136 (LineKnChArr + line - 1)->Assigned *
2137 LineKnChPF((LineKnChArr + line - 1)->Start,
2138 (LineKnChArr + line - 1)->Stop,
2139 (LineKnChArr + line - 1)->Radius, globalP, &tmpglobalF) /
2140 MyFACTOR;
2141 } // for lines
2142 if (dbgFn) {
2143 printf("value after known charges on lines: %g\n", value);
2144 }
2145
2146 // Contribution due to known area charges
2147 for (int area = 1; area <= NbAreasKnCh; ++area) {
2148 value +=
2149 (AreaKnChArr + area - 1)->Assigned *
2150 AreaKnChPF((AreaKnChArr + area - 1)->NbVertices,
2151 ((AreaKnChArr + area - 1)->Vertex), globalP, &tmpglobalF) /
2152 MyFACTOR;
2153 } // for areas
2154 if (dbgFn) {
2155 printf("value after known charges on areas: %g\n", value);
2156 }
2157
2158 // Contribution due to known volume charges
2159 for (int vol = 1; vol <= NbVolumesKnCh; ++vol) {
2160 value += (VolumeKnChArr + vol - 1)->Assigned *
2161 VolumeKnChPF((VolumeKnChArr + vol - 1)->NbVertices,
2162 ((VolumeKnChArr + vol - 1)->Vertex), globalP,
2163 &tmpglobalF) /
2164 MyFACTOR;
2165 } // for vols
2166 if (dbgFn) {
2167 printf("value after known charges in volumes: %g\n", value);
2168 }
2169
2170 return (value);
2171} // end of ValueKnCh
2172
2173// Neumann contribution due to known charge distribution.
2174// Note that the return value is negated from the BC which was set up without
2175// considering the presence of existing charges.
2176// Check dielectric-dielectric formulation in
2177// (NumSolnOfBIEforMolES_JPBardhan.pdf):
2178// Numerical solution of boundary-integral equations for molecular
2179// electrostatics,
2180// by Jaydeep P. Bardhan,
2181// THE JOURNAL OF CHEMICAL PHYSICS 130, 094102 (2009)
2182double ContinuityKnCh(int elefld) {
2183 int dbgFn = 0;
2184
2185 double value = 0.0;
2186 double xfld = (EleArr + elefld - 1)->BC.CollPt.X;
2187 double yfld = (EleArr + elefld - 1)->BC.CollPt.Y;
2188 double zfld = (EleArr + elefld - 1)->BC.CollPt.Z;
2189 // Point3D globalP;
2190 Point3D localP;
2191 Vector3D localF, globalF;
2192
2193 // OMPCheck - parallelize
2194
2195 // Effect of known charges on interface elements
2196 for (int elesrc = 1; elesrc <= NbElements; ++elesrc) {
2197 double assigned = (EleArr + elesrc - 1)->Assigned;
2198 if (fabs(assigned) <= 1.0e-16) continue;
2199
2200 Point3D *pOrigin = &(EleArr + elesrc - 1)->G.Origin;
2201
2202 // Retrieve element properties from the structure
2203 if ((EleArr + elesrc - 1)->E.Type == 0) {
2204 printf("Wrong EType for elesrc %d element %d on %dth primitive!\n",
2205 elesrc, (EleArr + elesrc - 1)->Id,
2206 (EleArr + elesrc - 1)->PrimitiveNb);
2207 exit(-1);
2208 }
2209
2210 // translated to local origin but axes direction as in GCS
2211 // globalP.X = xfld - pOrigin->X;
2212 // globalP.Y = yfld - pOrigin->Y;
2213 // globalP.Z = zfld - pOrigin->Z;
2214
2215 { // Rotate point3D from global to local system
2216 double TransformationMatrix[3][3] = {{0.0, 0.0, 0.0},
2217 {0.0, 0.0, 0.0},
2218 {0.0, 0.0, 0.0}};
2219 DirnCosn3D *DirCos = &(EleArr + elesrc - 1)->G.DC;
2220
2221 TransformationMatrix[0][0] = DirCos->XUnit.X;
2222 TransformationMatrix[0][1] = DirCos->XUnit.Y;
2223 TransformationMatrix[0][2] = DirCos->XUnit.Z;
2224 TransformationMatrix[1][0] = DirCos->YUnit.X;
2225 TransformationMatrix[1][1] = DirCos->YUnit.Y;
2226 TransformationMatrix[1][2] = DirCos->YUnit.Z;
2227 TransformationMatrix[2][0] = DirCos->ZUnit.X;
2228 TransformationMatrix[2][1] = DirCos->ZUnit.Y;
2229 TransformationMatrix[2][2] = DirCos->ZUnit.Z;
2230
2231 double InitialVector[3] = {xfld - pOrigin->X, yfld - pOrigin->Y, zfld - pOrigin->Z};
2232 double FinalVector[3] = {0., 0., 0.};
2233 for (int i = 0; i < 3; ++i) {
2234 for (int j = 0; j < 3; ++j) {
2235 FinalVector[i] += TransformationMatrix[i][j] * InitialVector[j];
2236 }
2237 }
2238
2239 localP.X = FinalVector[0];
2240 localP.Y = FinalVector[1];
2241 localP.Z = FinalVector[2];
2242 } // Point3D rotated
2243
2244 // if((((EleArr+elesrc-1)->E.Type == 4) && (elefld == elesrc)) //
2245 // self-influence
2246 // || (((EleArr+elesrc-1)->E.Type == 5) && (elefld == elesrc))) // DD
2247 // intfce
2248 // For self-influence, lmsrc is equal to lmfld which allows the following.
2249 if ((elefld == elesrc) &&
2250 (fabs(localP.X) < (EleArr + elesrc - 1)->G.LX / 2.0) &&
2251 (fabs(localP.Y) < MINDIST) &&
2252 (fabs(localP.Z) < (EleArr + elesrc - 1)->G.LZ / 2.0)) {
2253 value += assigned * 1.0 / (2.0 * EPS0 * (EleArr + elesrc - 1)->E.Lambda);
2254 } else {
2255 // Retrieve element properties from the structure
2256 if ((EleArr + elesrc - 1)->E.Type == 0) {
2257 printf("Wrong EType for elesrc %d element %d on %dth primitive!\n",
2258 elesrc, (EleArr + elesrc - 1)->Id,
2259 (EleArr + elesrc - 1)->PrimitiveNb);
2260 exit(-1);
2261 }
2262
2263 // Following fluxes in the influencing ECS
2264 switch ((EleArr + elesrc - 1)->G.Type) {
2265 case 4: // rectangular element
2266 RecFlux(elesrc, &localP, &localF);
2267 break;
2268 case 3: // triangular element
2269 TriFlux(elesrc, &localP, &localF);
2270 break;
2271 case 2: // linear (wire) element
2272 WireFlux(elesrc, &localP, &localF);
2273 break;
2274 default:
2275 printf("Geometrical type out of range! ... exiting ...\n");
2276 exit(-1);
2277 break; // never comes here
2278 } // switch over gtsrc ends
2279
2280 // in GCS - mirror points?!
2281 globalF =
2282 RotateVector3D(&localF, &(EleArr + elesrc - 1)->G.DC, local2global);
2283 // in ECS (local to the field element)
2284 localF =
2285 RotateVector3D(&globalF, &(EleArr + elefld - 1)->G.DC, global2local);
2286
2287 value -= assigned * localF.Y; // +ve gradient of Green's is -ve normal
2288 // force (changed from -= to += on 02/11/11
2289 // - CHECK!!! - and back to -= on 05/11/11)
2290 } // else self-influence
2291 }
2292
2293 if (dbgFn) {
2294 printf("value: %g\n", value);
2295 }
2296
2297 // Contributions from points, lines areas and volumes carrying known charge
2298 // (density).
2299 // globalP.X = xfld;
2300 // globalP.Y = yfld;
2301 // globalP.Z = zfld;
2302 for (int point = 1; point <= NbPointsKnCh; ++point) {
2303 // potential not being used to evaluate Neumann continuity
2304 // double tempPot =
2305 // PointKnChPF((PointKnChArr + point - 1)->P, globalP, &globalF);
2306 localF =
2307 RotateVector3D(&globalF, &(EleArr + elefld - 1)->G.DC, global2local);
2308 value -= (PointKnChArr + point - 1)->Assigned * localF.Y / MyFACTOR;
2309 } // loop over points NbPointsKnCh
2310
2311 for (int line = 1; line <= NbLinesKnCh; ++line) {
2312 // potential not being used to evaluate Neumann continuity
2313 // double tempPot = LineKnChPF(
2314 // (LineKnChArr + line - 1)->Start, (LineKnChArr + line - 1)->Stop,
2315 // (LineKnChArr + line - 1)->Radius, globalP, &globalF);
2316 localF =
2317 RotateVector3D(&globalF, &(EleArr + elefld - 1)->G.DC, global2local);
2318 value -= (LineKnChArr + line - 1)->Assigned * localF.Y / MyFACTOR;
2319 } // loop over lines
2320
2321 for (int area = 1; area <= NbAreasKnCh; ++area) {
2322 // potential not being used to evaluate Neumann continuity
2323 // double tempPot =
2324 // AreaKnChPF((AreaKnChArr + area - 1)->NbVertices,
2325 // ((AreaKnChArr + area - 1)->Vertex), globalP, &globalF);
2326 localF =
2327 RotateVector3D(&globalF, &(EleArr + elefld - 1)->G.DC, global2local);
2328 value -= (AreaKnChArr + area - 1)->Assigned * localF.Y / MyFACTOR;
2329 } // loop over areas
2330
2331 for (int vol = 1; vol <= NbVolumesKnCh; ++vol) {
2332 // potential not being used to evaluate Neumann continuity
2333 // double tempPot =
2334 // VolumeKnChPF((VolumeKnChArr + vol - 1)->NbVertices,
2335 // ((VolumeKnChArr + vol - 1)->Vertex), globalP, &globalF);
2336 localF =
2337 RotateVector3D(&globalF, &(EleArr + elefld - 1)->G.DC, global2local);
2338 value -= (VolumeKnChArr + vol - 1)->Assigned * localF.Y / MyFACTOR;
2339 } // loop over volumes
2340
2341 return (value);
2342} // end of ContinuityKnCh
2343
2344// Effect of charging up on the boundary conditions
2345/* This is what we need finally
2346
2347double EffectChUp(int caseid, int elefld)
2348{
2349switch(caseid)
2350 {
2351 case 1:
2352 return(ValueChUp(elefld);
2353 break;
2354 case 2:
2355 return(ContinuityChUp(elefld);
2356 break;
2357 default:
2358 printf("not an allowed configuration in EffectChUp ...
2359returning\n"); return(-1);
2360 }
2361} // EffectChUp ends
2362*/
2363
2364double EffectChUp(int elefld) { return (ValueChUp(elefld)); }
2365
2366// Effect of charging up on the Dirichlet boundary conditions
2367double ValueChUp(int elefld) {
2368
2369 printf("In ValueChUp ...\n");
2370
2371 // prepare LHMatrix to compute EffectChUp
2372 if (!InfluenceMatrixFlag) {
2373 printf("Influence matrix NOT in memory ...\n");
2374
2376 printf("reading influence coefficient matrix from formatted file...\n");
2377
2378 char InflFile[256];
2379 strcpy(InflFile, MeshOutDir);
2380 strcat(InflFile, "/Infl.out");
2381 FILE *fInf = fopen(InflFile, "r");
2382 // assert(fInf != NULL);
2383 if (fInf == NULL) {
2384 neBEMMessage("Solve - InflFile in OptValidate.");
2385 return 1;
2386 }
2387
2388 int chkNbEqns, chkNbUnknowns;
2389 fscanf(fInf, "%d %d\n", &chkNbEqns, &chkNbUnknowns);
2390 if ((chkNbEqns != NbEqns) || (chkNbUnknowns != NbUnknowns)) {
2391 neBEMMessage("Solve - matrix dimension do not match!");
2392 return (-1);
2393 }
2394
2395 printf("Solve: Matrix dimensions: %d equations, %d unknowns\n", NbEqns,
2396 NbUnknowns);
2397
2398 Inf = dmatrix(1, NbEqns, 1, NbUnknowns);
2399
2400 for (int ifld = 1; ifld <= NbEqns; ++ifld)
2401 for (int jsrc = 1; jsrc <= NbUnknowns; ++jsrc)
2402 fscanf(fInf, "%le\n", &Inf[ifld][jsrc]);
2403 fclose(fInf);
2404 } else {
2405 printf("repeating influence coefficient matrix computation ...\n");
2406
2407 int fstatus = LHMatrix();
2408 // assert(fstatus == 0);
2409 if (fstatus != 0) {
2410 neBEMMessage("Solve - LHMatrix in OptRepeatLHMatrix");
2411 return -1;
2412 }
2413 }
2414
2416 neBEMMessage("Solve - Binary read of Infl matrix not implemented yet.\n");
2417 } // if OptStoreInflMatrix and Unformatted file
2418
2420 } // if(!InfluenceMatrixFlag)
2421
2422 // This approach works because Inf is supposed to contain information of
2423 // repetitions, mirrors and other geometrical attributes of the system
2424 double value = 0.0;
2425 for (int elesrc = 1; elesrc <= NbElements; ++elesrc) {
2426 value += Inf[elefld][elesrc] * (EleArr + elesrc - 1)->Assigned;
2427 if (0) {
2428 printf("elesrc, Inf, Assigned, value: %d, %lg, %lg, %lg\n", elesrc,
2429 Inf[elefld][elesrc], (EleArr + elesrc - 1)->Assigned, value);
2430 }
2431 }
2432
2433 printf("Exiting ValueChUp ...\n");
2434 return value;
2435} // ValueChUp ends
2436
2437// Effect of charging up on the Neumann boundary condition
2438// int ContinuityChUp() ...
2439
2440// An error estimate should be carried out irrespective of the DebugLevel
2441int Solve(void) {
2442 double **RawInf = NULL;
2443 int LHMatrix(void);
2444
2446 // printf("Solution array allocated\n"); fflush(stdout);
2447
2448 printf("\ncomputing solution for each element: ");
2449
2450 for (int i = 1; i <= NbUnknowns; i++) {
2451 printf("%6d ...", i);
2452 Solution[i] = 0.0;
2453
2454 double sum = 0.0;
2455 int j;
2456#ifdef _OPENMP
2457 #pragma omp parallel for private(j) reduction(+ : sum)
2458#endif
2459 for (j = 1; j <= NbUnknowns; j++) {
2460 sum += InvMat[i][j] * RHS[j]; // new
2461 }
2462
2463 Solution[i] = sum;
2464 printf("\b\b\b\b\b\b\b\b\b\b");
2465 }
2466 fflush(stdout);
2467
2468 printf("\nsolution over for all elements ...\n");
2469 fflush(stdout);
2470
2471 if (NbConstraints) {
2472 if (OptSystemChargeZero) {
2474 printf("\nsolution over for system charge zero constraint ...\n");
2475 fflush(stdout);
2476 }
2477
2480 printf(
2481 "\nsolution over for floating conductor charge zero constraint "
2482 "...\n");
2483 fflush(stdout);
2484 }
2485 } // if NbConstraints
2486
2487 // Update the element structure array and write the solution in a file
2488 char SolnFile[256];
2489 strcpy(SolnFile, BCOutDir);
2490 strcat(SolnFile, "/Soln.out");
2491 FILE* fSoln = fopen(SolnFile, "w");
2492 if (fSoln == NULL) {
2493 neBEMMessage("Solve - SolnFile");
2494 return -1;
2495 }
2496 fprintf(fSoln, "#EleNb\tX\tY\tZ\tSolution\tAssigned\tTotal\n");
2497 for (int ele = 1; ele <= NbElements; ++ele) {
2498 (EleArr + ele - 1)->Solution = Solution[ele];
2499 fprintf(fSoln, "%d\t%lg\t%lg\t%lg\t%.16lg\t%.16lg\t%.16lg\n", ele,
2500 (EleArr + ele - 1)->G.Origin.X, (EleArr + ele - 1)->G.Origin.Y,
2501 (EleArr + ele - 1)->G.Origin.Z, (EleArr + ele - 1)->Solution,
2502 (EleArr + ele - 1)->Assigned,
2503 ((EleArr + ele - 1)->Solution + (EleArr + ele - 1)->Assigned));
2504 }
2505
2506 if (NbConstraints) {
2507 if (OptSystemChargeZero) {
2508 fprintf(fSoln, "#NbSystemChargeZero\tVSystemChargeZero\n");
2509 fprintf(fSoln, "# %d\t%lg\n", NbSystemChargeZero, VSystemChargeZero);
2510 }
2512 fprintf(fSoln, "#NbFloatCon\tVFloatCon\n");
2513 fprintf(fSoln, "# %d\t%lg\n", NbFloatCon, VFloatCon);
2514 }
2515 } // if NbConstraints
2516
2517 fclose(fSoln);
2518
2519 // Find primitive related charge densities
2520 char PrimSolnFile[256];
2521 strcpy(PrimSolnFile, BCOutDir);
2522 strcat(PrimSolnFile, "/PrimSoln.out");
2523 FILE *fPrimSoln = fopen(PrimSolnFile, "w");
2524 if (fPrimSoln == NULL) {
2525 neBEMMessage("Solve - PrimSolnFile");
2526 return -1;
2527 }
2528 fprintf(fPrimSoln, "#PrimNb\tEleBgn\tEleEnd\tX\tY\tZ\tAvChDen\tAvAsgndChDen\n");
2529 // OMPCheck - may be parallelized
2530 for (int prim = 1; prim <= NbPrimitives; ++prim) {
2531 double area = 0.0; // need area of the primitive as well!
2532 AvChDen[prim] = 0.0;
2533 AvAsgndChDen[prim] = 0.0;
2534
2535 for (int ele = ElementBgn[prim]; ele <= ElementEnd[prim]; ++ele) {
2536 area += (EleArr + ele - 1)->G.dA;
2537 AvChDen[prim] += (EleArr + ele - 1)->Solution * (EleArr + ele - 1)->G.dA;
2538 AvAsgndChDen[prim] +=
2539 (EleArr + ele - 1)->Assigned * (EleArr + ele - 1)->G.dA;
2540 }
2541
2542 AvChDen[prim] /= area;
2543 AvAsgndChDen[prim] /= area;
2544
2545 fprintf(fPrimSoln, "%d\t%d\t%d\t%lg\t%lg\t%lg\t%.16lg\t%.16g\n", prim,
2546 ElementBgn[prim], ElementEnd[prim], PrimOriginX[prim],
2547 PrimOriginY[prim], PrimOriginZ[prim], AvChDen[prim],
2548 AvAsgndChDen[prim]);
2549 }
2550
2551 fclose(fPrimSoln);
2552
2553 neBEMState = 9;
2554
2555 // Validate the obtained solution, i.e., estimate the residue at the
2556 // collocation points. The validation is expected to be carried out by the
2557 // influence matrix already available in the memory. If, however, for some
2558 // reason (such as a repeat calculation), the influence coefficient matrix is
2559 // not available, it can be retrieved by carrying out the computation once
2560 // again, reading it from a formatted or an unformatted file.
2561 printf("OptValidateSolution: %d\n", OptValidateSolution);
2562 if (OptValidateSolution) {
2563 printf("Computing solution at the collocation points for comparison.\n");
2564 fflush(stdout);
2565
2566 if (InfluenceMatrixFlag) {
2567 printf("Influence matrix in memory ...\n");
2568 }
2569
2570 // Only when InfluenceMatrixFlag is false, the influence coefficient
2571 // reamins uncomputed. Then the question of re-computation or reading it
2572 // from a file (formatted / unformatted) arises.
2573 if (!InfluenceMatrixFlag) {
2574 if (TimeStep != 1) {
2575 // influence matrix to be computed only in the first time step
2576 printf("Influence matrix in memory ...\n");
2577 } else {
2578 printf("Influence matrix NOT in memory ...\n");
2579
2580 if (OptRepeatLHMatrix) {
2581 printf("repeating influence coefficient matrix computation ...\n");
2582
2583 int fstatus = LHMatrix();
2584 // assert(fstatus == 0);
2585 if (fstatus != 0) {
2586 neBEMMessage("Solve - LHMatrix in OptRepeatLHMatrix");
2587 return -1;
2588 }
2589 }
2590
2592 printf(
2593 "reading influence coefficient matrix from formatted file...\n");
2594
2595 char InflFile[256];
2596 strcpy(InflFile, MeshOutDir);
2597 strcat(InflFile, "/Infl.out");
2598 FILE *fInf = fopen(InflFile, "r");
2599 // assert(fInf != NULL);
2600 if (fInf == NULL) {
2601 neBEMMessage("Solve - InflFile in OptValidate.");
2602 return 1;
2603 }
2604
2605 int chkNbEqns, chkNbUnknowns;
2606 fscanf(fInf, "%d %d\n", &chkNbEqns, &chkNbUnknowns);
2607 if ((chkNbEqns != NbEqns) || (chkNbUnknowns != NbUnknowns)) {
2608 neBEMMessage("Solve - matrix dimension do not match!");
2609 return (-1);
2610 }
2611
2612 printf("Solve: Matrix dimensions: %d equations, %d unknowns\n",
2614
2615 Inf = dmatrix(1, NbEqns, 1, NbUnknowns);
2616
2617 for (int elefld = 1; elefld <= NbEqns; ++elefld)
2618 for (int elesrc = 1; elesrc <= NbUnknowns; ++elesrc)
2619 fscanf(fInf, "%le\n", &Inf[elefld][elesrc]);
2620 fclose(fInf);
2621 } // stored influence matrix and formatted file
2622
2625 "Solve - Binary read of Infl matrix not implemented yet.\n");
2626 return -1;
2627
2628 RawInf = dmatrix(1, NbEqns, 1, NbUnknowns);
2629
2630 printf(
2631 "reading influence coefficient matrix from unformatted file "
2632 "...\n");
2633
2634 char InflFile[256];
2635 strcpy(InflFile, MeshOutDir);
2636 strcat(InflFile, "/RawInfl.out");
2637 printf("\nread from file %s\n", InflFile);
2638 fflush(stdout);
2639 FILE *fInf = fopen(InflFile, "rb");
2640 // assert(fInf != NULL);
2641 if (fInf == NULL) {
2642 neBEMMessage("Solve - RawInflFile in OptValidate");
2643 return -1;
2644 }
2645 printf("\nfInf: %p\n", (void *)fInf);
2646 int rfw = fread(RawInf, sizeof(double), NbEqns * NbUnknowns, fInf);
2647 fclose(fInf);
2648 printf("\nNb of items successfully read from raw mode in %s is %d\n",
2649 InflFile, rfw);
2650 fflush(stdout);
2651
2652 for (int unknown = 1; unknown <= NbUnknowns; ++unknown)
2653 for (int eqn = 1; eqn <= NbEqns; ++eqn)
2654 printf(
2655 "Unknown:%d, Eqn:%d => diff Inf: %lg, RawInf: %lg is %lg\n",
2656 unknown, eqn, Inf[unknown][eqn], RawInf[unknown][eqn],
2657 fabs(Inf[unknown][eqn] - RawInf[unknown][eqn]));
2658 } // if OptStoreInflMatrix and Unformatted file
2659 } // else TimeStep != 1
2660 } // if(!InfluenceMatrixFlag)
2661
2662 // Used for all validations except where re-computation is forced which
2663 // is taken care of by else of this if
2664 if (Inf || RawInf) {
2665 double XChk;
2666 char Chkfile[256];
2667 strcpy(Chkfile, BCOutDir);
2668 strcat(Chkfile, "/XChk.out");
2669 FILE *fChk = fopen(Chkfile, "w"); // assert(fChk != NULL);
2670 if (fChk == NULL) {
2671 neBEMMessage("Solve - ChkFile");
2672 return -1;
2673 }
2674 fprintf(fChk, "#Row\tGivenPot\tError\n");
2675
2676 int ElementOfMaxError = 1;
2677 double *Error, MaxError = 0.0;
2678 Error = dvector(1, NbEqns);
2679 int elesrc;
2680#ifdef _OPENMP
2681 #pragma omp parallel for private(elesrc)
2682#endif
2683 for (int elefld = 1; elefld <= NbEqns; elefld++) {
2684 XChk = 0.0;
2685 for (elesrc = 1; elesrc <= NbUnknowns; elesrc++) {
2688 XChk += RawInf[elefld][elesrc] * Solution[elesrc];
2689 else
2690 XChk += Inf[elefld][elesrc] * Solution[elesrc];
2691 } // for elesrc
2692 Error[elefld] = fabs(RHS[elefld] - XChk);
2693
2694 if (Error[elefld] > MaxError) {
2695 MaxError = Error[elefld]; // update maximum error related info
2696 ElementOfMaxError = elefld;
2697 }
2698 } // for elefld
2699 for (int elefld = 1; elefld <= NbEqns; elefld++)
2700 fprintf(fChk, "%d\t%lg\t%lg\n", elefld, RHS[elefld], Error[elefld]);
2701 free_dvector(Error, 1, NbEqns);
2702
2703 printf("Computed values at the collocation points for comparison.\n");
2704 printf("Error maximum on element %d and its magnitude is %lg.\n",
2705 ElementOfMaxError, MaxError);
2706 fflush(stdout);
2707
2708 fprintf(fChk, "#Error maximum on element %d and its magnitude is %lg.\n",
2709 ElementOfMaxError, MaxError);
2710 fclose(fChk);
2711
2717 free_dmatrix(RawInf, 1, NbEqns, 1, NbUnknowns);
2718 } // if(Inf || RawInf)
2719 else {
2720 if (OptForceValidation) {
2722 "Solve - Infl matrix not available, re-computation forced.\n");
2723
2724 int fstatus = LHMatrix();
2725 if (fstatus != 0) {
2726 neBEMMessage("Solve - LHMatrix in forced OptRepeatLHMatrix");
2727 return -1;
2728 }
2729
2730 double XChk;
2731 char Chkfile[256];
2732 FILE *fChk;
2733 strcpy(Chkfile, BCOutDir);
2734 strcat(Chkfile, "/XChk.out");
2735 fChk = fopen(Chkfile, "w");
2736 if (fChk == NULL) {
2737 neBEMMessage("Solve - ChkFile in forced recomputation");
2738 return -1;
2739 }
2740 fprintf(fChk, "#Row\tGivenPot\tComputedPot\tDiff\n");
2741
2742 int ElementOfMaxError = 1;
2743 double Error, MaxError = 0.0;
2744 for (int elefld = 1; elefld <= NbEqns; elefld++) {
2745 XChk = 0.0;
2746 for (int elesrc = 1; elesrc <= NbUnknowns; elesrc++) {
2747 XChk += Inf[elefld][elesrc] * Solution[elesrc];
2748 }
2749 Error = fabs(RHS[elefld] - XChk);
2750 fprintf(fChk, "%d\t%lg\t%lg\t%lg\n", elefld, RHS[elefld], XChk,
2751 Error);
2752
2753 if (Error > MaxError) {
2754 MaxError = Error; // update maximum error related info
2755 ElementOfMaxError = elefld;
2756 }
2757 }
2758
2759 printf("Computed values at the collocation points for comparison.\n");
2760 printf("Error maximum on element %d and its magnitude is %lg.\n",
2761 ElementOfMaxError, MaxError);
2762 fflush(stdout);
2763
2764 fprintf(fChk,
2765 "#Error maximum on element %d and its magnitude is %lg.\n",
2766 ElementOfMaxError, MaxError);
2767 fclose(fChk);
2768
2770 } else { // this is not an error, though
2771 neBEMMessage("Solve - Infl matrix not available, no validation.\n");
2772 }
2773 } // else (Inf || RawInf)
2774 } // if(OptValidateSolution)
2775
2776 /*
2777 Find out the error at relevant points. The points are chosen such that the
2778 mesh can be refined based on the errors obtained. For example, if the error
2779 at a particular point is found to be more than acceptable, an additional
2780 element (including necessary adjustment of the elements on the primitive
2781 in question) can easily be inserted to improve the accuracy of the solution.
2782 The validation is NOT expected to be carried out by the influence matrix
2783 already available in the memory, since the evaluation points no longer
2784 coincides with the collocation (qualocation?) points used to compute the
2785 solution. There is no question of repeating the computation, as while
2786 estimating the RESIDUE (Validation block immediately above this paragraph).
2787 The relevant points of rectangular elements are the centroid of four
2788 possible quadrants, whereas, for the triangular elements, these are the
2789 centroid of the rectangular and two barycentre of the two possible right
2790 triangles.
2791 In the following figures, X-s represent the collocation points, while x-s
2792 represent the points introduced to estimate error. For the triangle,
2793 there is a possibility of overlap of X and x of the rectangle.
2794 ----------------------------
2795 | | |
2796 | x | x |
2797 | | |
2798 --------------X-------------
2799 | | |
2800 | x | x |
2801 | | |
2802 ----------------------------
2803 \
2804 |\
2805 | \
2806 |x \
2807 ----\
2808 | |\
2809 | x | \
2810 | |x \
2811 --------\
2812 */
2813
2814 OptEstimateError = 0; // temporary measure
2815 printf("OptEstimateError: %d\n", OptEstimateError);
2816 if (OptEstimateError) {
2817 printf(
2818 "Properties at non-collocation points on element for estimating "
2819 "error.\n");
2820 fflush(stdout);
2821
2822 double Err;
2823 int PrimitiveOfMaxError = 1;
2824 int ElementOfMaxError = 1;
2825 double MaxError = 0.0;
2826 double xerrMax = 0.0, yerrMax = 0.0, zerrMax = 0.0;
2827
2828 char Errfile[256];
2829 strcpy(Errfile, BCOutDir);
2830 strcat(Errfile, "/Errors.out");
2831 FILE *fErr = fopen(Errfile, "w");
2832 if (fErr == NULL) {
2833 neBEMMessage("Solve - ErrFile");
2834 return -1;
2835 }
2836 fprintf(fErr,
2837 "#Prim\tEle\tGType\tIType\txerr\tyerr\tzerr\tGivenBC\tComputVal\tDi"
2838 "ff\n");
2839
2840 // loop over all the elements - at present wire elements are NOT
2841 // considered!! We now also have ElementBgn and ElementEnd for each
2842 // primitive. So, we can loop over primtives and, within it, the necessary
2843 // elements can be considered. It turns out that going from primitive to
2844 // primitive can result into lesser computation. For example, E.Type for an
2845 // entire primitive is the same, and does not need to be evaluated from
2846 // element to element. conductor-dielectric: 1, conductor with known charge:
2847 // 2 conductor with floating potential: 3, dielectric-dielectric: 4
2848 // dielectric with known charge: 5
2849 // At present, error-accounting is maintained only for two types of
2850 // interfaces, C-D interfaces (specified voltage), D-D interfaces
2851 // (continuity of displacement current implied)
2852 // OMPCheck - may be parallelized
2853 for (int prim = 1; prim <= NbPrimitives; ++prim)
2854 for (int ele = ElementBgn[prim]; ele <= ElementEnd[prim]; ++ele) {
2855 double normdisp = 1.0e-8; // displacement in the normal direction
2856
2857 if ((prim == 91) && (ele == 337)) // debug switches are turned on
2858 {
2859 // DebugLevel = 1001;
2860 DebugLevel = 0;
2861 } else // turn off switches
2862 {
2863 DebugLevel = 0;
2864 }
2865
2866 // find relevant points for this element; compute PF and cross-check
2867 // with BC
2868 if ((EleArr + ele - 1)->G.Type == 2) continue;
2869
2870 if ((EleArr + ele - 1)->G.Type == 3) // triangle
2871 { // 3 points need to be considered for estimating error (above fig)
2872 Point3D globalP;
2873 double Potential;
2874 Vector3D globalF, localF;
2875 double x0 = (EleArr + ele - 1)->G.Vertex[0].X;
2876 double y0 = (EleArr + ele - 1)->G.Vertex[0].Y;
2877 double z0 = (EleArr + ele - 1)->G.Vertex[0].Z;
2878 double x1 = (EleArr + ele - 1)->G.Vertex[1].X;
2879 double y1 = (EleArr + ele - 1)->G.Vertex[1].Y;
2880 double z1 = (EleArr + ele - 1)->G.Vertex[1].Z;
2881 double x2 = (EleArr + ele - 1)->G.Vertex[2].X;
2882 double y2 = (EleArr + ele - 1)->G.Vertex[2].Y;
2883 double z2 = (EleArr + ele - 1)->G.Vertex[2].Z;
2884 double xb = (x0 + x1 + x2) / 3.0; // b for barycentre
2885 double yb = (y0 + y1 + y2) / 3.0; // b for barycentre
2886 double zb = (z0 + z1 + z2) / 3.0; // b for barycentre
2887
2888 // check values at the barycentre
2889 globalP.X = xb;
2890 globalP.Y = yb;
2891 globalP.Z = zb;
2892 if (InterfaceType[prim] == 1) {
2893 PFAtPoint(&globalP, &Potential, &globalF);
2894 Err = ApplPot[prim] - Potential;
2895 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
2896 prim, ele, 3, 1, xb, yb, zb, ApplPot[prim], Potential, Err);
2897 if (fabs(Err) > fabs(MaxError)) {
2898 MaxError = Err;
2899 PrimitiveOfMaxError = prim;
2900 ElementOfMaxError = ele;
2901 xerrMax = xb;
2902 yerrMax = yb;
2903 zerrMax = zb;
2904 }
2905 }
2906 if (InterfaceType[prim] ==
2907 4) { // compute displacement currents in the two dielectrics
2908 double xplus = xb + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
2909 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
2910 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
2911 double yplus = yb + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
2912 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
2913 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
2914 double zplus = zb + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
2915 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
2916 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
2917 globalP.X = xplus;
2918 globalP.Y = yplus;
2919 globalP.Z = zplus;
2920 PFAtPoint(&globalP, &Potential, &globalF);
2921 localF // Flux in the ECS
2922 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
2923 global2local);
2924 double value1 = -localF.Y;
2925 double xminus = xb - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
2926 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
2927 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
2928 double yminus = yb - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
2929 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
2930 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
2931 double zminus = zb - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
2932 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
2933 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
2934 globalP.X = xminus;
2935 globalP.Y = yminus;
2936 globalP.Z = zminus;
2937 PFAtPoint(&globalP, &Potential, &globalF);
2938 localF // Flux in the ECS
2939 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
2940 global2local);
2941 double value2 = -localF.Y;
2942 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
2943 Err = epsratio - (value1 / value2);
2944 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
2945 prim, ele, 3, 4, xb, yb, zb, epsratio, (value1 / value2),
2946 Err);
2947 if (fabs(Err) > fabs(MaxError)) {
2948 MaxError = Err;
2949 PrimitiveOfMaxError = prim;
2950 ElementOfMaxError = ele;
2951 xerrMax = xb;
2952 yerrMax = yb;
2953 zerrMax = zb;
2954 }
2955 }
2956
2957 // values at the centroid of the rectangular part
2958 double xerr =
2959 0.25 * (x0 + 0.5 * (x0 + x1) + 0.5 * (x1 + x2) + 0.5 * (x0 + x2));
2960 double yerr =
2961 0.25 * (y0 + 0.5 * (y0 + y1) + 0.5 * (y1 + y2) + 0.5 * (y0 + y2));
2962 double zerr =
2963 0.25 * (z0 + 0.5 * (z0 + z1) + 0.5 * (z1 + z2) + 0.5 * (z0 + z2));
2964 globalP.X = xerr;
2965 globalP.Y = yerr;
2966 globalP.Z = zerr;
2967 // At present, error-accounting is maintained only for two types of
2968 // interfaces, C-D interfaces (specified voltage), D-D interfaces
2969 // (continuity of displacement current implied)
2970 if (InterfaceType[prim] == 1) {
2971 PFAtPoint(&globalP, &Potential, &globalF);
2972 Err = ApplPot[prim] - Potential;
2973 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
2974 prim, ele, 3, 1, xerr, yerr, zerr, ApplPot[prim], Potential,
2975 Err);
2976 if (fabs(Err) > fabs(MaxError)) {
2977 MaxError = Err;
2978 PrimitiveOfMaxError = prim;
2979 ElementOfMaxError = ele;
2980 xerrMax = xerr;
2981 yerrMax = yerr;
2982 zerrMax = zerr;
2983 }
2984 }
2985 if (InterfaceType[prim] ==
2986 4) { // compute displacement currents in the two dielectrics
2987 double xplus = xerr + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
2988 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
2989 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
2990 double yplus = yerr + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
2991 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
2992 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
2993 double zplus = zerr + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
2994 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
2995 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
2996 globalP.X = xplus;
2997 globalP.Y = yplus;
2998 globalP.Z = zplus;
2999 PFAtPoint(&globalP, &Potential, &globalF);
3000 localF // Flux in the ECS
3001 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3002 global2local);
3003 double value1 = -localF.Y;
3004 double xminus = xerr - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3005 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3006 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3007 double yminus = yerr - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3008 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3009 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3010 double zminus = zerr - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3011 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3012 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3013 globalP.X = xminus;
3014 globalP.Y = yminus;
3015 globalP.Z = zminus;
3016 PFAtPoint(&globalP, &Potential, &globalF);
3017 localF // Flux in the ECS
3018 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3019 global2local);
3020 double value2 = -localF.Y;
3021 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
3022 Err = epsratio - (value1 / value2);
3023 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3024 prim, ele, 3, 4, xerr, yerr, zerr, epsratio,
3025 (value1 / value2), Err);
3026 if (fabs(Err) > fabs(MaxError)) {
3027 MaxError = Err;
3028 PrimitiveOfMaxError = prim;
3029 ElementOfMaxError = ele;
3030 xerrMax = xerr;
3031 yerrMax = yerr;
3032 zerrMax = zerr;
3033 }
3034 }
3035
3036 // barycentre of the triangular part towards +ve X-axis of ECS
3037 xerr = (0.5 * (x0 + x1) + 0.5 * (x1 + x2) + x1) / 3.0;
3038 yerr = (0.5 * (y0 + y1) + 0.5 * (y1 + y2) + y1) / 3.0;
3039 zerr = (0.5 * (z0 + z1) + 0.5 * (z1 + z2) + z1) / 3.0;
3040 globalP.X = xerr;
3041 globalP.Y = yerr;
3042 globalP.Z = zerr;
3043 // At present, error-accounting is maintained only for two types of
3044 // interfaces, C-D interfaces (specified voltage), D-D interfaces
3045 // (continuity of displacement current implied)
3046 if (InterfaceType[prim] == 1) {
3047 PFAtPoint(&globalP, &Potential, &globalF);
3048 Err = ApplPot[prim] - Potential;
3049 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3050 prim, ele, 3, 1, xerr, yerr, zerr, ApplPot[prim], Potential,
3051 Err);
3052 if (fabs(Err) > fabs(MaxError)) {
3053 MaxError = Err;
3054 PrimitiveOfMaxError = prim;
3055 ElementOfMaxError = ele;
3056 xerrMax = xerr;
3057 yerrMax = yerr;
3058 zerrMax = zerr;
3059 }
3060 }
3061 if (InterfaceType[prim] ==
3062 4) { // compute displacement currents in the two dielectrics
3063 double xplus = xerr + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3064 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3065 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3066 double yplus = yerr + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3067 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3068 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3069 double zplus = zerr + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3070 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3071 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3072 globalP.X = xplus;
3073 globalP.Y = yplus;
3074 globalP.Z = zplus;
3075 PFAtPoint(&globalP, &Potential, &globalF);
3076 localF // Flux in the ECS
3077 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3078 global2local);
3079 double value1 = -localF.Y;
3080 double xminus = xerr - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3081 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3082 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3083 double yminus = yerr - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3084 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3085 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3086 double zminus = zerr - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3087 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3088 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3089 globalP.X = xminus;
3090 globalP.Y = yminus;
3091 globalP.Z = zminus;
3092 PFAtPoint(&globalP, &Potential, &globalF);
3093 localF // Flux in the ECS
3094 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3095 global2local);
3096 double value2 = -localF.Y;
3097 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
3098 Err = epsratio - (value1 / value2);
3099 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3100 prim, ele, 3, 4, xerr, yerr, zerr, epsratio,
3101 (value1 / value2), Err);
3102 if (fabs(Err) > fabs(MaxError)) {
3103 MaxError = Err;
3104 PrimitiveOfMaxError = prim;
3105 ElementOfMaxError = ele;
3106 xerrMax = xerr;
3107 yerrMax = yerr;
3108 zerrMax = zerr;
3109 }
3110 }
3111
3112 // barycentre of the triangular part towards +ve Z-axis of ECS
3113 xerr = (0.5 * (x0 + x2) + 0.5 * (x1 + x2) + x2) / 3.0;
3114 yerr = (0.5 * (y0 + y2) + 0.5 * (y1 + y2) + y2) / 3.0;
3115 zerr = (0.5 * (z0 + z2) + 0.5 * (z1 + z2) + z2) / 3.0;
3116 globalP.X = xerr;
3117 globalP.Y = yerr;
3118 globalP.Z = zerr;
3119 // At present, error-accounting is maintained only for two types of
3120 // interfaces, C-D interfaces (specified voltage), D-D interfaces
3121 // (continuity of displacement current implied)
3122 if (InterfaceType[prim] == 1) {
3123 PFAtPoint(&globalP, &Potential, &globalF);
3124 Err = ApplPot[prim] - Potential;
3125 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3126 prim, ele, 3, 1, xerr, yerr, zerr, ApplPot[prim], Potential,
3127 Err);
3128 if (fabs(Err) > fabs(MaxError)) {
3129 MaxError = Err;
3130 PrimitiveOfMaxError = prim;
3131 ElementOfMaxError = ele;
3132 xerrMax = xerr;
3133 yerrMax = yerr;
3134 zerrMax = zerr;
3135 }
3136 }
3137 if (InterfaceType[prim] ==
3138 4) { // compute displacement currents in the two dielectrics
3139 double xplus = xerr + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3140 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3141 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3142 double yplus = yerr + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3143 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3144 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3145 double zplus = zerr + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3146 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3147 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3148 globalP.X = xplus;
3149 globalP.Y = yplus;
3150 globalP.Z = zplus;
3151 PFAtPoint(&globalP, &Potential, &globalF);
3152 localF // Flux in the ECS
3153 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3154 global2local);
3155 double value1 = -localF.Y;
3156 double xminus = xerr - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3157 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3158 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3159 double yminus = yerr - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3160 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3161 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3162 double zminus = zerr - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3163 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3164 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3165 globalP.X = xminus;
3166 globalP.Y = yminus;
3167 globalP.Z = zminus;
3168 PFAtPoint(&globalP, &Potential, &globalF);
3169 localF // Flux in the ECS
3170 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3171 global2local);
3172 double value2 = -localF.Y;
3173 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
3174 Err = epsratio - (value1 / value2);
3175 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3176 prim, ele, 4, 4, xerr, yerr, zerr, epsratio,
3177 (value1 / value2), Err);
3178 if (fabs(Err) > fabs(MaxError)) {
3179 MaxError = Err;
3180 PrimitiveOfMaxError = prim;
3181 ElementOfMaxError = ele;
3182 xerrMax = xerr;
3183 yerrMax = yerr;
3184 zerrMax = zerr;
3185 }
3186 }
3187 } // if triangle
3188
3189 if ((EleArr + ele - 1)->G.Type == 4) // rectangle
3190 { // 4 points need to be considered for estimating error (above fig)
3191 Point3D globalP;
3192 double Potential;
3193 Vector3D globalF, localF;
3194
3195 double x0 = (EleArr + ele - 1)->G.Vertex[0].X;
3196 double y0 = (EleArr + ele - 1)->G.Vertex[0].Y;
3197 double z0 = (EleArr + ele - 1)->G.Vertex[0].Z;
3198 double x1 = (EleArr + ele - 1)->G.Vertex[1].X;
3199 double y1 = (EleArr + ele - 1)->G.Vertex[1].Y;
3200 double z1 = (EleArr + ele - 1)->G.Vertex[1].Z;
3201 double x2 = (EleArr + ele - 1)->G.Vertex[2].X;
3202 double y2 = (EleArr + ele - 1)->G.Vertex[2].Y;
3203 double z2 = (EleArr + ele - 1)->G.Vertex[2].Z;
3204 double x3 = (EleArr + ele - 1)->G.Vertex[3].X;
3205 double y3 = (EleArr + ele - 1)->G.Vertex[3].Y;
3206 double z3 = (EleArr + ele - 1)->G.Vertex[3].Z;
3207 double xo = 0.25 * (x0 + x1 + x2 + x3); // o for origin
3208 double yo = 0.25 * (y0 + y1 + y2 + y3); // o for origin
3209 double zo = 0.25 * (z0 + z1 + z2 + z3); // o for origin
3210
3211 // check values at the centroid of the element
3212 globalP.X = xo;
3213 globalP.Y = yo;
3214 globalP.Z = zo;
3215 if (InterfaceType[prim] == 1) {
3216 PFAtPoint(&globalP, &Potential, &globalF);
3217 Err = ApplPot[prim] - Potential;
3218 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3219 prim, ele, 4, 1, xo, yo, zo, ApplPot[prim], Potential, Err);
3220 if (fabs(Err) > fabs(MaxError)) {
3221 MaxError = Err;
3222 PrimitiveOfMaxError = prim;
3223 ElementOfMaxError = ele;
3224 xerrMax = xo;
3225 yerrMax = yo;
3226 zerrMax = zo;
3227 }
3228 }
3229 if (InterfaceType[prim] == 4) {
3230 // compute displacement currents in the two dielectrics
3231 double xplus = xo + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3232 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3233 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3234 double yplus = yo + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3235 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3236 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3237 double zplus = zo + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3238 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3239 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3240 globalP.X = xplus;
3241 globalP.Y = yplus;
3242 globalP.Z = zplus;
3243 PFAtPoint(&globalP, &Potential, &globalF);
3244 localF // Flux in the ECS
3245 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3246 global2local);
3247 double dispfld1 = Epsilon1[prim] * localF.Y;
3248 double xminus = xo - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3249 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3250 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3251 double yminus = yo - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3252 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3253 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3254 double zminus = zo - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3255 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3256 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3257 globalP.X = xminus;
3258 globalP.Y = yminus;
3259 globalP.Z = zminus;
3260 PFAtPoint(&globalP, &Potential, &globalF);
3261 localF // Flux in the ECS
3262 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3263 global2local);
3264 double dispfld2 = Epsilon2[prim] * localF.Y;
3265 globalP.X = xo;
3266 globalP.Y = yo;
3267 globalP.Z = zo;
3268 PFAtPoint(&globalP, &Potential, &globalF);
3269 localF // Flux in the ECS
3270 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3271 global2local);
3272 double dispfldo = Epsilon1[prim] * localF.Y;
3273 Err = (dispfld2 - dispfld1) /
3274 dispfldo; // - (&(EleArr+ele-1)->Assigned);
3275 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3276 prim, ele, 4, 4, xo, yo, zo, dispfld1, dispfld2, Err);
3277 if ((prim == 91) && (ele == 337)) {
3278 // debug switches are turned on
3279 double TotalInfl = 0.0;
3280 for (int elesrc = 1; elesrc <= NbElements; ++elesrc) {
3281 TotalInfl += Inf[ele][elesrc] * (EleArr + elesrc - 1)->Solution;
3282 }
3283 printf("TotalInfl: %lg\n", TotalInfl);
3284 printf(
3285 "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\t%"
3286 "lg\n",
3287 prim, ele, 4, 4, xo, yo, zo, Epsilon1[prim], Epsilon2[prim],
3288 dispfld1, dispfld2, dispfldo, Err);
3289 }
3290 if (fabs(Err) > fabs(MaxError)) {
3291 MaxError = Err;
3292 PrimitiveOfMaxError = prim;
3293 ElementOfMaxError = ele;
3294 xerrMax = xo;
3295 yerrMax = yo;
3296 zerrMax = zo;
3297 }
3298 }
3299
3300 // centroid of bottom-left rectangle
3301 double xerr = 0.25 * (x0 + 0.5 * (x1 + x0) + xo + 0.5 * (x0 + x3));
3302 double yerr = 0.25 * (y0 + 0.5 * (y1 + y0) + yo + 0.5 * (y0 + y3));
3303 double zerr = 0.25 * (z0 + 0.5 * (z1 + z0) + zo + 0.5 * (z0 + z3));
3304 globalP.X = xerr;
3305 globalP.Y = yerr;
3306 globalP.Z = zerr;
3307 if (InterfaceType[prim] == 1) {
3308 PFAtPoint(&globalP, &Potential, &globalF);
3309 Err = ApplPot[prim] - Potential;
3310 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3311 prim, ele, 4, 1, xerr, yerr, zerr, ApplPot[prim], Potential,
3312 Err);
3313 if (fabs(Err) > fabs(MaxError)) {
3314 MaxError = Err;
3315 PrimitiveOfMaxError = prim;
3316 ElementOfMaxError = ele;
3317 xerrMax = xerr;
3318 yerrMax = yerr;
3319 zerrMax = zerr;
3320 }
3321 }
3322 if (InterfaceType[prim] ==
3323 4) { // compute displacement currents in the two dielectrics
3324 double xplus = xerr + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3325 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3326 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3327 double yplus = yerr + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3328 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3329 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3330 double zplus = zerr + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3331 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3332 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3333 globalP.X = xplus;
3334 globalP.Y = yplus;
3335 globalP.Z = zplus;
3336 PFAtPoint(&globalP, &Potential, &globalF);
3337 localF // Flux in the ECS
3338 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3339 global2local);
3340 double value1 = -localF.Y;
3341 double xminus = xerr - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3342 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3343 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3344 double yminus = yerr - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3345 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3346 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3347 double zminus = zerr - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3348 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3349 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3350 globalP.X = xminus;
3351 globalP.Y = yminus;
3352 globalP.Z = zminus;
3353 PFAtPoint(&globalP, &Potential, &globalF);
3354 localF // Flux in the ECS
3355 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3356 global2local);
3357 double value2 = -localF.Y;
3358 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
3359 Err = epsratio - (value1 / value2);
3360 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3361 prim, ele, 4, 4, xerr, yerr, zerr, epsratio,
3362 (value1 / value2), Err);
3363 if (fabs(Err) > fabs(MaxError)) {
3364 MaxError = Err;
3365 PrimitiveOfMaxError = prim;
3366 ElementOfMaxError = ele;
3367 xerrMax = xerr;
3368 yerrMax = yerr;
3369 zerrMax = zerr;
3370 }
3371 }
3372
3373 // centroid of bottom-right rectangle
3374 xerr = 0.25 * (0.5 * (x1 + x0) + x1 + 0.5 * (x1 + x2) + xo);
3375 yerr = 0.25 * (0.5 * (y1 + y0) + y1 + 0.5 * (y1 + y2) + yo);
3376 zerr = 0.25 * (0.5 * (z1 + z0) + z1 + 0.5 * (z1 + z2) + zo);
3377 globalP.X = xerr;
3378 globalP.Y = yerr;
3379 globalP.Z = zerr;
3380 // At present, error-accounting is maintained only for two types of
3381 // interfaces, C-D interfaces (specified voltage), D-D interfaces
3382 // (continuity of displacement current implied)
3383 if (InterfaceType[prim] == 1) {
3384 PFAtPoint(&globalP, &Potential, &globalF);
3385 Err = ApplPot[prim] - Potential;
3386 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3387 prim, ele, 4, 1, xerr, yerr, zerr, ApplPot[prim], Potential,
3388 Err);
3389 if (fabs(Err) > fabs(MaxError)) {
3390 MaxError = Err;
3391 PrimitiveOfMaxError = prim;
3392 ElementOfMaxError = ele;
3393 xerrMax = xerr;
3394 yerrMax = yerr;
3395 zerrMax = zerr;
3396 }
3397 }
3398 if (InterfaceType[prim] ==
3399 4) { // compute displacement currents in the two dielectrics
3400 double xplus = xerr + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3401 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3402 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3403 double yplus = yerr + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3404 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3405 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3406 double zplus = zerr + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3407 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3408 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3409 globalP.X = xplus;
3410 globalP.Y = yplus;
3411 globalP.Z = zplus;
3412 PFAtPoint(&globalP, &Potential, &globalF);
3413 localF // Flux in the ECS
3414 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3415 global2local);
3416 double value1 = -localF.Y;
3417 double xminus = xerr - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3418 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3419 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3420 double yminus = yerr - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3421 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3422 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3423 double zminus = zerr - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3424 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3425 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3426 globalP.X = xminus;
3427 globalP.Y = yminus;
3428 globalP.Z = zminus;
3429 PFAtPoint(&globalP, &Potential, &globalF);
3430 localF // Flux in the ECS
3431 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3432 global2local);
3433 double value2 = -localF.Y;
3434 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
3435 Err = epsratio - (value1 / value2);
3436 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3437 prim, ele, 4, 4, xerr, yerr, zerr, epsratio,
3438 (value1 / value2), Err);
3439 if (fabs(Err) > fabs(MaxError)) {
3440 MaxError = Err;
3441 PrimitiveOfMaxError = prim;
3442 ElementOfMaxError = ele;
3443 xerrMax = xerr;
3444 yerrMax = yerr;
3445 zerrMax = zerr;
3446 }
3447 }
3448
3449 // centroid of top-right rectangle
3450 xerr = 0.25 * (xo + 0.5 * (x1 + x2) + x2 + 0.5 * (x3 + x2));
3451 yerr = 0.25 * (yo + 0.5 * (y1 + y2) + y2 + 0.5 * (y3 + y2));
3452 zerr = 0.25 * (zo + 0.5 * (z1 + z2) + z2 + 0.5 * (z3 + z2));
3453 globalP.X = xerr;
3454 globalP.Y = yerr;
3455 globalP.Z = zerr;
3456 // At present, error-accounting is maintained only for two types of
3457 // interfaces, C-D interfaces (specified voltage), D-D interfaces
3458 // (continuity of displacement current implied)
3459 if (InterfaceType[prim] == 1) {
3460 PFAtPoint(&globalP, &Potential, &globalF);
3461 Err = ApplPot[prim] - Potential;
3462 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3463 prim, ele, 4, 1, xerr, yerr, zerr, ApplPot[prim], Potential,
3464 Err);
3465 if (fabs(Err) > fabs(MaxError)) {
3466 MaxError = Err;
3467 PrimitiveOfMaxError = prim;
3468 ElementOfMaxError = ele;
3469 xerrMax = xerr;
3470 yerrMax = yerr;
3471 zerrMax = zerr;
3472 }
3473 }
3474 if (InterfaceType[prim] ==
3475 4) { // compute displacement currents in the two dielectrics
3476 double xplus = xerr + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3477 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3478 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3479 double yplus = yerr + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3480 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3481 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3482 double zplus = zerr + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3483 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3484 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3485 globalP.X = xplus;
3486 globalP.Y = yplus;
3487 globalP.Z = zplus;
3488 PFAtPoint(&globalP, &Potential, &globalF);
3489 localF // Flux in the ECS
3490 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3491 global2local);
3492 double value1 = -localF.Y;
3493 double xminus = xerr - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3494 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3495 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3496 double yminus = yerr - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3497 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3498 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3499 double zminus = zerr - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3500 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3501 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3502 globalP.X = xminus;
3503 globalP.Y = yminus;
3504 globalP.Z = zminus;
3505 PFAtPoint(&globalP, &Potential, &globalF);
3506 localF // Flux in the ECS
3507 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3508 global2local);
3509 double value2 = -localF.Y;
3510 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
3511 Err = epsratio - (value1 / value2);
3512 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3513 prim, ele, 4, 4, xerr, yerr, zerr, epsratio,
3514 (value1 / value2), Err);
3515 if (fabs(Err) > fabs(MaxError)) {
3516 MaxError = Err;
3517 PrimitiveOfMaxError = prim;
3518 ElementOfMaxError = ele;
3519 xerrMax = xerr;
3520 yerrMax = yerr;
3521 zerrMax = zerr;
3522 }
3523 }
3524
3525 // centroid of top-left rectangle
3526 xerr = 0.25 * (0.5 * (x0 + x3) + xo + 0.5 * (x3 + x2) + x3);
3527 yerr = 0.25 * (0.5 * (y0 + y3) + yo + 0.5 * (y3 + y2) + y3);
3528 zerr = 0.25 * (0.5 * (z0 + z3) + zo + 0.5 * (z3 + z2) + z3);
3529 globalP.X = xerr;
3530 globalP.Y = yerr;
3531 globalP.Z = zerr;
3532 // At present, error-accounting is maintained only for two types of
3533 // interfaces, C-D interfaces (specified voltage), D-D interfaces
3534 // (continuity of displacement current implied)
3535 if (InterfaceType[prim] == 1) {
3536 PFAtPoint(&globalP, &Potential, &globalF);
3537 Err = ApplPot[prim] - Potential;
3538 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3539 prim, ele, 4, 1, xerr, yerr, zerr, ApplPot[prim], Potential,
3540 Err);
3541 if (fabs(Err) > fabs(MaxError)) {
3542 MaxError = Err;
3543 PrimitiveOfMaxError = prim;
3544 ElementOfMaxError = ele;
3545 xerrMax = xerr;
3546 yerrMax = yerr;
3547 zerrMax = zerr;
3548 }
3549 }
3550 if (InterfaceType[prim] ==
3551 4) { // compute displacement currents in the two dielectrics
3552 double xplus = xerr + (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3553 xplus += (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3554 xplus += (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3555 double yplus = yerr + (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3556 yplus += (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3557 yplus += (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3558 double zplus = zerr + (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3559 zplus += (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3560 zplus += (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3561 globalP.X = xplus;
3562 globalP.Y = yplus;
3563 globalP.Z = zplus;
3564 PFAtPoint(&globalP, &Potential, &globalF);
3565 localF // Flux in the ECS
3566 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3567 global2local);
3568 double value1 = -localF.Y;
3569 double xminus = xerr - (EleArr + ele - 1)->G.DC.XUnit.X * normdisp;
3570 xminus -= (EleArr + ele - 1)->G.DC.YUnit.X * normdisp;
3571 xminus -= (EleArr + ele - 1)->G.DC.ZUnit.X * normdisp;
3572 double yminus = yerr - (EleArr + ele - 1)->G.DC.XUnit.Y * normdisp;
3573 yminus -= (EleArr + ele - 1)->G.DC.YUnit.Y * normdisp;
3574 yminus -= (EleArr + ele - 1)->G.DC.ZUnit.Y * normdisp;
3575 double zminus = zerr - (EleArr + ele - 1)->G.DC.XUnit.Z * normdisp;
3576 zminus -= (EleArr + ele - 1)->G.DC.YUnit.Z * normdisp;
3577 zminus -= (EleArr + ele - 1)->G.DC.ZUnit.Z * normdisp;
3578 globalP.X = xminus;
3579 globalP.Y = yminus;
3580 globalP.Z = zminus;
3581 PFAtPoint(&globalP, &Potential, &globalF);
3582 localF // Flux in the ECS
3583 = RotateVector3D(&globalF, &(EleArr + ele - 1)->G.DC,
3584 global2local);
3585 double value2 = -localF.Y;
3586 double epsratio = (Epsilon2[prim] / Epsilon1[prim]);
3587 Err = epsratio - (value1 / value2);
3588 fprintf(fErr, "%d\t%d\t%d\t%d\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
3589 prim, ele, 4, 4, xerr, yerr, zerr, epsratio,
3590 (value1 / value2), Err);
3591 if (fabs(Err) > fabs(MaxError)) {
3592 MaxError = Err;
3593 PrimitiveOfMaxError = prim;
3594 ElementOfMaxError = ele;
3595 xerrMax = xerr;
3596 yerrMax = yerr;
3597 zerrMax = zerr;
3598 }
3599 }
3600 } // if rectangle
3601
3602 if (DebugLevel == 1001) exit(1);
3603 } // loop over primitives and elements
3604
3605 fprintf(fErr,
3606 "#Error maximum on element %d on primitive %d with x,y,z %lg, "
3607 "%lg, %lg and its magnitude is %lg.\n",
3608 ElementOfMaxError, PrimitiveOfMaxError, xerrMax, yerrMax, zerrMax,
3609 MaxError);
3610 fclose(fErr);
3611 } // if(OptEstimateError)
3612
3613 return (0);
3614} // Solve ends here
3615
3616// In case we are PostProcessing only the solution needs to be read in
3617// from an existing Solution file present in the BCOutDir
3618int ReadSolution(void) {
3619 char SolnFile[256];
3620 strcpy(SolnFile, BCOutDir);
3621 strcat(SolnFile, "/Soln.out");
3622 FILE *fSoln = fopen(SolnFile, "r");
3623 // assert(fSoln != NULL);
3624 if (fSoln == NULL) {
3625 neBEMMessage("ReadSoln - unable to open solution file.");
3626 return -1;
3627 }
3628
3629 int itmp;
3630 double dtmp, sol;
3631 char instr[256];
3632 fgets(instr, 256, fSoln);
3633 for (int ele = 1; ele <= NbElements; ++ele) {
3634 fscanf(fSoln, "%d %lg %lg %lg %lg\n", &itmp, &dtmp, &dtmp, &dtmp, &sol);
3635 // assert(ele == itmp);
3636 if (ele != itmp) {
3637 neBEMMessage("ReadSolution - ele_itmp in ReadSolution");
3638 return -1;
3639 }
3640 (EleArr + ele - 1)->Solution = sol;
3641 }
3642 printf("\nReadSolution: Solution read in for all elements ...\n");
3643 fflush(stdout);
3644
3645 if (NbConstraints) {
3646 if (OptSystemChargeZero) {
3647 fgets(instr, 256, fSoln);
3648 fscanf(fSoln, "%d %lg\n", &NbSystemChargeZero, &VSystemChargeZero);
3649 printf(
3650 "ReadSolution: Read in voltage shift to ensure system charge "
3651 "zero.\n");
3652 }
3654 fgets(instr, 256, fSoln);
3655 fscanf(fSoln, "%d %lg\n", &NbFloatCon, &VFloatCon);
3656 printf("ReadSolution: Read in voltage on floating conductor.\n");
3657 }
3658 fflush(stdout);
3659 } // if NbConstraints
3660
3661 fclose(fSoln);
3662
3663 // Find primitive related charge densities
3664 // OMPCheck - may be parallelized
3665 for (int prim = 1; prim <= NbPrimitives; ++prim) {
3666 double area = 0.0; // need area of the primitive as well!
3667 AvChDen[prim] = 0.0;
3668 AvAsgndChDen[prim] = 0.0;
3669
3670 for (int ele = ElementBgn[prim]; ele <= ElementEnd[prim]; ++ele) {
3671 const double dA = (EleArr + ele - 1)->G.dA;
3672 area += dA;
3673 AvChDen[prim] += (EleArr + ele - 1)->Solution * dA;
3674 AvAsgndChDen[prim] += (EleArr + ele - 1)->Assigned * dA;
3675 }
3676
3677 AvChDen[prim] /= area;
3678 AvAsgndChDen[prim] /= area;
3679 }
3680
3681 neBEMState = 9;
3682
3683 return (0);
3684} // end of neBEMReadSolution
3685
3686// Error estimate is easy here - check that the integration yields unity!
3687// TryWtField is a script that elucidates the idea.
3688int WeightingFieldSolution(int NbPrimsWtField, int PrimListWtField[],
3689 double solnarray[]) {
3690 // Check for the inverted matrix
3691 if (!InvMat) {
3692 printf(
3693 "WeightingFieldSolution: Capacitance matrix not in memory, can not "
3694 "calculate weighting charges.\n");
3695 return (-1);
3696 }
3697
3698 for (int i = 1; i <= NbUnknowns; i++) solnarray[i] = 0.0;
3699
3700 for (int ele = 1, InList; ele <= NbElements; ++ele) {
3701 int prim = (EleArr + ele - 1)->PrimitiveNb;
3702
3703 InList = 0; // assume that this prim is not in the list
3704 for (int primwtfl = 0; primwtfl < NbPrimsWtField; ++primwtfl) {
3705 if (prim == PrimListWtField[primwtfl]) {
3706 InList = 1;
3707 break; // get out of the for loop
3708 }
3709 } // for primwtfl
3710
3711 if (InList) {
3712 for (int i = 1; i <= NbUnknowns; ++i) {
3713 solnarray[i] += InvMat[i][ele];
3714 }
3715 }
3716 } // for ele
3717
3718 return (0);
3719} // WtFieldSolution ends
3720
3721// Create a function for Reflect to get the effect of given mirrors - this
3722// function should provide the localP. Rest can be done within the calling
3723// routines.
3724// Inputs for the function: Ele array, count ele, MirrorTypes, MirrorDists,
3725// xfld, yfld, zfld, xsrc, ysrc, zsrc, primsrc (if necessary)
3726// Rest can be computed within the function: p1, n, Image, dist, MirroredDC,
3727// globalP
3728// Output from the function: localP (distance from the reflected point to
3729// the field point where the influence is being evaluated)
3730//
3731// Shift the reflected point to take care of mirrors not at origin
3732// The equation to such a plane is (n.X)*x + (n.Y)*y + (n.Z)*z = d
3733// where d is the perpendicular distance from the origin
3734// So, we refine mirror definition using this additional information
3735// which, according to Garfield, has to be deduced from the device geom
3736// In neBEM, this distance has been deduced in neBEMInterface.
3737
3738// the `handed-ness' of the element can get altered whenever elments
3739// are not perpendicular to the mirror
3740// Signs for the `X' componets need to be changed.
3741
3742Point3D ReflectPrimitiveOnMirror(char Axis, int primsrc, Point3D srcpt,
3743 Point3D fldpt, double distance,
3744 DirnCosn3D *MirroredDC) {
3745 Vector3D n; // define mirror by a bi-vector perpendicular to it
3746 Point3D Image; // reflected point by mirror assumed at origin
3747
3748 switch (Axis) {
3749 case 'x':
3750 case 'X':
3751 n.X = 1.0;
3752 n.Y = 0.0;
3753 n.Z = 0.0;
3754
3755 Image = ReflectPoint3DByMirrorAtOrigin(&srcpt, &n);
3756 Image.X += 2.0 * distance;
3757
3758 MirroredDC->XUnit.X = -PrimDC[primsrc].XUnit.X;
3759 MirroredDC->XUnit.Y = PrimDC[primsrc].XUnit.Y;
3760 MirroredDC->XUnit.Z = PrimDC[primsrc].XUnit.Z;
3761 MirroredDC->YUnit.X = -PrimDC[primsrc].YUnit.X;
3762 MirroredDC->YUnit.Y = PrimDC[primsrc].YUnit.Y;
3763 MirroredDC->YUnit.Z = PrimDC[primsrc].YUnit.Z;
3764 MirroredDC->ZUnit.X = -PrimDC[primsrc].ZUnit.X;
3765 MirroredDC->ZUnit.Y = PrimDC[primsrc].ZUnit.Y;
3766 MirroredDC->ZUnit.Z = PrimDC[primsrc].ZUnit.Z;
3767 break;
3768
3769 case 'y':
3770 case 'Y':
3771 n.X = 0.0;
3772 n.Y = 1.0;
3773 n.Z = 0.0;
3774
3775 Image = ReflectPoint3DByMirrorAtOrigin(&srcpt, &n);
3776 Image.Y += 2.0 * distance;
3777
3778 MirroredDC->XUnit.X = PrimDC[primsrc].XUnit.X;
3779 MirroredDC->XUnit.Y = -PrimDC[primsrc].XUnit.Y;
3780 MirroredDC->XUnit.Z = PrimDC[primsrc].XUnit.Z;
3781 MirroredDC->YUnit.X = PrimDC[primsrc].YUnit.X;
3782 MirroredDC->YUnit.Y = -PrimDC[primsrc].YUnit.Y;
3783 MirroredDC->YUnit.Z = PrimDC[primsrc].YUnit.Z;
3784 MirroredDC->ZUnit.X = PrimDC[primsrc].ZUnit.X;
3785 MirroredDC->ZUnit.Y = -PrimDC[primsrc].ZUnit.Y;
3786 MirroredDC->ZUnit.Z = PrimDC[primsrc].ZUnit.Z;
3787 break;
3788
3789 case 'z':
3790 case 'Z':
3791 n.X = 0.0;
3792 n.Y = 0.0;
3793 n.Z = 1.0;
3794
3795 Image = ReflectPoint3DByMirrorAtOrigin(&srcpt, &n);
3796 Image.Z += 2.0 * distance;
3797
3798 MirroredDC->XUnit.X = PrimDC[primsrc].XUnit.X;
3799 MirroredDC->XUnit.Y = PrimDC[primsrc].XUnit.Y;
3800 MirroredDC->XUnit.Z = -PrimDC[primsrc].XUnit.Z;
3801 MirroredDC->YUnit.X = PrimDC[primsrc].YUnit.X;
3802 MirroredDC->YUnit.Y = PrimDC[primsrc].YUnit.Y;
3803 MirroredDC->YUnit.Z = -PrimDC[primsrc].YUnit.Z;
3804 MirroredDC->ZUnit.X = PrimDC[primsrc].ZUnit.X;
3805 MirroredDC->ZUnit.Y = PrimDC[primsrc].ZUnit.Y;
3806 MirroredDC->ZUnit.Z = -PrimDC[primsrc].ZUnit.Z;
3807 break;
3808
3809 default:
3810 printf("Axis not chosen properly!!! No reflection occurred!\n");
3811 Image.X = srcpt.X;
3812 Image.Y = srcpt.Y;
3813 Image.Z = srcpt.Z;
3814 } // switch on Axis ends
3815
3816 // printf("Axis: %c, distance: %lg\n", Axis, distance);
3817 // printf("srcpt: %lg, %lg, %lg\n", srcpt.X, srcpt.Y, srcpt.Z);
3818 // printf("Image: %lg, %lg, %lg\n", Image.X, Image.Y, Image.Z);
3819 // getchar();
3820
3821 // traslated to ECS origin, but axes direction as in global system
3822 Point3D globalP, localP;
3823 globalP.X = fldpt.X - Image.X;
3824 globalP.Y = fldpt.Y - Image.Y;
3825 globalP.Z = fldpt.Z - Image.Z;
3826
3827 // entirely in ECS
3828 return (localP = RotatePoint3D(&globalP, MirroredDC, global2local));
3829} // ReflectPrimtiveOnMirror ends here
3830
3831Point3D ReflectOnMirror(char Axis, int elesrc, Point3D srcpt, Point3D fldpt,
3832 double distance, DirnCosn3D *MirroredDC) {
3833 Vector3D n; // define mirror by a bi-vector perpendicular to it
3834 Point3D Image; // reflected point by mirror assumed at origin
3835
3836 switch (Axis) {
3837 case 'x':
3838 case 'X':
3839 n.X = 1.0;
3840 n.Y = 0.0;
3841 n.Z = 0.0;
3842
3843 Image = ReflectPoint3DByMirrorAtOrigin(&srcpt, &n);
3844 Image.X += 2.0 * distance;
3845
3846 MirroredDC->XUnit.X = -(EleArr + elesrc - 1)->G.DC.XUnit.X;
3847 MirroredDC->XUnit.Y = (EleArr + elesrc - 1)->G.DC.XUnit.Y;
3848 MirroredDC->XUnit.Z = (EleArr + elesrc - 1)->G.DC.XUnit.Z;
3849 MirroredDC->YUnit.X = -(EleArr + elesrc - 1)->G.DC.YUnit.X;
3850 MirroredDC->YUnit.Y = (EleArr + elesrc - 1)->G.DC.YUnit.Y;
3851 MirroredDC->YUnit.Z = (EleArr + elesrc - 1)->G.DC.YUnit.Z;
3852 MirroredDC->ZUnit.X = -(EleArr + elesrc - 1)->G.DC.ZUnit.X;
3853 MirroredDC->ZUnit.Y = (EleArr + elesrc - 1)->G.DC.ZUnit.Y;
3854 MirroredDC->ZUnit.Z = (EleArr + elesrc - 1)->G.DC.ZUnit.Z;
3855 break;
3856
3857 case 'y':
3858 case 'Y':
3859 n.X = 0.0;
3860 n.Y = 1.0;
3861 n.Z = 0.0;
3862
3863 Image = ReflectPoint3DByMirrorAtOrigin(&srcpt, &n);
3864 Image.Y += 2.0 * distance;
3865
3866 MirroredDC->XUnit.X = (EleArr + elesrc - 1)->G.DC.XUnit.X;
3867 MirroredDC->XUnit.Y = -(EleArr + elesrc - 1)->G.DC.XUnit.Y;
3868 MirroredDC->XUnit.Z = (EleArr + elesrc - 1)->G.DC.XUnit.Z;
3869 MirroredDC->YUnit.X = (EleArr + elesrc - 1)->G.DC.YUnit.X;
3870 MirroredDC->YUnit.Y = -(EleArr + elesrc - 1)->G.DC.YUnit.Y;
3871 MirroredDC->YUnit.Z = (EleArr + elesrc - 1)->G.DC.YUnit.Z;
3872 MirroredDC->ZUnit.X = (EleArr + elesrc - 1)->G.DC.ZUnit.X;
3873 MirroredDC->ZUnit.Y = -(EleArr + elesrc - 1)->G.DC.ZUnit.Y;
3874 MirroredDC->ZUnit.Z = (EleArr + elesrc - 1)->G.DC.ZUnit.Z;
3875 break;
3876
3877 case 'z':
3878 case 'Z':
3879 n.X = 0.0;
3880 n.Y = 0.0;
3881 n.Z = 1.0;
3882
3883 Image = ReflectPoint3DByMirrorAtOrigin(&srcpt, &n);
3884 Image.Z += 2.0 * distance;
3885
3886 MirroredDC->XUnit.X = (EleArr + elesrc - 1)->G.DC.XUnit.X;
3887 MirroredDC->XUnit.Y = (EleArr + elesrc - 1)->G.DC.XUnit.Y;
3888 MirroredDC->XUnit.Z = -(EleArr + elesrc - 1)->G.DC.XUnit.Z;
3889 MirroredDC->YUnit.X = (EleArr + elesrc - 1)->G.DC.YUnit.X;
3890 MirroredDC->YUnit.Y = (EleArr + elesrc - 1)->G.DC.YUnit.Y;
3891 MirroredDC->YUnit.Z = -(EleArr + elesrc - 1)->G.DC.YUnit.Z;
3892 MirroredDC->ZUnit.X = (EleArr + elesrc - 1)->G.DC.ZUnit.X;
3893 MirroredDC->ZUnit.Y = (EleArr + elesrc - 1)->G.DC.ZUnit.Y;
3894 MirroredDC->ZUnit.Z = -(EleArr + elesrc - 1)->G.DC.ZUnit.Z;
3895 break;
3896
3897 default:
3898 printf("Axis not chosen properly!!! No reflection occurred!\n");
3899 Image.X = srcpt.X;
3900 Image.Y = srcpt.Y;
3901 Image.Z = srcpt.Z;
3902 } // switch on Axis ends
3903
3904 // printf("Axis: %c, distance: %lg\n", Axis, distance);
3905 // printf("srcpt: %lg, %lg, %lg\n", srcpt.X, srcpt.Y, srcpt.Z);
3906 // printf("Image: %lg, %lg, %lg\n", Image.X, Image.Y, Image.Z);
3907 // getchar();
3908
3909 // traslated to ECS origin, but axes direction as in global system
3910 Point3D globalP, localP;
3911 globalP.X = fldpt.X - Image.X;
3912 globalP.Y = fldpt.Y - Image.Y;
3913 globalP.Z = fldpt.Z - Image.Z;
3914
3915 // entirely in ECS
3916 return (localP = RotatePoint3D(&globalP, MirroredDC, global2local));
3917} // ReflectOnMirror ends
3918
3919#ifdef __cplusplus
3920} // namespace
3921#endif
double TriPot(int ele, Point3D *localP)
double WirePot(int ele, Point3D *localP)
void TriFlux(int ele, Point3D *localP, Vector3D *localF)
void RecFlux(int ele, Point3D *localP, Vector3D *localF)
double RecPot(int ele, Point3D *localP)
void WireFlux(int ele, Point3D *localP, Vector3D *localF)
int PFAtPoint(Point3D *globalP, double *Potential, Vector3D *globalF)
double LineKnChPF(Point3D LineStart, Point3D LineStop, double radius, Point3D FieldPt, Vector3D *globalF)
Definition: Isles.c:2199
double AreaKnChPF(int NbVertices, Point3D *Vertex, Point3D FieldPt, Vector3D *globalF)
Definition: Isles.c:2350
double PointKnChPF(Point3D SourcePt, Point3D FieldPt, Vector3D *globalF)
Definition: Isles.c:2177
double VolumeKnChPF(int, Point3D *, Point3D, Vector3D *globalF)
Definition: Isles.c:2491
ISLESGLOBAL int DebugISLES
Definition: Isles.h:35
#define MINDIST
Definition: Isles.h:17
NRGLOBAL void svdcmp(double **a, int matrow, int matcol, double *w, double **v)
Definition: svdcmp.c:27
Point3D ReflectPoint3DByMirrorAtOrigin(Point3D *p1, Vector3D *n)
Definition: Vector.c:467
Point3D RotatePoint3D(Point3D *A, DirnCosn3D *DC, int Sense)
Definition: Vector.c:339
Vector3D RotateVector3D(Vector3D *A, DirnCosn3D *DC, int Sense)
Definition: Vector.c:397
#define global2local
Definition: Vector.h:13
#define local2global
Definition: Vector.h:14
void lubksb(double **a, int n, int *index, double *b)
Definition: luc.c:90
void ludcmp(double **a, int n, int *index, double *d)
Definition: luc.c:12
int neBEMMessage(const char *message)
double neBEMTimeElapsed(clock_t t0, clock_t t1)
int neBEMChargingUp(int)
int neBEMKnownCharges(void)
INTFACEGLOBAL clock_t stopClock
INTFACEGLOBAL int neBEMState
INTFACEGLOBAL clock_t startClock
int InfluenceMatrixFlag
Definition: neBEM.c:30
int RHVector(void)
Definition: neBEM.c:1903
int LHMatrix(void)
Definition: neBEM.c:304
int Solve(void)
Definition: neBEM.c:2441
int ComputeSolution(void)
Definition: neBEM.c:36
int DecomposeMatrixSVD(double **SVDInf, double *SVDw, double **SVDv)
Definition: neBEM.c:1454
double ComputeInfluence(int elefld, int elesrc, Point3D *localP, DirnCosn3D *DirCos)
Definition: neBEM.c:1579
int ReadInvertedMatrix(void)
Definition: neBEM.c:1504
int InvertMatrix(void)
Definition: neBEM.c:1236
double ValueKnCh(int elefld)
Definition: neBEM.c:2035
double EffectChUp(int elefld)
Definition: neBEM.c:2364
double ContinuityKnCh(int elefld)
Definition: neBEM.c:2182
Point3D ReflectPrimitiveOnMirror(char Axis, int primsrc, Point3D srcpt, Point3D fldpt, double distance, DirnCosn3D *MirroredDC)
Definition: neBEM.c:3742
int WeightingFieldSolution(int NbPrimsWtField, int PrimListWtField[], double solnarray[])
Definition: neBEM.c:3688
double ValueChUp(int elefld)
Definition: neBEM.c:2367
double SatisfyContinuity(int elefld, int elesrc, Point3D *localP, DirnCosn3D *DirCos)
Definition: neBEM.c:1724
Point3D ReflectOnMirror(char Axis, int elesrc, Point3D srcpt, Point3D fldpt, double distance, DirnCosn3D *MirroredDC)
Definition: neBEM.c:3831
int ReadSolution(void)
Definition: neBEM.c:3618
double SatisfyValue(int elesrc, Point3D *localP)
Definition: neBEM.c:1686
double EffectKnCh(int elefld)
Definition: neBEM.c:2028
neBEMGLOBAL double ** InvMat
Definition: neBEM.h:237
neBEMGLOBAL Element * EleArr
Definition: neBEM.h:169
neBEMGLOBAL double * ApplPot
Definition: neBEM.h:75
neBEMGLOBAL int DebugLevel
Definition: neBEM.h:235
neBEMGLOBAL int NbFloatCon
Definition: neBEM.h:126
neBEMGLOBAL int * PeriodicInY
Definition: neBEM.h:79
neBEMGLOBAL double VFloatCon
Definition: neBEM.h:128
neBEMGLOBAL int MeshCntr
Definition: neBEM.h:224
neBEMGLOBAL int PPCntr
Definition: neBEM.h:224
neBEMGLOBAL int OptSVD
Definition: neBEM.h:236
neBEMGLOBAL int OptInvMatProc
Definition: neBEM.h:41
neBEMGLOBAL int OptRepeatLHMatrix
Definition: neBEM.h:51
neBEMGLOBAL char MeshOutDir[256]
Definition: neBEM.h:263
neBEMGLOBAL int * MirrorTypeZ
Definition: neBEM.h:81
neBEMGLOBAL double * RHS
Definition: neBEM.h:237
neBEMGLOBAL double * MirrorDistYFromOrigin
Definition: neBEM.h:82
#define EPS0
Definition: neBEM.h:20
neBEMGLOBAL int OptLU
Definition: neBEM.h:236
neBEMGLOBAL double * ZPeriod
Definition: neBEM.h:80
neBEMGLOBAL int NewModel
Definition: neBEM.h:220
neBEMGLOBAL PointKnCh * PointKnChArr
Definition: neBEM.h:181
neBEMGLOBAL VolumeKnCh * VolumeKnChArr
Definition: neBEM.h:216
neBEMGLOBAL int OptFormattedFile
Definition: neBEM.h:49
neBEMGLOBAL int OptChargingUp
Definition: neBEM.h:53
neBEMGLOBAL double VSystemChargeZero
Definition: neBEM.h:122
neBEMGLOBAL int EndOfTime
Definition: neBEM.h:241
neBEMGLOBAL int NewMesh
Definition: neBEM.h:220
neBEMGLOBAL double * PrimOriginZ
Definition: neBEM.h:73
neBEMGLOBAL int NbPrimitives
Definition: neBEM.h:57
neBEMGLOBAL int * PeriodicTypeX
Definition: neBEM.h:78
neBEMGLOBAL int NbElements
Definition: neBEM.h:113
neBEMGLOBAL int OptEstimateError
Definition: neBEM.h:44
neBEMGLOBAL int * PeriodicTypeY
Definition: neBEM.h:78
neBEMGLOBAL int NbPointsKnCh
Definition: neBEM.h:172
neBEMGLOBAL double * Epsilon1
Definition: neBEM.h:75
neBEMGLOBAL double * PrimOriginY
Definition: neBEM.h:73
neBEMGLOBAL double * MirrorDistZFromOrigin
Definition: neBEM.h:83
neBEMGLOBAL AreaKnCh * AreaKnChArr
Definition: neBEM.h:204
neBEMGLOBAL DirnCosn3D * PrimDC
Definition: neBEM.h:74
neBEMGLOBAL int OptSystemChargeZero
Definition: neBEM.h:118
neBEMGLOBAL int NbEqns
Definition: neBEM.h:234
neBEMGLOBAL int NbLinesKnCh
Definition: neBEM.h:172
neBEMGLOBAL int NbFloatingConductors
Definition: neBEM.h:124
neBEMGLOBAL int NbConstraints
Definition: neBEM.h:233
neBEMGLOBAL double * XPeriod
Definition: neBEM.h:80
neBEMGLOBAL int NbVolumesKnCh
Definition: neBEM.h:172
neBEMGLOBAL double * AvAsgndChDen
Definition: neBEM.h:90
neBEMGLOBAL int NewPP
Definition: neBEM.h:220
neBEMGLOBAL int * MirrorTypeY
Definition: neBEM.h:81
neBEMGLOBAL int NbAreasKnCh
Definition: neBEM.h:172
neBEMGLOBAL int * ElementEnd
Definition: neBEM.h:94
neBEMGLOBAL double * AvChDen
Definition: neBEM.h:90
neBEMGLOBAL int * MirrorTypeX
Definition: neBEM.h:81
neBEMGLOBAL int * InterfaceType
Definition: neBEM.h:68
neBEMGLOBAL int BCCntr
Definition: neBEM.h:224
neBEMGLOBAL int TimeStep
Definition: neBEM.h:241
neBEMGLOBAL double * Solution
Definition: neBEM.h:237
neBEMGLOBAL int * ElementBgn
Definition: neBEM.h:94
neBEMGLOBAL double * PrimOriginX
Definition: neBEM.h:73
neBEMGLOBAL int OptStoreInflMatrix
Definition: neBEM.h:47
neBEMGLOBAL int OptGSL
Definition: neBEM.h:236
neBEMGLOBAL int * PeriodicInZ
Definition: neBEM.h:79
neBEMGLOBAL int * PeriodicInX
Definition: neBEM.h:79
neBEMGLOBAL int OptForceValidation
Definition: neBEM.h:43
neBEMGLOBAL double ** Inf
Definition: neBEM.h:237
neBEMGLOBAL int OptUnformattedFile
Definition: neBEM.h:50
neBEMGLOBAL int NbUnknowns
Definition: neBEM.h:234
neBEMGLOBAL int ModelCntr
Definition: neBEM.h:224
neBEMGLOBAL int * PeriodicTypeZ
Definition: neBEM.h:78
neBEMGLOBAL LineKnCh * LineKnChArr
Definition: neBEM.h:192
neBEMGLOBAL int OptValidateSolution
Definition: neBEM.h:42
neBEMGLOBAL int OptKnCh
Definition: neBEM.h:52
neBEMGLOBAL int OptStoreInvMatrix
Definition: neBEM.h:48
#define MyFACTOR
Definition: neBEM.h:21
neBEMGLOBAL char BCOutDir[256]
Definition: neBEM.h:263
neBEMGLOBAL double * YPeriod
Definition: neBEM.h:80
neBEMGLOBAL double * MirrorDistXFromOrigin
Definition: neBEM.h:82
neBEMGLOBAL int NbSystemChargeZero
Definition: neBEM.h:120
neBEMGLOBAL double * Epsilon2
Definition: neBEM.h:75
neBEMGLOBAL int NewBC
Definition: neBEM.h:220
void free_dmatrix(double **m, long nrl, long, long ncl, long)
Definition: nrutil.c:481
void free_dvector(double *v, long nl, long)
Definition: nrutil.c:470
int * ivector(long nl, long nh)
Definition: nrutil.c:32
double ** dmatrix(long nrl, long nrh, long ncl, long nch)
Definition: nrutil.c:97
void free_ivector(int *v, long nl, long)
Definition: nrutil.c:455
double * dvector(long nl, long nh)
Definition: nrutil.c:63
Vector3D ZUnit
Definition: Vector.h:38
Vector3D YUnit
Definition: Vector.h:37
Vector3D XUnit
Definition: Vector.h:36
Definition: Vector.h:21
double X
Definition: Vector.h:22
double Z
Definition: Vector.h:24
double Y
Definition: Vector.h:23
double Z
Definition: Vector.h:31
double Y
Definition: Vector.h:30
double X
Definition: Vector.h:29