16 nCollocationPoints(3),
19 randomCollocation(false),
24 matrixInversionFlag(false) {
28 influenceMatrix.clear();
29 inverseMatrix.clear();
33 const double z,
double& ex,
double& ey,
34 double& ez,
double& v,
Medium*& m,
37 ex = ey = ez = v = 0.;
49 std::cerr <<
" Initialisation failed.\n";
56 double dx = 0., dy = 0.;
61 for (
int i = nElements; i--;) {
62 dx = x - elements[i].cX;
63 dy = y - elements[i].cY;
65 Rotate(dx, dy, elements[i].phi, Global2Local, xLoc, yLoc);
67 if (!ComputePotential(elements[i].geoType, elements[i].len, xLoc, yLoc,
70 std::cerr <<
" Potential contribution from element " << i
71 <<
" could not be calculated.\n";
76 if (!ComputeFlux(elements[i].geoType, elements[i].len, elements[i].phi,
77 xLoc, yLoc, fx, fy)) {
79 std::cerr <<
" Field contribution from element " << i
80 <<
" could not be calculated.\n";
84 v += u * elements[i].solution;
85 ex += fx * elements[i].solution;
86 ey += fy * elements[i].solution;
91 const double z,
double& ex,
double& ey,
92 double& ez,
Medium*& m,
int& status) {
100 if (nPanels <= 0 && nWires <= 0)
return false;
101 bool gotValue =
false;
103 for (
int i = nPanels; i--;) {
104 if (panels[i].bcType != 0)
continue;
106 vmin = vmax = panels[i].bcValue;
109 if (panels[i].bcValue < vmin) vmin = panels[i].bcValue;
110 if (panels[i].bcValue > vmax) vmax = panels[i].bcValue;
114 for (
int i = nWires; i--;) {
116 vmin = vmax = wires[i].bcValue;
119 if (wires[i].bcValue < vmin) vmin = wires[i].bcValue;
120 if (wires[i].bcValue > vmax) vmax = wires[i].bcValue;
128 const double x1,
const double y1,
129 const int bctype,
const double bcval,
130 const double lambda) {
132 const double dx = x1 - x0;
133 const double dy = y1 - y0;
134 if (dx * dx + dy * dy <= Small) {
136 std::cerr <<
" Panel length must be greater than zero.\n";
145 if (bctype < 0 || bctype > 3) {
147 std::cerr <<
" Unknown boundary condition type: " << bctype <<
"\n";
150 newPanel.bcType = bctype;
151 newPanel.bcValue = bcval;
152 newPanel.lambda = lambda;
153 panels.push_back(newPanel);
158 std::cout <<
" From: (" << x0 <<
", " << y0 <<
")\n";
159 std::cout <<
" To: (" << x1 <<
", " << y1 <<
")\n";
162 std::cout <<
" Type: Conductor\n";
163 std::cout <<
" Potential: " << bcval <<
" V\n";
166 std::cout <<
" Floating conductor\n";
169 std::cout <<
" Dielectric-dielectric interface\n";
170 std::cout <<
" Lambda: " << lambda <<
"\n";
173 std::cout <<
" Surface charge\n";
176 std::cout <<
" Unknown boundary condition (program bug!)\n";
181 matrixInversionFlag =
false;
185 const double bcval) {
189 std::cerr <<
" Wire diameter must be greater than zero.\n";
197 newWire.bcValue = bcval;
198 wires.push_back(newWire);
203 std::cout <<
" Center: (" << x0 <<
", " << y0 <<
")\n";
204 std::cout <<
" Diameter: " << d <<
" cm\n";
205 std::cout <<
" Potential: " << bcval <<
" V\n";
209 matrixInversionFlag =
false;
215 std::cerr <<
m_className <<
"::SetNumberOfDivisions:\n";
216 std::cerr <<
" Number of divisions must be greater than zero.\n";
222 matrixInversionFlag =
false;
228 std::cerr <<
m_className <<
"::SetNumberOfCollocationPoints:\n";
229 std::cerr <<
" Number of coll. points must be greater than zero.\n";
233 nCollocationPoints = ncoll;
235 matrixInversionFlag =
false;
241 std::cerr <<
m_className <<
"::SetMinimumElementSize:\n";
242 std::cerr <<
" Provided element size is too small.\n";
248 matrixInversionFlag =
false;
254 std::cerr <<
m_className <<
"::SetMaxNumberOfIterations:\n";
255 std::cerr <<
" Number of iterations must be greater than zero.\n";
259 nMaxIterations = niter;
262bool ComponentNeBem2d::Initialise() {
267 std::cerr <<
" Discretisation failed.\n";
272 std::cout <<
" Discretisation ok.\n";
275 bool converged =
false;
281 std::cout <<
" Iteration " << nIter <<
"\n";
284 if (!ComputeInfluenceMatrix()) {
286 std::cerr <<
" Error computing the influence matrix.\n";
291 if (!InvertMatrix()) {
293 std::cerr <<
" Error inverting the influence matrix.\n";
299 std::cout <<
" Matrix inversion ok.\n";
303 if (!GetBoundaryConditions()) {
305 std::cerr <<
" Error computing the potential vector.\n";
312 std::cerr <<
" Error in Solve function.\n";
317 std::cout <<
" Solution ok.\n";
320 converged = CheckConvergence();
321 if (!autoSize)
break;
322 if (nIter >= nMaxIterations)
break;
328bool ComponentNeBem2d::Discretise() {
336 std::cout <<
" Panel BC Type Bc Value Rotation Length\n";
338 newElement.geoType = 0;
339 double dx = 0., dy = 0.;
340 for (
int j = nPanels; j--;) {
341 newElement.bcType = panels[j].bcType;
342 newElement.bcValue = panels[j].bcValue;
343 newElement.lambda = panels[j].lambda;
344 dx = panels[j].x1 - panels[j].x0;
345 dy = panels[j].y1 - panels[j].y0;
346 newElement.phi = atan2(dy, dx);
347 newElement.len = 0.5 *
sqrt(dx * dx + dy * dy) / nDivisions;
350 newElement.cX = panels[j].x0 - 0.5 * dx;
351 newElement.cY = panels[j].y0 - 0.5 * dy;
352 for (
int i = 0; i < nDivisions; ++i) {
355 elements.push_back(newElement);
358 std::cout <<
" " << j <<
" " << newElement.bcType <<
" "
359 << newElement.bcValue <<
" " << newElement.phi <<
" "
360 << newElement.len <<
"\n";
365 newElement.geoType = 1;
368 newElement.bcType = 0;
369 newElement.lambda = 1.;
370 for (
int j = nWires; j--;) {
371 newElement.cX = wires[j].cX;
372 newElement.cY = wires[j].cY;
373 newElement.len = wires[j].d / 2.;
374 newElement.bcValue = wires[j].bcValue;
375 elements.push_back(newElement);
382bool ComponentNeBem2d::ComputeInfluenceMatrix() {
384 if (matrixInversionFlag)
return true;
388 double xS, yS, phiS, lenS;
405 int nEntries = nElements + 1;
406 influenceMatrix.resize(nEntries);
407 for (
int i = nEntries; i--;) influenceMatrix[i].resize(nEntries);
410 for (
int iF = 0; iF < nElements; ++iF) {
411 phiF = elements[iF].phi;
413 etF = elements[iF].bcType;
415 xF = elements[iF].cX;
416 yF = elements[iF].cY;
419 for (
int jS = 0; jS < nElements; ++jS) {
420 gtS = elements[jS].geoType;
421 xS = elements[jS].cX;
422 yS = elements[jS].cY;
423 phiS = elements[jS].phi;
424 lenS = elements[jS].len;
428 Rotate(dx, dy, phiS, Global2Local, du, dv);
435 if (!ComputePotential(gtS, lenS, du, dv, infCoeff)) {
441 if (!ComputePotential(gtS, lenS, du, dv, infCoeff)) {
450 infCoeff = 1. / (2. * elements[jS].lambda * VacuumPermittivity);
453 if (!ComputeFlux(gtS, lenS, phiS, du, dv, fx, fy)) {
457 Rotate(fx, fy, phiF, Global2Local, ex, ey);
462 std::cerr <<
m_className <<
"::ComputeInfluenceMatrix:\n";
463 std::cerr <<
" Unknown boundary type: " << etF <<
".\n";
467 influenceMatrix[iF][jS] = infCoeff;
472 for (
int i = 0; i < nElements; ++i) {
473 influenceMatrix[nElements][i] = elements[i].len;
474 influenceMatrix[i][nElements] = 0.;
476 influenceMatrix[nElements][nElements] = 0.;
481void ComponentNeBem2d::SplitElement(
const int iel) {
484 if (elements[iel].geoType != 0)
return;
486 double phi = elements[iel].phi;
487 double len = elements[iel].len / 2.;
488 elements[iel].len = len;
489 double x0 = elements[iel].cX;
490 double y0 = elements[iel].cY;
492 double dx = 0., dy = 0.;
493 Rotate(len, 0., phi, Local2Global, dx, dy);
496 newElement.geoType = elements[iel].geoType;
497 newElement.len = elements[iel].len;
498 newElement.phi = elements[iel].phi;
499 newElement.bcType = elements[iel].bcType;
500 newElement.bcValue = elements[iel].bcValue;
501 newElement.lambda = elements[iel].lambda;
503 elements[iel].cX = x0 + dx;
504 elements[iel].cY = y0 + dy;
505 newElement.cX = x0 - dx;
506 newElement.cY = y0 - dx;
508 elements.push_back(newElement);
512bool ComponentNeBem2d::InvertMatrix() {
515 if (matrixInversionFlag)
return true;
517 const int nEntries = nElements + 1;
520 inverseMatrix.resize(nEntries);
521 for (
int i = nEntries; i--;) inverseMatrix[i].resize(nEntries);
524 col.resize(nEntries);
525 index.resize(nEntries);
528 if (!LUDecomposition()) {
530 std::cerr <<
" LU Decomposition failed.\n";
535 for (
int j = 0; j < nEntries; ++j) {
536 for (
int i = 0; i < nEntries; ++i) col[i] = 0.;
539 for (
int i = 0; i < nEntries; ++i) inverseMatrix[i][j] = col[i];
543 influenceMatrix.clear();
548 matrixInversionFlag =
true;
553bool ComponentNeBem2d::LUDecomposition() {
561 const int n = nElements;
564 std::vector<double> v;
569 double big = 0., temp = 0.;
570 for (i = 0; i < n; ++i) {
572 for (j = 0; j < n; ++j) {
573 temp =
fabs(influenceMatrix[i][j]);
574 if (temp > big) big = temp;
576 if (big == 0.)
return false;
582 double sum = 0., dum = 0.;
584 for (j = 0; j < n; ++j) {
585 for (i = 0; i < j; ++i) {
586 sum = influenceMatrix[i][j];
587 for (k = 0; k < i; ++k)
588 sum -= influenceMatrix[i][k] * influenceMatrix[k][j];
589 influenceMatrix[i][j] = sum;
593 for (i = j; i < n; ++i) {
594 sum = influenceMatrix[i][j];
595 for (k = 0; k < j; ++k)
596 sum -= influenceMatrix[i][k] * influenceMatrix[k][j];
597 influenceMatrix[i][j] = sum;
599 dum = v[i] *
fabs(sum);
607 for (k = 0; k < n; ++k) {
608 dum = influenceMatrix[imax][k];
609 influenceMatrix[imax][k] = influenceMatrix[j][k];
610 influenceMatrix[j][k] = dum;
616 if (influenceMatrix[j][j] == 0.) influenceMatrix[j][j] = Small;
619 dum = 1. / (influenceMatrix[j][j]);
620 for (i = j + 1; i < n; ++i) influenceMatrix[i][j] *= dum;
627void ComponentNeBem2d::LUSubstitution() {
629 const int n = nElements;
636 for (i = 0; i < n; ++i) {
641 for (j = ii - 1; j < i; ++j) sum -= influenceMatrix[i][j] * col[j];
642 }
else if (sum != 0.) {
649 for (i = n - 1; i >= 0; i--) {
651 for (j = i + 1; j < n; ++j) sum -= influenceMatrix[i][j] * col[j];
652 col[i] = sum / influenceMatrix[i][i];
656bool ComponentNeBem2d::GetBoundaryConditions() {
658 const int nEntries = nElements + 1;
661 boundaryConditions.resize(nEntries);
663 for (
int i = nElements; i--;) {
664 switch (elements[i].bcType) {
667 boundaryConditions[i] = elements[i].bcValue;
671 boundaryConditions[i] = 0.;
675 boundaryConditions[i] = 0.;
679 boundaryConditions[i] = 0.;
683 boundaryConditions[nElements] = 0.;
688bool ComponentNeBem2d::Solve() {
690 const int nEntries = nElements + 1;
693 double solution = 0.;
694 for (i = nElements; i--;) {
696 for (j = nEntries; j--;) {
697 solution += inverseMatrix[i][j] * boundaryConditions[j];
699 elements[i].solution = solution;
704 std::cout <<
" Element Solution\n";
705 for (i = 0; i < nElements; ++i) {
706 std::cout <<
" " << i <<
" " << elements[i].solution <<
"\n";
713bool ComponentNeBem2d::CheckConvergence() {
717 std::vector<double> v;
718 std::vector<double> ne;
719 v.resize(nCollocationPoints);
720 ne.resize(nCollocationPoints);
722 double ex = 0., ey = 0.;
723 double fx = 0., fy = 0., u = 0.;
726 double x = 0., y = 0.;
727 double dx = 0., dy = 0.;
731 std::cout <<
m_className <<
"::CheckConvergence:\n";
732 std::cout <<
"element # type LHS RHS\n";
734 for (
int i = nElements; i--;) {
735 for (
int k = nCollocationPoints; k--;) v[k] = ne[k] = 0.;
737 for (
int j = nElements; j--;) {
739 for (
int k = nCollocationPoints; k--;) {
742 if (elements[i].geoType == 0) {
744 Rotate(2. * elements[i].len, 0., elements[i].phi, Local2Global, dx,
748 if (randomCollocation) {
751 r = (k + 1.) / (nCollocationPoints + 1.);
758 x += elements[i].len *
cos(r);
759 y += elements[i].len *
sin(r);
762 dx = x - elements[j].cX;
763 dy = y - elements[j].cY;
765 Rotate(dx, dy, elements[j].phi, Global2Local, xLoc, yLoc);
767 ComputePotential(elements[j].geoType, elements[j].len, xLoc, yLoc, u);
769 ComputeFlux(elements[j].geoType, elements[j].len, elements[j].phi, xLoc,
772 Rotate(fx, fy, elements[i].phi, Global2Local, ex, ey);
773 v[k] += u * elements[j].solution;
774 ne[k] += ey * elements[j].solution;
777 double v0 = 0., ne0 = 0.;
778 for (
int k = nCollocationPoints; k--;) {
782 v0 /= nCollocationPoints;
783 ne0 /= nCollocationPoints;
785 if (elements[i].bcType == 2) {
787 ne1 = ne0 + elements[i].solution /
788 (2. * elements[i].lambda * VacuumPermittivity);
791 if (elements[i].bcType == 0) {
792 std::cout << std::setw(5) << i <<
" cond. " << std::setw(10) << v0
793 <<
" " << std::setw(10) << elements[i].bcValue <<
"\n";
794 }
else if (elements[i].bcType == 2) {
795 std::cout << std::setw(5) << i <<
" diel. " << std::setw(10) << ne0
796 <<
" " << ne1 <<
" 0\n";
804void ComponentNeBem2d::Rotate(
const double xIn,
const double yIn,
805 const double phi,
const int opt,
double& xOut,
812 if (
fabs(phi) < 1.e-12) {
818 const double c =
cos(phi);
819 const double s = opt *
sin(phi);
820 xOut = c * xIn + s * yIn;
821 yOut = -s * xIn + c * yIn;
824double ComponentNeBem2d::LinePotential(
const double a,
const double x,
828 const double amx = a - x;
829 const double apx = a + x;
830 if (
fabs(y) > Small) {
831 const double y2 = y * y;
832 p = 2. * a - y * (atan(amx / y) + atan(apx / y)) -
833 0.5 * amx * log(amx * amx + y2) - 0.5 * apx * log(apx * apx + y2);
834 }
else if (
fabs(x) != a) {
835 p = 2. * a - 0.5 * amx * log(amx * amx) - 0.5 * apx * log(apx * apx);
837 p = 2. * a * (1. - log(2. * a));
840 return p / TwoPiEpsilon0;
843double ComponentNeBem2d::WirePotential(
const double r0,
const double x,
846 const double r =
sqrt(x * x + y * y);
848 return -log(r) * r0 / VacuumPermittivity;
852 return -log(r0) * r0 / VacuumPermittivity;
855void ComponentNeBem2d::LineFlux(
const double a,
const double x,
const double y,
856 double& ex,
double& ey) {
858 const double amx = a - x;
859 const double apx = a + x;
861 const double y2 = y * y;
862 ex = 0.5 * log((apx * apx + y2) / (amx * amx + y2));
863 ey = atan(amx / y) + atan(apx / y);
864 }
else if (
fabs(x) != a) {
865 ex = 0.5 * log(apx * apx / (amx * amx));
869 const double eps = 1.e-12;
871 log(
pow(apx * apx - eps * eps, 2) /
pow(amx * amx - eps * eps, 2));
879void ComponentNeBem2d::WireFlux(
const double r0,
const double x,
const double y,
880 double& ex,
double& ey) {
882 const double r =
sqrt(x * x + y * y);
884 const double r2 = r * r;
887 }
else if (r == r0) {
895 ex = ex / VacuumPermittivity;
896 ey = ey / VacuumPermittivity;
899void ComponentNeBem2d::Reset() {
911void ComponentNeBem2d::UpdatePeriodicity() {
913 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n";
914 std::cerr <<
" Periodicities are not supported.\n";
DoubleAc cos(const DoubleAc &f)
DoubleAc pow(const DoubleAc &f, double p)
DoubleAc sqrt(const DoubleAc &f)
DoubleAc sin(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
virtual Medium * GetMedium(const double &x, const double &y, const double &z)
void SetNumberOfDivisions(const int ndiv)
void SetMaxNumberOfIterations(const int niter)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status)
void AddWire(const double x0, const double y0, const double d, const double bcval)
void SetNumberOfCollocationPoints(const int ncoll)
void AddPanel(const double x0, const double y0, const double x1, const double y1, const int bctype, const double bcval, const double lambda)
bool GetVoltageRange(double &vmin, double &vmax)
void SetMinimumElementSize(const double min)