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