22unsigned int NextPoint(
const unsigned int i,
const unsigned int n) {
23 const unsigned int j = i + 1;
27unsigned int PrevPoint(
const unsigned int i,
const unsigned int n) {
28 return i > 0 ? i - 1 : n - 1;
31double Mag(
const std::array<double, 3>& a) {
32 return sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
35std::array<double, 3> UnitVector(
const std::array<double, 3>& a) {
36 const double mag = Mag(a);
37 if (mag < 1.e-12)
return a;
38 const std::array<double, 3> b = {a[0] / mag, a[1] / mag, a[2] / mag};
42std::array<double, 3> CrossProduct(
const std::array<double, 3>& u,
43 const std::array<double, 3>& v) {
44 const std::array<double, 3> w = {u[1] * v[2] - u[2] * v[1],
45 u[2] * v[0] - u[0] * v[2],
46 u[0] * v[1] - u[1] * v[0]};
50std::array<double, 3> LocalToGlobal(
51 const double x,
const double y,
const double z,
52 const std::array<std::array<double, 3>, 3>& dcos,
53 const std::array<double, 3>& t) {
55 std::array<double, 4> u = {
x,
y,
z, 1.};
57 std::array<std::array<double, 4>, 4> rot;
58 rot[0] = {dcos[0][0], dcos[1][0], dcos[2][0], 0.};
59 rot[1] = {dcos[0][1], dcos[1][1], dcos[2][1], 0.};
60 rot[2] = {dcos[0][2], dcos[1][2], dcos[2][2], 0.};
61 rot[3] = {0., 0., 0., 1.};
63 std::array<double, 4> v = {0., 0., 0., 0.};
64 for (
int i = 0; i < 4; ++i) {
65 for (
int j = 0; j < 4; ++j) {
66 v[i] += rot[i][j] * u[j];
69 const std::array<double, 3> a = {v[0] + t[0], v[1] + t[1], v[2] + t[2]};
74double Lambda(
const double x1,
const double x0,
const double x2,
75 const double y1,
const double y0,
const double y2) {
77 if ((x1 - x2) == 0. && (y1 - y2) == 0.) {
78 std::cerr <<
"ComponentNeBem3d::Lambda: Zero length segment.\n";
83 const double dx1 = x0 - x1;
84 const double dy1 = y0 - y1;
85 const double dx2 = x0 - x2;
86 const double dy2 = y0 - y2;
87 if (dx1 * dx1 + dy1 * dy1 < dx2 * dx2 + dy2 * dy2) {
97 xl = 1. - dy2 / (y1 - y2);
99 xl = 1. - dx2 / (x1 - x2);
107bool OnLine(
const double x1,
const double y1,
const double x2,
const double y2,
108 const double u,
const double v) {
110 double epsx = 1.e-10 * std::max({
fabs(x1),
fabs(x2),
fabs(u)});
111 double epsy = 1.e-10 * std::max({
fabs(y1),
fabs(y2),
fabs(v)});
112 epsx = std::max(1.e-10, epsx);
113 epsy = std::max(1.e-10, epsy);
115 if ((
fabs(x1 - u) <= epsx &&
fabs(y1 - v) <= epsy) ||
116 (
fabs(x2 - u) <= epsx &&
fabs(y2 - v) <= epsy)) {
119 }
else if (
fabs(x1 - x2) <= epsx &&
fabs(y1 - y2) <= epsy) {
123 double xc = 0., yc = 0.;
126 const double dx = (x2 - x1);
127 const double dy = (y2 - y1);
128 const double xl = ((u - x1) * dx + (v - y1) * dy) / (dx * dx + dy * dy);
132 }
else if (xl > 1.) {
141 const double dx = (x1 - x2);
142 const double dy = (y1 - y2);
143 const double xl = ((u - x2) * dx + (v - y2) * dy) / (dx * dx + dy * dy);
147 }
else if (xl > 1.) {
156 if (
fabs(u - xc) < epsx &&
fabs(v - yc) < epsy) {
164bool Crossing(
const double x1,
const double y1,
const double x2,
165 const double y2,
const double u1,
const double v1,
166 const double u2,
const double v2,
double& xc,
double& yc) {
168 std::array<std::array<double, 2>, 2> a;
173 const double det = a[0][0] * a[1][1] - a[1][0] * a[0][1];
180 epsx = std::max(epsx, 1.e-10);
181 epsy = std::max(epsy, 1.e-10);
183 if (OnLine(x1, y1, x2, y2, u1, v1)) {
187 }
else if (OnLine(x1, y1, x2, y2, u2, v2)) {
191 }
else if (OnLine(u1, v1, u2, v2, x1, y1)) {
195 }
else if (OnLine(u1, v1, u2, v2, x2, y2)) {
199 }
else if (
fabs(det) < epsx * epsy) {
204 const double aux = a[1][1];
205 a[1][1] = a[0][0] / det;
207 a[1][0] = -a[1][0] / det;
208 a[0][1] = -a[0][1] / det;
210 xc = a[0][0] * (x1 * y2 - x2 * y1) + a[1][0] * (u1 * v2 - u2 * v1);
211 yc = a[0][1] * (x1 * y2 - x2 * y1) + a[1][1] * (u1 * v2 - u2 * v1);
213 if (OnLine(x1, y1, x2, y2, xc, yc) && OnLine(u1, v1, u2, v2, xc, yc)) {
221void AddPoints(
const std::vector<double>& xp1,
const std::vector<double>& yp1,
222 const std::vector<double>& xp2,
const std::vector<double>& yp2,
223 std::vector<double>& xl, std::vector<double>& yl,
224 std::vector<int>& flags, std::vector<double>& qs,
225 const double epsx,
const double epsy) {
233 std::vector<Point> points;
235 const unsigned int np1 = xp1.size();
236 const unsigned int np2 = xp2.size();
237 for (
unsigned int i = 0; i < np1; ++i) {
238 const double xi0 = xp1[i];
239 const double yi0 = yp1[i];
240 const double xi1 = xp1[NextPoint(i, np1)];
241 const double yi1 = yp1[NextPoint(i, np1)];
249 for (
unsigned int j = 0; j < np2; ++j) {
250 const double xj0 = xp2[j];
251 const double yj0 = yp2[j];
252 if (
fabs(xj0 - xi0) < epsx &&
fabs(yj0 - yi0) < epsy) {
255 const double xj1 = xp2[NextPoint(j, np2)];
256 const double yj1 = yp2[NextPoint(j, np2)];
257 if (OnLine(xj0, yj0, xj1, yj1, xi0, yi0) &&
258 (
fabs(xj0 - xi0) > epsx ||
fabs(yj0 - yi0) > epsy) &&
259 (
fabs(xj1 - xi0) > epsx ||
fabs(yj1 - yi0) > epsy)) {
263 points.push_back(std::move(p1));
265 std::vector<Point> pointsOther;
266 for (
unsigned int j = 0; j < np2; ++j) {
267 const double xj0 = xp2[j];
268 const double yj0 = yp2[j];
270 if (OnLine(xi0, yi0, xi1, yi1, xj0, yj0) &&
271 (
fabs(xi0 - xj0) > epsx ||
fabs(yi0 - yj0) > epsy) &&
272 (
fabs(xi1 - xj0) > epsx ||
fabs(yi1 - yj0) > epsy)) {
277 pointsOther.push_back(std::move(p2));
279 const double xj1 = xp2[NextPoint(j, np2)];
280 const double yj1 = yp2[NextPoint(j, np2)];
282 double xc = 0., yc = 0.;
283 bool add = Crossing(xi0, yi0, xi1, yi1, xj0, yj0, xj1, yj1, xc, yc);
285 if ((
fabs(xi0 - xc) < epsx &&
fabs(yi0 - yc) < epsy) ||
286 (
fabs(xi1 - xc) < epsx &&
fabs(yi1 - yc) < epsy) ||
287 (
fabs(xj0 - xc) < epsx &&
fabs(yj0 - yc) < epsy) ||
288 (
fabs(xj1 - xc) < epsx &&
fabs(yj1 - yc) < epsy)) {
291 if ((
fabs(xi0 - xj0) < epsx &&
fabs(yi0 - yj0) < epsy) ||
292 (
fabs(xi0 - xj1) < epsx &&
fabs(yi0 - yj1) < epsy) ||
293 (
fabs(xi1 - xj0) < epsx &&
fabs(yi1 - yj0) < epsy) ||
294 (
fabs(xi1 - xj1) < epsx &&
fabs(yi1 - yj1) < epsy)) {
303 pointsOther.push_back(std::move(p2));
307 for (
auto& p : pointsOther) {
308 p.q =
Lambda(xi0, p.x, xi1, yi0, p.y, yi1);
312 pointsOther.begin(), pointsOther.end(),
313 [](
const Point& lhs,
const Point& rhs) { return (lhs.q < rhs.q); });
314 points.insert(points.end(), pointsOther.begin(), pointsOther.end());
317 for (
const Point& p : points) {
320 flags.push_back(p.flag);
327 const double epsx,
const double epsy) {
328 const auto& xp1 = panel1.
xv;
329 const auto& yp1 = panel1.
yv;
330 const auto& xp2 = panel2.
xv;
331 const auto& yp2 = panel2.
yv;
332 if (xp1.empty() || xp2.empty())
return false;
333 const unsigned int np1 = xp1.size();
334 const unsigned int np2 = xp2.size();
337 for (
unsigned int i = 0; i < np1; ++i) {
340 for (
unsigned int j = 0; j < np2; ++j) {
341 if (
fabs(xp2[j] - xp1[i]) < epsx &&
fabs(yp2[j] - yp1[i]) < epsy) {
345 const unsigned int jj = NextPoint(j, np2);
346 if (OnLine(xp2[j], yp2[j], xp2[jj], yp2[jj], xp1[i], yp1[i])) {
351 if (!match)
return false;
355 for (
unsigned int i = 0; i < np2; ++i) {
358 for (
unsigned int j = 0; j < np1; ++j) {
359 if (
fabs(xp2[i] - xp1[j]) < epsx &&
fabs(yp2[i] - yp1[j]) < epsy) {
363 const unsigned int jj = NextPoint(j, np1);
364 if (OnLine(xp1[j], yp1[j], xp1[jj], yp1[jj], xp2[i], yp2[i])) {
369 if (!match)
return false;
392void ComponentNeBem3d::InitValues() {
396 for(
int id = 1;
id <
MAXWtFld; ++id) {
397 neBEM::OptFixedWtField[id] = 0;
398 neBEM::OptWtFldFastVol[id] = 0;
399 m_optWtFldFastVol[id] = 0;
400 m_optCreateWtFldFastPF[id] = 0;
401 m_optReadWtFldFastPF[id] = 0;
406 const double z,
double& ex,
double& ey,
407 double& ez,
double& v,
Medium*& m,
409 ex = ey = ez = v = 0.;
421 std::cerr <<
m_className <<
"::ElectricField: Initialisation failed.\n";
429 neBEM::Point3D point;
435 neBEM::Vector3D field;
436 if (neBEM::neBEMPF(&point, &v, &field) != 0) {
446 const double z,
double& ex,
double& ey,
447 double& ez,
Medium*& m,
int& status) {
459 const double z,
double& wx,
double& wy,
460 double& wz,
const std::string& label) {
462 if (m_wfields.count(label) == 0)
return;
463 const int id = m_wfields[label];
464 neBEM::Point3D point;
468 neBEM::Vector3D field;
469 if (neBEM::neBEMWeightingField(&point, &field,
id) == DBL_MAX) {
470 std::cerr <<
m_className <<
"::WeightingField: Evaluation failed.\n";
480 const std::string& label) {
481 if (m_wfields.count(label) == 0)
return 0.;
482 const int id = m_wfields[label];
483 neBEM::Point3D point;
487 neBEM::Vector3D field;
488 const double v = neBEM::neBEMWeightingField(&point, &field,
id);
489 return v == DBL_MAX ? 0. : v;
493 if (m_ynplan[0] && m_ynplan[1]) {
495 <<
" Cannot have more than two planes at constant x.\n";
501 if (x < m_coplan[0]) {
502 m_coplan[1] = m_coplan[0];
503 m_vtplan[1] = m_vtplan[0];
519 if (m_ynplan[2] && m_ynplan[3]) {
521 <<
" Cannot have more than two planes at constant y.\n";
527 if (y < m_coplan[2]) {
528 m_coplan[3] = m_coplan[2];
529 m_vtplan[3] = m_vtplan[2];
545 if (m_ynplan[4] && m_ynplan[5]) {
547 <<
" Cannot have more than two planes at constant z.\n";
553 if (z < m_coplan[4]) {
554 m_coplan[5] = m_coplan[4];
555 m_vtplan[5] = m_vtplan[4];
571 if (m_ynplan[0] && m_ynplan[1]) {
573 }
else if (m_ynplan[0] || m_ynplan[1]) {
580 if (m_ynplan[2] && m_ynplan[3]) {
582 }
else if (m_ynplan[2] || m_ynplan[3]) {
589 if (m_ynplan[4] && m_ynplan[5]) {
591 }
else if (m_ynplan[4] || m_ynplan[5]) {
599 if (i >= 2 || (i == 1 && !m_ynplan[1])) {
600 std::cerr <<
m_className <<
"::GetPlaneX: Index out of range.\n";
610 if (i >= 2 || (i == 1 && !m_ynplan[3])) {
611 std::cerr <<
m_className <<
"::GetPlaneY: Index out of range.\n";
621 if (i >= 2 || (i == 1 && !m_ynplan[5])) {
622 std::cerr <<
m_className <<
"::GetPlaneZ: Index out of range.\n";
631 if (length < MinDist) {
632 std::cerr <<
m_className <<
"::SetTargetElementSize: Value must be > "
636 m_targetElementSize = length;
640 const unsigned int nmax) {
641 if (nmin == 0 || nmax == 0) {
642 std::cerr <<
m_className <<
"::SetMinMaxNumberOfElements:\n"
643 <<
" Values must be non-zero.\n";
646 m_minNbElementsOnLength = std::min(nmin, nmax);
647 m_maxNbElementsOnLength = std::max(nmin, nmax);
664 const unsigned int NewBC,
665 const unsigned int NewPP) {
738 m_optReadInvMatrix = 1;
762 const unsigned int OptForceVaildation,
766 m_optForceValidation = OptForceVaildation;
795 m_idWtField = IdWtField;
803 const unsigned int IdWtField,
const unsigned int VersionWtFldFV) {
804 m_idWtField = IdWtField;
811 m_idWtField = IdWtField;
817 const unsigned int OptKnownCharge) {
818 m_optKnownCharge = OptKnownCharge;
827 const unsigned int ny,
828 const unsigned int nz) {
837 <<
" Periodic length must be greater than zero.\n";
840 m_periodicLength[0] = s;
849 <<
" Periodic length must be greater than zero.\n";
852 m_periodicLength[1] = s;
861 <<
" Periodic length must be greater than zero.\n";
864 m_periodicLength[2] = s;
872 std::cerr <<
m_className <<
"::SetMirrorPeriodicityX:\n"
873 <<
" Periodic length must be greater than zero.\n";
876 m_periodicLength[0] = s;
884 std::cerr <<
m_className <<
"::SetMirrorPeriodicityY:\n"
885 <<
" Periodic length must be greater than zero.\n";
888 m_periodicLength[1] = s;
896 std::cerr <<
m_className <<
"::SetMirrorPeriodicityZ:\n"
897 <<
" Periodic length must be greater than zero.\n";
900 m_periodicLength[2] = s;
911 s = m_periodicLength[0];
920 s = m_periodicLength[1];
929 s = m_periodicLength[2];
935 m_primitives.clear();
939 std::cerr <<
m_className <<
"::Initialise: Geometry not set.\n";
945 std::map<int, Solid*> solids;
946 std::map<int, Solid::BoundaryCondition> bc;
947 std::map<int, double> volt;
948 std::map<int, double> eps;
949 std::map<int, double> charge;
950 const unsigned int nSolids =
m_geometry->GetNumberOfSolids();
951 std::vector<Panel> panelsIn;
952 for (
unsigned int i = 0; i < nSolids; ++i) {
954 const auto solid =
m_geometry->GetSolid(i, medium);
955 if (!solid)
continue;
957 solid->SolidPanels(panelsIn);
959 const auto id = solid->GetId();
961 bc[id] = solid->GetBoundaryConditionType();
962 volt[id] = solid->GetBoundaryPotential();
965 <<
" Boundary conditions for solid " <<
id <<
" not set.\n";
967 std::cout <<
" Assuming the panels to be grounded.\n";
971 std::cout <<
" Assuming dielectric-dielectric interfaces.\n";
975 charge[id] = solid->GetBoundaryChargeDensity();
985 ShiftPanels(panelsIn);
995 const double epsang = 1.e-6;
996 const double epsxyz = 1.e-6;
999 const unsigned int nIn = panelsIn.size();
1001 std::cout <<
m_className <<
"::Initialise: Retrieved " << nIn
1002 <<
" panels from the solids.\n";
1005 std::vector<bool> mark(nIn,
false);
1007 unsigned int nTrivial = 0;
1008 unsigned int nConflicting = 0;
1009 unsigned int nNotImplemented = 0;
1011 for (
unsigned int i = 0; i < nIn; ++i) {
1013 if (mark[i])
continue;
1015 const double a1 = panelsIn[i].a;
1016 const double b1 = panelsIn[i].b;
1017 const double c1 = panelsIn[i].c;
1018 const auto& xp1 = panelsIn[i].xv;
1019 const auto& yp1 = panelsIn[i].yv;
1020 const auto& zp1 = panelsIn[i].zv;
1021 const unsigned int np1 = xp1.size();
1023 const double d1 = a1 * xp1[0] + b1 * yp1[0] + c1 * zp1[0];
1025 std::cout <<
" Panel " << i <<
"\n Norm vector: " << a1 <<
", " << b1
1026 <<
", " << c1 <<
", " << d1 <<
".\n";
1029 std::array<std::array<double, 3>, 3> rot;
1030 if (fabs(c1) <= fabs(a1) && fabs(c1) <= fabs(b1)) {
1032 rot[0][0] = b1 / sqrt(a1 * a1 + b1 * b1);
1033 rot[0][1] = -a1 / sqrt(a1 * a1 + b1 * b1);
1035 }
else if (fabs(b1) <= fabs(a1) && fabs(b1) <= fabs(c1)) {
1037 rot[0][0] = c1 / sqrt(a1 * a1 + c1 * c1);
1039 rot[0][2] = -a1 / sqrt(a1 * a1 + c1 * c1);
1043 rot[0][1] = c1 / sqrt(b1 * b1 + c1 * c1);
1044 rot[0][2] = -b1 / sqrt(b1 * b1 + c1 * c1);
1049 rot[1][0] = rot[2][1] * rot[0][2] - rot[2][2] * rot[0][1];
1050 rot[1][1] = rot[2][2] * rot[0][0] - rot[2][0] * rot[0][2];
1051 rot[1][2] = rot[2][0] * rot[0][1] - rot[2][1] * rot[0][0];
1053 std::vector<double> xp(np1, 0.);
1054 std::vector<double> yp(np1, 0.);
1055 std::vector<double> zp(np1, 0.);
1056 for (
unsigned int k = 0; k < np1; ++k) {
1057 xp[k] = rot[0][0] * xp1[k] + rot[0][1] * yp1[k] + rot[0][2] * zp1[k];
1058 yp[k] = rot[1][0] * xp1[k] + rot[1][1] * yp1[k] + rot[1][2] * zp1[k];
1059 zp[k] = rot[2][0] * xp1[k] + rot[2][1] * yp1[k] + rot[2][2] * zp1[k];
1062 std::vector<Panel> newPanels;
1063 std::vector<int> vol1;
1064 std::vector<int> vol2;
1065 Panel panel1 = panelsIn[i];
1069 vol1.push_back(panel1.
volume);
1071 newPanels.push_back(std::move(panel1));
1073 for (
unsigned int j = i + 1; j < nIn; ++j) {
1074 if (mark[j])
continue;
1075 const double a2 = panelsIn[j].a;
1076 const double b2 = panelsIn[j].b;
1077 const double c2 = panelsIn[j].c;
1078 const auto& xp2 = panelsIn[j].xv;
1079 const auto& yp2 = panelsIn[j].yv;
1080 const auto& zp2 = panelsIn[j].zv;
1081 const unsigned int np2 = xp2.size();
1083 const double d2 = a2 * xp2[0] + b2 * yp2[0] + c2 * zp2[0];
1085 const double dot = a1 * a2 + b1 * b2 + c1 * c2;
1087 const double offset = d1 - d2 * dot;
1088 if (fabs(fabs(dot) - 1.) > epsang || fabs(offset) > epsxyz)
continue;
1091 if (
m_debug) std::cout <<
" Match with panel " << j <<
".\n";
1096 for (
unsigned int k = 0; k < np2; ++k) {
1097 xp[k] = rot[0][0] * xp2[k] + rot[0][1] * yp2[k] + rot[0][2] * zp2[k];
1098 yp[k] = rot[1][0] * xp2[k] + rot[1][1] * yp2[k] + rot[1][2] * zp2[k];
1099 zp[k] = rot[2][0] * xp2[k] + rot[2][1] * yp2[k] + rot[2][2] * zp2[k];
1102 Panel panel2 = panelsIn[j];
1106 vol1.push_back(panel2.
volume);
1108 newPanels.push_back(std::move(panel2));
1110 std::vector<bool> obsolete(newPanels.size(),
false);
1112 unsigned int jmin = 0;
1116 const unsigned int n = newPanels.size();
1117 for (
unsigned int j = 0; j < n; ++j) {
1118 if (obsolete[j] || j < jmin)
continue;
1119 if (vol1[j] >= 0 && vol2[j] >= 0)
continue;
1120 const auto& panelj = newPanels[j];
1121 for (
unsigned int k = j + 1; k < n; ++k) {
1122 if (obsolete[k])
continue;
1123 if (vol1[k] >= 0 && vol2[k] >= 0)
continue;
1124 const auto& panelk = newPanels[k];
1125 if (
m_debug) std::cout <<
" Cutting " << j <<
", " << k <<
".\n";
1127 std::vector<Panel> panelsOut;
1128 std::vector<int> itypo;
1129 EliminateOverlaps(panelj, panelk, panelsOut, itypo);
1130 const unsigned int nOut = panelsOut.size();
1133 const double epsx = epsxyz;
1134 const double epsy = epsxyz;
1136 const bool equal1 = Equal(panelj, panelsOut[0], epsx, epsy);
1137 const bool equal2 = Equal(panelj, panelsOut[1], epsx, epsy);
1138 const bool equal3 = Equal(panelk, panelsOut[0], epsx, epsy);
1139 const bool equal4 = Equal(panelk, panelsOut[1], epsx, epsy);
1140 if ((equal1 || equal3) && (equal2 || equal4)) {
1142 std::cout <<
" Original and new panels are identical.\n";
1150 if (
m_debug) std::cout <<
" Change flag: " << change <<
".\n";
1152 if (!change)
continue;
1158 for (
unsigned int l = 0; l < nOut; ++l) {
1159 if (itypo[l] == 1) {
1160 vol1.push_back(std::max(vol1[j], vol2[j]));
1162 }
else if (itypo[l] == 2) {
1163 vol1.push_back(std::max(vol1[k], vol2[k]));
1166 vol1.push_back(std::max(vol1[j], vol2[j]));
1167 vol2.push_back(std::max(vol1[k], vol2[k]));
1169 newPanels.push_back(std::move(panelsOut[l]));
1170 obsolete.push_back(
false);
1180 const unsigned int nNew = newPanels.size();
1181 for (
unsigned int j = 0; j < nNew; ++j) {
1182 if (obsolete[j])
continue;
1184 int interfaceType = 0;
1185 double potential = 0.;
1187 double chargeDensity = 0.;
1189 std::cout <<
" Volume 1: " << vol1[j] <<
". Volume 2: " << vol2[j]
1192 if (vol1[j] < 0 && vol2[j] < 0) {
1195 }
else if (vol1[j] < 0 || vol2[j] < 0) {
1197 const auto vol = vol1[j] < 0 ? vol2[j] : vol1[j];
1201 if (fabs(eps[vol] - 1.) < 1.e-6) {
1205 lambda = (eps[vol] - 1.) / (eps[vol] + 1.);
1208 potential = volt[vol];
1211 chargeDensity = charge[vol];
1214 const auto bc1 = bc[vol1[j]];
1215 const auto bc2 = bc[vol2[j]];
1222 potential = volt[vol1[j]];
1224 chargeDensity = charge[vol1[j]];
1230 const double v1 = volt[vol1[j]];
1231 const double v2 = volt[vol2[j]];
1232 if (fabs(v1 - v2) < 1.e-6 * (1. + fabs(v1) + fabs(v2))) {
1240 potential = volt[vol2[j]];
1242 chargeDensity = charge[vol2[j]];
1245 const double eps1 = eps[vol1[j]];
1246 const double eps2 = eps[vol2[j]];
1247 if (fabs(eps1 - eps2) < 1.e-6 * (1. + fabs(eps1) + fabs(eps2))) {
1251 lambda = (eps1 - eps2) / (eps1 + eps2);
1257 if (interfaceType < 0) {
1258 std::cout <<
" Conflicting boundary conditions. Skip.\n";
1259 }
else if (interfaceType < 1) {
1260 std::cout <<
" Trivial interface. Skip.\n";
1261 }
else if (interfaceType > 5) {
1262 std::cout <<
" Interface type " << interfaceType
1263 <<
" is not implemented. Skip.\n";
1266 if (interfaceType < 0) {
1268 }
else if (interfaceType < 1) {
1270 }
else if (interfaceType > 5) {
1273 if (interfaceType < 1 || interfaceType > 5)
continue;
1275 std::vector<Panel> panelsOut;
1277 if (
m_debug) std::cout <<
" Creating primitives.\n";
1278 MakePrimitives(newPanels[j], panelsOut);
1280 for (
auto& panel : panelsOut) {
1281 const auto& up = panel.xv;
1282 const auto& vp = panel.yv;
1283 const auto& wp = panel.zv;
1284 const unsigned int np = up.size();
1289 for (
unsigned int k = 0; k < np; ++k) {
1290 xp[k] = rot[0][0] * up[k] + rot[1][0] * vp[k] + rot[2][0] * wp[k];
1291 yp[k] = rot[0][1] * up[k] + rot[1][1] * vp[k] + rot[2][1] * wp[k];
1292 zp[k] = rot[0][2] * up[k] + rot[1][2] * vp[k] + rot[2][2] * wp[k];
1294 Primitive primitive;
1295 primitive.a = panel.a;
1296 primitive.b = panel.b;
1297 primitive.c = panel.c;
1301 primitive.v = potential;
1302 primitive.q = chargeDensity;
1303 primitive.lambda = lambda;
1304 primitive.interface = interfaceType;
1306 primitive.elementSize = -1.;
1307 if (solids.find(vol1[j]) != solids.end()) {
1308 const auto solid = solids[vol1[j]];
1310 primitive.elementSize = solid->GetDiscretisationLevel(panel);
1313 primitive.vol1 = vol1[j];
1314 primitive.vol2 = vol2[j];
1315 m_primitives.push_back(std::move(primitive));
1321 for (
unsigned int i = 0; i < nSolids; ++i) {
1323 if (!solid)
continue;
1324 if (!solid->IsWire())
continue;
1325 double x0 = 0., y0 = 0., z0 = 0.;
1326 solid->GetCentre(x0, y0, z0);
1327 double dx = 0., dy = 0., dz = 1.;
1328 solid->GetDirection(dx, dy, dz);
1329 const double dnorm = sqrt(dx * dx + dy * dy + dz * dz);
1330 if (dnorm < Small) {
1332 <<
" Wire has zero norm direction vector; skipped.\n";
1338 const double h = solid->GetHalfLengthZ();
1339 Primitive primitive;
1340 primitive.a = solid->GetRadius();
1343 primitive.xv = {x0 - h * dx, x0 + h * dx};
1344 primitive.yv = {y0 - h * dy, y0 + h * dy};
1345 primitive.zv = {z0 - h * dz, z0 + h * dz};
1346 primitive.v = solid->GetBoundaryPotential();
1347 primitive.q = solid->GetBoundaryChargeDensity();
1348 primitive.lambda = 0.;
1349 primitive.interface =
InterfaceType(solid->GetBoundaryConditionType());
1352 primitive.elementSize = solid->GetDiscretisationLevel(panel);
1353 primitive.vol1 = solid->GetId();
1354 primitive.vol2 = -1;
1355 m_primitives.push_back(std::move(primitive));
1358 if (nTrivial > 0 || nConflicting > 0 || nNotImplemented > 0) {
1360 if (nConflicting > 0) {
1361 std::cerr <<
" Skipped " << nConflicting
1362 <<
" panels with conflicting boundary conditions.\n";
1364 if (nNotImplemented > 0) {
1365 std::cerr <<
" Skipped " << nNotImplemented
1366 <<
" panels with not yet available boundary conditions.\n";
1369 std::cerr <<
" Skipped " << nTrivial
1370 <<
" panels with trivial boundary conditions.\n";
1375 <<
" Created " << m_primitives.size() <<
" primitives.\n";
1379 for (
const auto& primitive : m_primitives) {
1380 const auto nVertices = primitive.xv.size();
1381 if (nVertices < 2 || nVertices > 4)
continue;
1382 std::vector<Element> elements;
1384 double targetSize = primitive.elementSize;
1385 if (targetSize < MinDist) targetSize = m_targetElementSize;
1386 if (nVertices == 2) {
1387 DiscretizeWire(primitive, targetSize, elements);
1388 }
else if (nVertices == 3) {
1389 DiscretizeTriangle(primitive, targetSize, elements);
1390 }
else if (nVertices == 4) {
1391 DiscretizeRectangle(primitive, targetSize, elements);
1393 for (
auto& element : elements) {
1394 element.interface = primitive.interface;
1395 element.lambda = primitive.lambda;
1396 element.bc = primitive.v;
1397 element.assigned = primitive.q;
1398 element.solution = 0.;
1400 m_elements.insert(m_elements.end(),
1401 std::make_move_iterator(elements.begin()),
1402 std::make_move_iterator(elements.end()));
1407 neBEM::NbThreads = m_nThreads;
1408 neBEM::PrimAfter = m_primAfter;
1409 neBEM::WtFldPrimAfter = m_wtFldPrimAfter;
1410 neBEM::OptRmPrim = m_optRmPrim;
1413 neBEM::OptFastVol = m_optFastVol;
1414 neBEM::OptCreateFastPF = m_optCreateFastPF;
1415 neBEM::OptReadFastPF = m_optReadFastPF;
1416 neBEM::VersionFV = m_versionFV;
1417 neBEM::NbBlocksFV = m_nbBlocksFV;
1420 for (
int id = 1;
id <
MAXWtFld; ++id) {
1421 neBEM::OptWtFldFastVol[id] = m_optWtFldFastVol[id];
1422 neBEM::OptCreateWtFldFastPF[id] = m_optCreateWtFldFastPF[id];
1423 neBEM::OptReadWtFldFastPF[id] = m_optReadWtFldFastPF[id];
1424 neBEM::VersionWtFldFV[id] = m_versionWtFldFV[id];
1425 neBEM::NbBlocksWtFldFV[id] = m_nbBlocksWtFldFV[id];
1428 neBEM::OptKnCh = m_optKnownCharge;
1430 neBEM::OptChargingUp = m_optChargingUp;
1433 if (neBEM::neBEMInitialize() != 0) {
1435 <<
" Initialising neBEM failed.\n";
1441 neBEM::MinNbElementsOnLength = m_minNbElementsOnLength;
1442 neBEM::MaxNbElementsOnLength = m_maxNbElementsOnLength;
1443 neBEM::ElementLengthRqstd = m_targetElementSize * 0.01;
1446 neBEM::NewModel = m_newModel;
1447 neBEM::NewMesh = m_newMesh;
1448 neBEM::NewBC = m_newBC;
1449 neBEM::NewPP = m_newPP;
1452 neBEM::OptStoreInflMatrix = m_optStoreInflMatrix;
1453 neBEM::OptReadInflMatrix = m_optReadInflMatrix;
1454 neBEM::OptStoreInvMatrix = m_optStoreInvMatrix;
1455 neBEM::OptReadInvMatrix = m_optReadInvMatrix;
1456 neBEM::OptStorePrimitives = m_optStorePrimitives;
1457 neBEM::OptReadPrimitives = m_optReadPrimitives;
1458 neBEM::OptStoreElements = m_optStoreElements;
1459 neBEM::OptReadElements = m_optReadElements;
1460 neBEM::OptFormattedFile = m_optStoreFormatted;
1461 neBEM::OptUnformattedFile = m_optStoreUnformatted;
1462 neBEM::OptSystemChargeZero = m_optSystemChargeZero;
1463 neBEM::OptValidateSolution = m_optValidateSolution;
1464 neBEM::OptForceValidation = m_optForceValidation;
1465 neBEM::OptRepeatLHMatrix = m_optRepeatLHMatrix;
1468 neBEM::OptSystemChargeZero = m_optSystemChargeZero;
1469 neBEM::OptValidateSolution = m_optValidateSolution;
1470 neBEM::OptForceValidation = m_optForceValidation;
1471 neBEM::OptRepeatLHMatrix = m_optRepeatLHMatrix;
1474 neBEM::DebugLevel =
m_debug ? 101 : 0;
1477 if (m_inversion == Inversion::LU) {
1478 neBEM::OptInvMatProc = 0;
1480 neBEM::OptInvMatProc = 1;
1483 if (neBEM::WtFieldChDen != NULL) {
1484 neBEM::neBEMDeleteAllWeightingFields();
1487 if (neBEM::neBEMReadGeometry() != 0) {
1489 <<
" Transferring the geometry to neBEM failed.\n";
1494 int** elementNbs = neBEM::imatrix(1, neBEM::NbPrimitives, 1, 2);
1495 for (
int i = 1; i <= neBEM::NbPrimitives; ++i) {
1496 const int vol1 = neBEM::VolRef1[i];
1498 if (solids.find(vol1) != solids.end()) {
1499 const auto solid = solids[vol1];
1502 panel.
a = neBEM::XNorm[i];
1503 panel.
b = neBEM::YNorm[i];
1504 panel.
c = neBEM::ZNorm[i];
1505 const int nv = neBEM::NbVertices[i];
1506 panel.
xv.resize(nv);
1507 panel.
yv.resize(nv);
1508 panel.
zv.resize(nv);
1509 for (
int j = 0; j < nv; ++j) {
1510 panel.
xv[j] = neBEM::XVertex[i][j];
1511 panel.
yv[j] = neBEM::YVertex[i][j];
1512 panel.
zv[j] = neBEM::ZVertex[i][j];
1514 size1 = solid->GetDiscretisationLevel(panel);
1517 int vol2 = neBEM::VolRef2[i];
1519 if (solids.find(vol2) != solids.end()) {
1520 const auto solid = solids[vol2];
1523 panel.
a = -neBEM::XNorm[i];
1524 panel.
b = -neBEM::YNorm[i];
1525 panel.
c = -neBEM::ZNorm[i];
1526 const int nv = neBEM::NbVertices[i];
1527 panel.
xv.resize(nv);
1528 panel.
yv.resize(nv);
1529 panel.
zv.resize(nv);
1530 for (
int j = 0; j < nv; ++j) {
1531 panel.
xv[j] = neBEM::XVertex[i][j];
1532 panel.
yv[j] = neBEM::YVertex[i][j];
1533 panel.
zv[j] = neBEM::ZVertex[i][j];
1535 size2 = solid->GetDiscretisationLevel(panel);
1538 double size = m_targetElementSize;
1539 if (size1 > 0. && size2 > 0.) {
1540 size = std::min(size1, size2);
1541 }
else if (size1 > 0.) {
1543 }
else if (size2 > 0.) {
1550 const double dx1 = neBEM::XVertex[i][0] - neBEM::XVertex[i][1];
1551 const double dy1 = neBEM::YVertex[i][0] - neBEM::YVertex[i][1];
1552 const double dz1 = neBEM::ZVertex[i][0] - neBEM::ZVertex[i][1];
1553 const double l1 = dx1 * dx1 + dy1 * dy1 + dz1 * dz1;
1554 int nb1 = (int)(sqrt(l1) / size);
1556 if (nb1 < neBEM::MinNbElementsOnLength) {
1557 nb1 = neBEM::MinNbElementsOnLength;
1558 }
else if (nb1 > neBEM::MaxNbElementsOnLength) {
1559 nb1 = neBEM::MaxNbElementsOnLength;
1562 if (neBEM::NbVertices[i] > 2) {
1563 const double dx2 = neBEM::XVertex[i][2] - neBEM::XVertex[i][1];
1564 const double dy2 = neBEM::YVertex[i][2] - neBEM::YVertex[i][1];
1565 const double dz2 = neBEM::ZVertex[i][2] - neBEM::ZVertex[i][1];
1566 const double l2 = dx2 * dx2 + dy2 * dy2 + dz2 * dz2;
1567 nb2 = (int)(sqrt(l2) / size);
1568 if (nb2 < neBEM::MinNbElementsOnLength) {
1569 nb2 = neBEM::MinNbElementsOnLength;
1570 }
else if (nb2 > neBEM::MaxNbElementsOnLength) {
1571 nb2 = neBEM::MaxNbElementsOnLength;
1574 elementNbs[i][1] = nb1;
1575 elementNbs[i][2] = nb2;
1578 if (neBEM::neBEMDiscretize(elementNbs) != 0) {
1579 std::cerr <<
m_className <<
"::Initialise: Discretization failed.\n";
1580 neBEM::free_imatrix(elementNbs, 1, neBEM::NbPrimitives, 1, 2);
1583 neBEM::free_imatrix(elementNbs, 1, neBEM::NbPrimitives, 1, 2);
1584 if (neBEM::neBEMBoundaryInitialConditions() != 0) {
1586 <<
" Setting the boundary and initial conditions failed.\n";
1589 if (neBEM::neBEMSolve() != 0) {
1590 std::cerr <<
m_className <<
"::Initialise: Solution failed.\n";
1594 std::set<std::string> labels;
1595 for (
unsigned int i = 0; i < nSolids; ++i) {
1597 if (!solid)
continue;
1598 const std::string label = solid->GetLabel();
1599 if (!label.empty()) labels.insert(label);
1601 for (
const auto& label : labels) {
1602 std::vector<int> primitives;
1603 for (
unsigned int i = 0; i < nSolids; ++i) {
1605 if (!solid)
continue;
1606 if (solid->GetLabel() != label)
continue;
1607 const int id = solid->GetId();
1609 for (
int j = 1; j <= neBEM::NbPrimitives; ++j) {
1610 if (neBEM::VolRef1[j] ==
id || neBEM::VolRef2[j] ==
id) {
1611 primitives.push_back(j);
1616 const int np = primitives.size();
1617 const int id = neBEM::neBEMPrepareWeightingField(np, primitives.data());
1620 <<
" Weighting field calculation for readout group \""
1621 << label <<
"\" failed.\n";
1625 <<
" Prepared weighting field for readout group \"" << label
1627 m_wfields[label] = id;
1636void ComponentNeBem3d::ShiftPanels(std::vector<Panel>& panels)
const {
1644 if (!perx && !pery && !perz)
return;
1647 for (
auto& panel : panels) {
1648 const auto nv = panel.xv.size();
1649 if (nv == 0)
continue;
1651 double xc = std::accumulate(panel.xv.begin(), panel.xv.end(), 0.);
1652 double yc = std::accumulate(panel.yv.begin(), panel.yv.end(), 0.);
1653 double zc = std::accumulate(panel.zv.begin(), panel.zv.end(), 0.);
1658 constexpr double eps = 1.e-6;
1661 if (perx && m_periodicLength[0] > 0.) {
1662 rx = xc / m_periodicLength[0];
1663 nx = std::round(rx);
1664 if (std::abs(rx - nx - 0.5) < eps) ++nx;
1668 if (pery && m_periodicLength[1] > 0.) {
1669 ry = yc / m_periodicLength[1];
1670 ny = std::round(ry);
1671 if (std::abs(ry - ny - 0.5) < eps) ++ny;
1675 if (perz && m_periodicLength[2] > 0.) {
1676 rz = zc / m_periodicLength[2];
1677 nz = std::round(rz);
1678 if (std::abs(rz - nz - 0.5) < eps) ++nz;
1681 if (nx == 0 && ny == 0 && nz == 0)
continue;
1684 const double shift = nx * m_periodicLength[0];
1685 for (
auto& x : panel.xv)
x -= shift;
1689 const double shift = ny * m_periodicLength[1];
1690 for (
auto& y : panel.yv)
y -= shift;
1694 const double shift = nz * m_periodicLength[2];
1695 for (
auto& z : panel.zv)
z -= shift;
1744bool ComponentNeBem3d::DiscretizeWire(
const Primitive& primitive,
1745 const double targetSize,
1746 std::vector<Element>& elements)
const {
1747 const double dx = primitive.xv[1] - primitive.xv[0];
1748 const double dy = primitive.yv[1] - primitive.yv[0];
1749 const double dz = primitive.zv[1] - primitive.zv[0];
1750 const double lw =
sqrt(dx * dx + dy * dy + dz * dz);
1752 unsigned int nSegments = NbOfSegments(lw, targetSize);
1753 const double elementSize = lw / nSegments;
1757 const std::array<double, 3> zu = {dx / lw, dy / lw, dz / lw};
1759 std::array<double, 3> xu;
1761 xu = {-zu[1], zu[0], 0.};
1763 xu = {-zu[2], 0., zu[0]};
1765 xu = {0., zu[2], -zu[1]};
1767 xu = UnitVector(xu);
1769 const std::array<double, 3> yu = UnitVector(CrossProduct(zu, xu));
1770 const std::array<std::array<double, 3>, 3> dcos = {xu, yu, zu};
1772 const double xincr = dx / nSegments;
1773 const double yincr = dy / nSegments;
1774 const double zincr = dz / nSegments;
1777 const double radius = 1.;
1778 const double dA = TwoPi * radius * elementSize;
1779 for (
unsigned int i = 0; i < nSegments; ++i) {
1780 const double x0 = primitive.xv[0] + i * xincr;
1781 const double y0 = primitive.yv[0] + i * yincr;
1782 const double z0 = primitive.zv[0] + i * zincr;
1784 element.origin = {x0 + 0.5 * xincr, y0 + 0.5 * yincr, z0 + 0.5 * zincr};
1785 element.xv = {x0, x0 + xincr};
1786 element.yv = {y0, y0 + yincr};
1787 element.zv = {z0, z0 + zincr};
1788 element.lx = radius;
1789 element.lz = elementSize;
1791 element.dcos = dcos;
1793 element.collocationPoint = element.origin;
1794 elements.push_back(std::move(element));
1799bool ComponentNeBem3d::DiscretizeTriangle(
1800 const Primitive& primitive,
const double targetSize,
1801 std::vector<Element>& elements)
const {
1803 std::array<double, 3> corner = {primitive.xv[1], primitive.yv[1],
1806 const double dx1 = primitive.xv[0] - primitive.xv[1];
1807 const double dy1 = primitive.yv[0] - primitive.yv[1];
1808 const double dz1 = primitive.zv[0] - primitive.zv[1];
1809 const double dx2 = primitive.xv[2] - primitive.xv[1];
1810 const double dy2 = primitive.yv[2] - primitive.yv[1];
1811 const double dz2 = primitive.zv[2] - primitive.zv[1];
1813 std::array<double, 3> nu = {primitive.a, primitive.b, primitive.c};
1814 nu = UnitVector(nu);
1817 double lx =
sqrt(dx1 * dx1 + dy1 * dy1 + dz1 * dz1);
1818 double lz =
sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2);
1819 std::array<double, 3> xu = {dx1 / lx, dy1 / lx, dz1 / lx};
1820 std::array<double, 3> zu = {dx2 / lz, dy2 / lz, dz2 / lz};
1821 std::array<double, 3> yu = CrossProduct(zu, xu);
1822 constexpr double tol = 1.e-3;
1823 if ((
fabs(yu[0] - nu[0]) > tol) || (
fabs(yu[1] - nu[1]) > tol) ||
1824 (
fabs(yu[2] - nu[2]) > tol)) {
1828 xu = {dx2 / lx, dy2 / lx, dz2 / lx};
1829 zu = {dx1 / lz, dy1 / lz, dz1 / lz};
1830 yu = CrossProduct(zu, xu);
1831 if ((
fabs(yu[0] - nu[0]) > tol) || (
fabs(yu[1] - nu[1]) > tol) ||
1832 (
fabs(yu[2] - nu[2]) > tol)) {
1834 std::cerr <<
m_className <<
"::DiscretizeTriangle:\n"
1835 <<
" Could not establish direction vectors.\n";
1839 std::array<std::array<double, 3>, 3> dcos = {xu, yu, zu};
1849 unsigned int nx = NbOfSegments(lx, targetSize);
1850 unsigned int nz = NbOfSegments(lz, targetSize);
1851 double elementSizeX = lx / nx;
1852 double elementSizeZ = lz / nz;
1855 double ar = elementSizeX / elementSizeZ;
1858 elementSizeZ = 0.1 * elementSizeX;
1859 nz = std::max(
static_cast<int>(lz / elementSizeZ), 1);
1860 elementSizeZ = lz / nz;
1864 elementSizeX = 0.1 * elementSizeZ;
1865 nx = std::max(
static_cast<int>(lx / elementSizeX), 1);
1866 elementSizeX = lx / nx;
1868 const double dxdz = lx / lz;
1869 for (
unsigned int k = 0; k < nz; ++k) {
1871 const double zlo = k * elementSizeZ;
1872 const double zhi = (k + 1) * elementSizeZ;
1873 double xlo = (lz - zlo) * dxdz;
1874 double xhi = (lz - zhi) * dxdz;
1877 triangle.origin = LocalToGlobal(xhi, 0., zlo, dcos, corner);
1879 const double triangleSizeX = xlo - xhi;
1880 triangle.lx = triangleSizeX;
1881 triangle.lz = elementSizeZ;
1882 triangle.dA = 0.5 * triangleSizeX * elementSizeZ;
1883 triangle.dcos = dcos;
1885 const double xv0 = triangle.origin[0];
1886 const double yv0 = triangle.origin[1];
1887 const double zv0 = triangle.origin[2];
1888 const double xv1 = xv0 + triangleSizeX * xu[0];
1889 const double yv1 = yv0 + triangleSizeX * xu[1];
1890 const double zv1 = zv0 + triangleSizeX * xu[2];
1891 const double xv2 = xv0 + elementSizeZ * zu[0];
1892 const double yv2 = yv0 + elementSizeZ * zu[1];
1893 const double zv2 = zv0 + elementSizeZ * zu[2];
1895 triangle.xv = {xv0, xv1, xv2};
1896 triangle.yv = {yv0, yv1, yv2};
1897 triangle.zv = {zv0, zv1, zv2};
1901 const double xb = triangleSizeX / 3.;
1902 const double yb = 0.;
1903 const double zb = elementSizeZ / 3.;
1904 triangle.collocationPoint =
1905 LocalToGlobal(xb, yb, zb, dcos, triangle.origin);
1906 elements.push_back(std::move(triangle));
1908 if (k == nz - 1)
continue;
1911 const int nRect = xhi <= elementSizeX ? 1 : (int)(xhi / elementSizeX);
1912 const double rectSizeX = xhi / nRect;
1913 const double zc = 0.5 * (zlo + zhi);
1914 for (
int i = 0; i < nRect; ++i) {
1916 const double xc = (i + 0.5) * rectSizeX;
1917 const double yc = 0.;
1918 std::array<double, 3> centre = LocalToGlobal(xc, yc, zc, dcos, corner);
1921 rect.origin = centre;
1922 rect.lx = rectSizeX;
1923 rect.lz = elementSizeZ;
1924 rect.dA = rectSizeX * elementSizeZ;
1928 rect.collocationPoint = centre;
1930 const double hx = 0.5 * rectSizeX;
1931 const double hz = 0.5 * elementSizeZ;
1932 std::array<double, 3> p0 = LocalToGlobal(-hx, 0., -hz, dcos, centre);
1933 std::array<double, 3> p1 = LocalToGlobal(hx, 0., -hz, dcos, centre);
1934 std::array<double, 3> p2 = LocalToGlobal(hx, 0., hz, dcos, centre);
1935 std::array<double, 3> p3 = LocalToGlobal(-hx, 0., hz, dcos, centre);
1937 rect.xv = {p0[0], p1[0], p2[0], p3[0]};
1938 rect.yv = {p0[1], p1[1], p2[1], p3[1]};
1939 rect.zv = {p0[2], p1[2], p2[2], p3[2]};
1940 elements.push_back(std::move(rect));
1946bool ComponentNeBem3d::DiscretizeRectangle(
1947 const Primitive& primitive,
const double targetSize,
1948 std::vector<Element>& elements)
const {
1949 std::array<double, 3> origin = {
1950 0.25 * std::accumulate(primitive.xv.begin(), primitive.xv.end(), 0.),
1951 0.25 * std::accumulate(primitive.yv.begin(), primitive.yv.end(), 0.),
1952 0.25 * std::accumulate(primitive.zv.begin(), primitive.zv.end(), 0.)};
1955 const double dx1 = primitive.xv[1] - primitive.xv[0];
1956 const double dy1 = primitive.yv[1] - primitive.yv[0];
1957 const double dz1 = primitive.zv[1] - primitive.zv[0];
1958 const double dx2 = primitive.xv[2] - primitive.xv[1];
1959 const double dy2 = primitive.yv[2] - primitive.yv[1];
1960 const double dz2 = primitive.zv[2] - primitive.zv[1];
1961 double lx =
sqrt(dx1 * dx1 + dy1 * dy1 + dz1 * dz1);
1962 double lz =
sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2);
1963 const std::array<double, 3> xu = {dx1 / lx, dy1 / lx, dz1 / lx};
1964 const std::array<double, 3> yu = {primitive.a, primitive.b, primitive.c};
1965 const std::array<double, 3> zu = CrossProduct(xu, yu);
1966 const std::array<std::array<double, 3>, 3> dcos = {xu, yu, zu};
1969 unsigned int nx = NbOfSegments(lx, targetSize);
1970 unsigned int nz = NbOfSegments(lz, targetSize);
1972 double elementSizeX = lx / nx;
1973 double elementSizeZ = lz / nz;
1976 double ar = elementSizeX / elementSizeZ;
1979 elementSizeZ = 0.1 * elementSizeX;
1980 nz = std::max(
static_cast<int>(lz / elementSizeZ), 1);
1981 elementSizeZ = lz / nz;
1985 elementSizeX = 0.1 * elementSizeZ;
1986 nx = std::max(
static_cast<int>(lx / elementSizeX), 1);
1987 elementSizeX = lx / nx;
1990 const double dA = elementSizeX * elementSizeZ;
1991 for (
unsigned int i = 0; i < nx; ++i) {
1993 const double xav = -0.5 * lx + (i + 0.5) * elementSizeX;
1994 for (
unsigned int k = 0; k < nz; ++k) {
1995 const double zav = -0.5 * lz + (k + 0.5) * elementSizeZ;
1997 std::array<double, 3> centre = LocalToGlobal(xav, 0., zav, dcos, origin);
1999 element.origin = centre;
2000 element.lx = elementSizeX;
2001 element.lz = elementSizeZ;
2003 element.dcos = dcos;
2004 element.collocationPoint = centre;
2006 const double hx = 0.5 * elementSizeX;
2007 const double hz = 0.5 * elementSizeZ;
2008 std::array<double, 3> p0 = LocalToGlobal(-hx, 0., -hz, dcos, centre);
2009 std::array<double, 3> p1 = LocalToGlobal(hx, 0., -hz, dcos, centre);
2010 std::array<double, 3> p2 = LocalToGlobal(hx, 0., hz, dcos, centre);
2011 std::array<double, 3> p3 = LocalToGlobal(-hx, 0., hz, dcos, centre);
2013 element.xv = {p0[0], p1[0], p2[0], p3[0]};
2014 element.yv = {p0[1], p1[1], p2[1], p3[1]};
2015 element.zv = {p0[2], p1[2], p2[2], p3[2]};
2016 elements.push_back(std::move(element));
2022unsigned int ComponentNeBem3d::NbOfSegments(
const double length,
2023 const double target)
const {
2025 if (length < MinDist)
return 1;
2026 unsigned int n =
static_cast<unsigned int>(length / target);
2027 if (n < m_minNbElementsOnLength) {
2029 n = m_minNbElementsOnLength;
2030 if (length < n * MinDist) {
2032 n =
static_cast<unsigned int>(length / MinDist);
2039 return std::min(n, m_maxNbElementsOnLength);
2042bool ComponentNeBem3d::EliminateOverlaps(
const Panel& panel1,
2043 const Panel& panel2,
2044 std::vector<Panel>& panelsOut,
2045 std::vector<int>& itypo) {
2050 const auto& xp1 = panel1.xv;
2051 const auto& yp1 = panel1.yv;
2052 const auto& zp1 = panel1.zv;
2053 const auto& xp2 = panel2.xv;
2054 const auto& yp2 = panel2.yv;
2055 const auto& zp2 = panel2.zv;
2057 if (xp1.size() <= 2 || xp2.size() <= 2) {
2061 const double xmin1 = *std::min_element(std::begin(xp1), std::end(xp1));
2062 const double ymin1 = *std::min_element(std::begin(yp1), std::end(yp1));
2063 const double xmax1 = *std::max_element(std::begin(xp1), std::end(xp1));
2064 const double ymax1 = *std::max_element(std::begin(yp1), std::end(yp1));
2066 const double xmin2 = *std::min_element(std::begin(xp2), std::end(xp2));
2067 const double ymin2 = *std::min_element(std::begin(yp2), std::end(yp2));
2068 const double xmax2 = *std::max_element(std::begin(xp2), std::end(xp2));
2069 const double ymax2 = *std::max_element(std::begin(yp2), std::end(yp2));
2071 const double xmin = std::min(xmin1, xmin2);
2072 const double ymin = std::min(ymin1, ymin2);
2073 const double xmax = std::max(xmax1, xmax2);
2074 const double ymax = std::max(ymax1, ymax2);
2076 const double epsx = 1.e-6 * std::max(std::abs(xmax), std::abs(xmin));
2077 const double epsy = 1.e-6 * std::max(std::abs(ymax), std::abs(ymin));
2079 const double zsum1 = std::accumulate(std::begin(zp1), std::end(zp1), 0.);
2080 const double zsum2 = std::accumulate(std::begin(zp2), std::end(zp2), 0.);
2081 const double zmean = (zsum1 + zsum2) / (zp1.size() + zp2.size());
2083 std::array<std::vector<double>, 2> xl;
2084 std::array<std::vector<double>, 2> yl;
2085 std::array<std::vector<int>, 2> flags;
2086 std::array<std::vector<double>, 2> qs;
2088 AddPoints(xp1, yp1, xp2, yp2, xl[0], yl[0], flags[0], qs[0], epsx, epsy);
2090 AddPoints(xp2, yp2, xp1, yp1, xl[1], yl[1], flags[1], qs[1], epsx, epsy);
2094 std::array<std::vector<int>, 2> links;
2095 for (
unsigned int ic = 0; ic < 2; ++ic) {
2096 const unsigned int n1 = xl[ic].size();
2097 links[ic].assign(n1, -1);
2098 const unsigned int jc = ic == 0 ? 1 : 0;
2099 const unsigned int n2 = xl[jc].size();
2100 for (
unsigned int i = 0; i < n1; ++i) {
2101 unsigned int nFound = 0;
2102 for (
unsigned int j = 0; j < n2; ++j) {
2103 if (
fabs(xl[ic][i] - xl[jc][j]) < epsx &&
2104 fabs(yl[ic][i] - yl[jc][j]) < epsy) {
2109 if (nFound == 0 && (flags[ic][i] == 2 || flags[ic][i] == 3)) {
2110 std::cerr <<
m_className <<
"::EliminateOverlaps: "
2111 <<
"Warning. Expected match not found (" << ic <<
"-" << jc
2115 }
else if (nFound > 1) {
2116 std::cerr <<
m_className <<
"::EliminateOverlaps: "
2117 <<
"Warning. More than 1 match found (" << ic <<
"-" << jc
2127 for (
unsigned int j = 0; j < 2; ++j) {
2128 std::cout <<
" Polygon " << j <<
"\n "
2129 <<
" No Type x y Q links\n";
2130 const unsigned int n = xl[j].size();
2131 for (
unsigned int i = 0; i < n; ++i) {
2132 printf(
" %3u %5d %13.6f %13.6f %5.3f %3d\n", i, flags[j][i],
2133 xl[j][i], yl[j][i], qs[j][i], links[j][i]);
2137 if (!ok)
return false;
2139 for (
unsigned int ic = 0; ic < 2; ++ic) {
2141 bool allInside =
true;
2142 const unsigned int np = xl[ic].size();
2143 for (
unsigned int i = 0; i < np; ++i) {
2144 if (flags[ic][i] != 1) {
2148 bool inside =
false, edge =
false;
2154 if (!(inside || edge)) {
2162 if (
m_debug) std::cout <<
" Curve 0 fully inside 1.\n";
2164 panelsOut.push_back(panel1);
2166 if (
m_debug) std::cout <<
" Curve 1 fully inside 0.\n";
2168 panelsOut.push_back(panel2);
2170 panelsOut.back().zv.assign(panelsOut.back().xv.size(), zmean);
2172 std::vector<Panel> newPanels;
2174 if (!TraceEnclosed(xl[0], yl[0], xl[1], yl[1], panel2, newPanels)) {
2178 if (!TraceEnclosed(xl[1], yl[1], xl[0], yl[0], panel1, newPanels)) {
2182 for (
auto& panel : newPanels) {
2183 panel.zv.assign(panel.xv.size(), zmean);
2190 panelsOut.insert(panelsOut.end(), newPanels.begin(), newPanels.end());
2195 for (
unsigned int ic = 0; ic < 2; ++ic) {
2196 std::vector<Panel> newPanels;
2197 const unsigned int n = xl[ic].size();
2199 std::vector<bool> mark(n,
false);
2203 std::cout <<
" Searching for starting point on " << ic <<
".\n";
2207 for (
unsigned int i = 0; i < n; ++i) {
2208 const unsigned int ii = NextPoint(i, n);
2210 if (mark[i] || mark[ii])
continue;
2212 bool inside =
false, edge =
false;
2213 const double xm = 0.5 * (xl[ic][i] + xl[ic][ii]);
2214 const double ym = 0.5 * (yl[ic][i] + yl[ic][ii]);
2220 if (inside || edge)
continue;
2226 TraceNonOverlap(xp1, yp1, xl[0], yl[0], xl[1], yl[1], flags[0],
2227 flags[1], links[0], links[1], mark, i, panel1,
2231 TraceNonOverlap(xp2, yp2, xl[1], yl[1], xl[0], yl[0], flags[1],
2232 flags[0], links[1], links[0], mark, i, panel2,
2238 for (
auto& panel : newPanels) {
2239 panel.zv.assign(panel.xv.size(), zmean);
2240 itypo.push_back(ic + 1);
2242 panelsOut.insert(panelsOut.end(), newPanels.begin(), newPanels.end());
2244 std::cout <<
" No further non-overlapped areas of " << ic <<
".\n";
2249 std::vector<Panel> newPanels;
2250 const unsigned int n1 = xl[0].size();
2251 std::vector<bool> mark1(n1,
false);
2256 std::cout <<
" Searching for starting point on overlap.\n";
2258 for (
unsigned int i = 0; i < n1; ++i) {
2260 if (mark1[i])
continue;
2263 int ip2 = links[0][ip1];
2264 if (ip2 < 0 || flags[0][ip1] == 1) {
2265 bool inside =
false, edge =
false;
2267 if (!(inside || edge))
continue;
2268 }
else if (flags[1][ip2] == 1) {
2273 TraceOverlap(xp1, yp1, xp2, yp2, xl[0], yl[0], xl[1], yl[1], flags[0],
2274 links[0], links[1], mark1, ip1, ip2, panel1, newPanels);
2278 for (
auto& panel : newPanels) {
2279 panel.zv.assign(panel.xv.size(), zmean);
2282 panelsOut.insert(panelsOut.end(), newPanels.begin(), newPanels.end());
2284 if (
m_debug) std::cout <<
" No further overlapped areas.\n";
2288bool ComponentNeBem3d::TraceEnclosed(
const std::vector<double>& xl1,
2289 const std::vector<double>& yl1,
2290 const std::vector<double>& xl2,
2291 const std::vector<double>& yl2,
2292 const Panel& panel2,
2293 std::vector<Panel>& panelsOut)
const {
2294 const int n1 = xl1.size();
2295 const int n2 = xl2.size();
2297 unsigned int nFound = 0;
2298 int jp1 = 0, jp2 = 0;
2299 int kp1 = 0, kp2 = 0;
2300 for (
int ip1 = 0; ip1 < n1; ++ip1) {
2301 const double x1 = xl1[ip1];
2302 const double y1 = yl1[ip1];
2303 for (
int ip2 = 0; ip2 < n2; ++ip2) {
2304 if (nFound > 0 && ip2 == jp2)
continue;
2305 const double x2 = xl2[ip2];
2306 const double y2 = yl2[ip2];
2308 for (
int k = 0; k < n1; ++k) {
2309 const int kk = NextPoint(k, n1);
2310 if (k == ip1 || kk == ip1)
continue;
2311 double xc = 0., yc = 0.;
2313 Crossing(x1, y1, x2, y2, xl1[k], yl1[k], xl1[kk], yl1[kk], xc, yc);
2316 if (cross)
continue;
2317 if (
m_debug) std::cout <<
" No crossing with 1.\n";
2318 for (
int k = 0; k < n2; ++k) {
2319 const int kk = NextPoint(k, n2);
2320 if (k == ip2 || kk == ip2)
continue;
2321 double xc = 0., yc = 0.;
2323 Crossing(x1, y1, x2, y2, xl2[k], yl2[k], xl2[kk], yl2[kk], xc, yc);
2326 if (cross)
continue;
2331 std::cout <<
" 1st junction: " << jp1 <<
", " << jp2 <<
".\n";
2338 double xc = 0., yc = 0.;
2339 cross = Crossing(x1, y1, x2, y2, xl1[jp1], yl1[jp1], xl2[jp2], yl2[jp2],
2343 std::cout <<
" 2nd junction: " << kp1 <<
", " << kp2 <<
".\n";
2350 if (nFound > 1)
break;
2353 std::cerr <<
m_className <<
"::TraceEnclosed: Found no cut-out.\n";
2358 std::vector<double> xpl;
2359 std::vector<double> ypl;
2360 if (
m_debug) std::cout <<
" Creating part 1 of area 2.\n";
2361 for (
int ip1 = jp1; ip1 <= kp1; ++ip1) {
2362 if (
m_debug) std::cout <<
" Adding " << ip1 <<
" on 1.\n";
2363 xpl.push_back(xl1[ip1]);
2364 ypl.push_back(yl1[ip1]);
2367 int imax = jp2 < kp2 ? jp2 + n2 : jp2;
2369 for (
int i = kp2; i <= imax; ++i) {
2371 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
2372 xpl.push_back(xl2[ip2]);
2373 ypl.push_back(yl2[ip2]);
2377 for (
int ip1 = 0; ip1 < n1; ++ip1) {
2378 if (ip1 == jp1 || ip1 == kp1)
continue;
2379 bool inside =
false, edge =
false;
2388 if (
m_debug) std::cout <<
" Trying the other direction.\n";
2389 xpl.resize(kp1 - jp1 + 1);
2390 ypl.resize(kp1 - jp1 + 1);
2391 imax = jp2 < kp2 ? kp2 : kp2 + n2;
2393 for (
int i = imax; i >= jp2; --i) {
2394 const int ip2 = i % n2;
2395 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
2396 xpl.push_back(xl2[ip2]);
2397 ypl.push_back(yl2[ip2]);
2402 Panel newPanel1 = panel2;
2405 panelsOut.push_back(std::move(newPanel1));
2406 if (
m_debug) std::cout <<
" Part 1 has " << xpl.size() <<
" nodes.\n";
2411 if (
m_debug) std::cout <<
" Creating part 2 of area 2.\n";
2413 for (
int i = kp1; i <= imax; ++i) {
2414 const int ip1 = i % n1;
2415 if (
m_debug) std::cout <<
" Adding " << ip1 <<
" on 1.\n";
2416 xpl.push_back(xl1[ip1]);
2417 ypl.push_back(yl1[ip1]);
2421 imax = jp2 > kp2 ? jp2 : jp2 + n2;
2422 for (
int i = imax; i >= kp2; --i) {
2423 const int ip2 = i % n2;
2424 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
2425 xpl.push_back(xl2[ip2]);
2426 ypl.push_back(yl2[ip2]);
2429 imax = jp2 > kp2 ? kp2 + n2 : kp2;
2430 for (
int i = jp2; i <= imax; ++i) {
2431 const int ip2 = i % n2;
2432 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
2433 xpl.push_back(xl2[ip2]);
2434 ypl.push_back(yl2[ip2]);
2438 Panel newPanel2 = panel2;
2441 panelsOut.push_back(std::move(newPanel2));
2442 if (
m_debug) std::cout <<
" Part 1 has " << xpl.size() <<
" nodes.\n";
2446void ComponentNeBem3d::TraceNonOverlap(
2447 const std::vector<double>& xp1,
const std::vector<double>& yp1,
2448 const std::vector<double>& xl1,
const std::vector<double>& yl1,
2449 const std::vector<double>& xl2,
const std::vector<double>& yl2,
2450 const std::vector<int>& flags1,
const std::vector<int>& flags2,
2451 const std::vector<int>& links1,
const std::vector<int>& links2,
2452 std::vector<bool>& mark1,
int ip1,
const Panel& panel1,
2453 std::vector<Panel>& panelsOut)
const {
2454 const unsigned int n1 = xl1.size();
2455 const unsigned int n2 = xl2.size();
2458 const int is1 = ip1;
2459 std::vector<double> xpl;
2460 std::vector<double> ypl;
2462 xpl.push_back(xl1[ip1]);
2463 ypl.push_back(yl1[ip1]);
2466 std::cout <<
" Start from point " << ip1 <<
" on curve 1.\n";
2469 ip1 = NextPoint(ip1, n1);
2470 xpl.push_back(xl1[ip1]);
2471 ypl.push_back(yl1[ip1]);
2474 std::cout <<
" Next point is " << ip1 <<
" on curve 1.\n";
2478 unsigned int il = 1;
2485 if (il == 1 && flags1[std::max(ip1, 0)] == 1) {
2487 ip1 = NextPoint(ip1, n1);
2493 xpl.push_back(xl1[ip1]);
2494 ypl.push_back(yl1[ip1]);
2496 std::cout <<
" Went to point " << ip1 <<
" on curve 1.\n";
2498 }
else if (il == 1) {
2502 if (dir == +1 || dir == 0) {
2503 const double xm = 0.5 * (xl2[ip2] + xl2[NextPoint(ip2, n2)]);
2504 const double ym = 0.5 * (yl2[ip2] + yl2[NextPoint(ip2, n2)]);
2505 bool inside =
false, edge =
false;
2508 ip2 = NextPoint(ip2, n2);
2515 }
else if (ip1 >= 0) {
2518 xpl.push_back(xl2[ip2]);
2519 ypl.push_back(yl2[ip2]);
2522 std::cout <<
" Added point " << ip2 <<
" along 2 +.\n";
2526 if (dir == -1 || dir == 0) {
2527 const double xm = 0.5 * (xl2[ip2] + xl2[PrevPoint(ip2, n2)]);
2528 const double ym = 0.5 * (yl2[ip2] + yl2[PrevPoint(ip2, n2)]);
2529 bool inside =
false, edge =
false;
2532 ip2 = PrevPoint(ip2, n2);
2539 }
else if (ip1 >= 0) {
2542 xpl.push_back(xl2[ip2]);
2543 ypl.push_back(yl2[ip2]);
2546 std::cout <<
" Added point " << ip2 <<
" along 2 -\n";
2551 ip1 = NextPoint(ip1, n1);
2555 }
else if (ip1 >= 0) {
2558 xpl.push_back(xl1[ip1]);
2559 ypl.push_back(yl1[ip1]);
2560 if (
m_debug) std::cout <<
" Continued over 1.\n";
2562 }
else if (il == 2 && flags2[std::max(ip2, 0)] == 1) {
2564 ip2 = dir > 0 ? NextPoint(ip2, n2) : PrevPoint(ip2, n2);
2569 }
else if (ip1 >= 0) {
2572 xpl.push_back(xl2[ip2]);
2573 ypl.push_back(yl2[ip2]);
2575 std::cout <<
" Went to point " << ip2 <<
" on 2.\n";
2577 }
else if (il == 2) {
2580 ip1 = NextPoint(ip1, n1);
2586 xpl.push_back(xl1[ip1]);
2587 ypl.push_back(yl1[ip1]);
2588 if (
m_debug) std::cout <<
" Resumed 1 at point " << ip1 <<
".\n";
2591 std::cerr <<
m_className <<
"::TraceNonOverlap: Unexpected case.\n";
2596 Panel newPanel = panel1;
2599 panelsOut.push_back(std::move(newPanel));
2601 std::cout <<
" End of curve reached, " << xpl.size() <<
" points.\n";
2605void ComponentNeBem3d::TraceOverlap(
2606 const std::vector<double>& xp1,
const std::vector<double>& yp1,
2607 const std::vector<double>& xp2,
const std::vector<double>& yp2,
2608 const std::vector<double>& xl1,
const std::vector<double>& yl1,
2609 const std::vector<double>& xl2,
const std::vector<double>& yl2,
2610 const std::vector<int>& flags1,
const std::vector<int>& links1,
2611 const std::vector<int>& links2, std::vector<bool>& mark1,
int ip1,
int ip2,
2612 const Panel& panel1, std::vector<Panel>& panelsOut)
const {
2616 const unsigned int n1 = xl1.size();
2617 const unsigned int n2 = xl2.size();
2620 const int is1 = ip1;
2621 const int is2 = ip2;
2622 std::vector<double> xpl;
2623 std::vector<double> ypl;
2624 xpl.push_back(xl1[ip1]);
2625 ypl.push_back(yl1[ip1]);
2629 unsigned int il = 1;
2636 std::cout <<
" Start from point " << ip1 <<
" on curve " << il <<
"\n";
2643 const int ii = NextPoint(ip1, n1);
2650 bool inside =
false, edge =
false;
2651 if (links1[ii] >= 0) {
2653 }
else if (flags1[ii] == 1) {
2657 if (inside || edge) {
2658 const double xm = 0.5 * (xl1[ip1] + xl1[ii]);
2659 const double ym = 0.5 * (yl1[ip1] + yl1[ii]);
2663 if (inside || edge) {
2666 std::cout <<
" Continued to point " << ip1 <<
" on " << il
2669 xpl.push_back(xl1[ip1]);
2670 ypl.push_back(yl1[ip1]);
2678 <<
"No point 2 reference found; abandoned.\n";
2683 if (links2[NextPoint(ip2, n2)] == ip1LL &&
2684 links2[PrevPoint(ip2, n2)] == ip1LL) {
2686 <<
"Both 2+ and 2- return on 1; not stored.\n";
2688 }
else if (links2[NextPoint(ip2, n2)] == ip1LL) {
2690 std::cout <<
" 2+ is a return to previous point on 1.\n";
2693 }
else if (links2[PrevPoint(ip2, n2)] == ip1LL) {
2695 std::cout <<
" 2- is a return to previous point on 1.\n";
2699 if (
m_debug) std::cout <<
" Both ways are OK.\n";
2703 if (dir == +1 || dir == 0) {
2704 ip2 = NextPoint(ip2, n2);
2706 if (
m_debug) std::cout <<
" Return to start over 2+.\n";
2711 if (inside || edge) {
2713 std::cout <<
" Going to 2+ (point " << ip2 <<
" of 2).\n";
2715 xpl.push_back(xl2[ip2]);
2716 ypl.push_back(yl2[ip2]);
2718 if (links2[ip2] >= 0) {
2723 std::cout <<
" This point is also on curve 1: " << ip1
2732 ip2 = PrevPoint(ip2, n2);
2735 if (dir == -1 || dir == 0) {
2736 ip2 = PrevPoint(ip2, n2);
2738 if (
m_debug) std::cout <<
" Return to start over 2-\n";
2743 if (inside || edge) {
2745 std::cout <<
" Going to 2- (point " << ip2 <<
" of 2).\n";
2747 xpl.push_back(xl2[ip2]);
2748 ypl.push_back(yl2[ip2]);
2750 if (links2[ip2] >= 0) {
2755 std::cout <<
" This point is also on 1: " << ip1 <<
".\n";
2764 if (
m_debug) std::cout <<
" Dead end.\n";
2766 }
else if (il == 2) {
2770 <<
"Direction not set; abandoned.\n";
2774 ip2 = dir > 0 ? NextPoint(ip2, n2) : PrevPoint(ip2, n2);
2783 std::cout <<
" Stepped over 2 to point " << ip2 <<
" of 2.\n";
2785 xpl.push_back(xl2[ip2]);
2786 ypl.push_back(yl2[ip2]);
2787 if (links2[ip2] >= 0) {
2792 std::cout <<
" This point is also on curve 1: " << ip1 <<
".\n";
2800 if (xpl.size() <= 2) {
2801 if (
m_debug) std::cout <<
" Too few points.\n";
2803 Panel newPanel = panel1;
2806 panelsOut.push_back(std::move(newPanel));
2810 std::cout <<
" End of curve reached, " << xpl.size() <<
" points.\n";
2814bool ComponentNeBem3d::MakePrimitives(
const Panel& panelIn,
2815 std::vector<Panel>& panelsOut)
const {
2822 const double epsang = 1.e-6;
2824 if (panelIn.xv.empty() || panelIn.yv.empty() || panelIn.zv.empty()) {
2829 std::accumulate(std::begin(panelIn.zv), std::end(panelIn.zv), 0.);
2830 const double zmean = zsum / panelIn.zv.size();
2832 std::vector<Panel> stack;
2833 stack.push_back(panelIn);
2834 stack.back().zv.clear();
2835 for (
unsigned int k = 0; k < stack.size(); ++k) {
2837 const auto& xp1 = stack[k].xv;
2838 const auto& yp1 = stack[k].yv;
2839 const unsigned int np = xp1.size();
2841 std::cout <<
" Polygon " << k <<
" with " << np <<
" nodes.\n";
2845 if (
m_debug) std::cout <<
" Too few points.\n";
2851 const double x12 = xp1[0] - xp1[1];
2852 const double y12 = yp1[0] - yp1[1];
2853 const double x23 = xp1[1] - xp1[2];
2854 const double y23 = yp1[1] - yp1[2];
2855 const double x31 = xp1[2] - xp1[0];
2856 const double y31 = yp1[2] - yp1[0];
2857 const double x32 = xp1[2] - xp1[1];
2858 const double y32 = yp1[2] - yp1[1];
2859 const double x13 = xp1[0] - xp1[2];
2860 const double y13 = yp1[0] - yp1[2];
2861 const double x21 = xp1[1] - xp1[0];
2862 const double y21 = yp1[1] - yp1[0];
2863 const double s12 = x12 * x12 + y12 * y12;
2864 const double s32 = x32 * x32 + y32 * y32;
2865 const double s13 = x13 * x13 + y13 * y13;
2866 const double s23 = x23 * x23 + y23 * y23;
2867 const double s31 = x31 * x31 + y31 * y31;
2868 const double s21 = x21 * x21 + y21 * y21;
2869 if (
fabs(x12 * x32 + y12 * y32) < epsang *
sqrt(s12 * s32)) {
2871 std::cout <<
" Right-angled triangle node 2 - done.\n";
2873 panelsOut.push_back(stack[k]);
2875 }
else if (
fabs(x13 * x23 + y13 * y23) < epsang *
sqrt(s13 * s23)) {
2877 std::cout <<
" Right-angled triangle node 3 - rearrange.\n";
2879 Panel panel = stack[k];
2880 panel.xv = {xp1[1], xp1[2], xp1[0]};
2881 panel.yv = {yp1[1], yp1[2], yp1[0]};
2882 panelsOut.push_back(std::move(panel));
2884 }
else if (
fabs(x31 * x21 + y31 * y21) < epsang *
sqrt(s31 * s21)) {
2886 std::cout <<
" Right-angled triangle node 1 - rearrange.\n";
2888 Panel panel = stack[k];
2889 panel.xv = {xp1[2], xp1[0], xp1[1]};
2890 panel.yv = {yp1[2], yp1[0], yp1[1]};
2891 panelsOut.push_back(std::move(panel));
2897 const double x12 = xp1[0] - xp1[1];
2898 const double y12 = yp1[0] - yp1[1];
2899 const double x23 = xp1[1] - xp1[2];
2900 const double y23 = yp1[1] - yp1[2];
2901 const double x34 = xp1[2] - xp1[3];
2902 const double y34 = yp1[2] - yp1[3];
2903 const double x43 = xp1[3] - xp1[2];
2904 const double y43 = yp1[3] - yp1[2];
2905 const double x14 = xp1[0] - xp1[3];
2906 const double y14 = yp1[0] - yp1[3];
2907 const double x32 = xp1[2] - xp1[1];
2908 const double y32 = yp1[2] - yp1[1];
2910 const double s12 = x12 * x12 + y12 * y12;
2911 const double s23 = x23 * x23 + y23 * y23;
2912 const double s32 = x32 * x32 + y32 * y32;
2913 const double s34 = x34 * x34 + y34 * y34;
2914 const double s43 = x43 * x43 + y43 * y43;
2915 const double s14 = x14 * x14 + y14 * y14;
2916 if (
fabs(x12 * x32 + y12 * y32) < epsang *
sqrt(s12 * s32) &&
2917 fabs(x23 * x43 + y23 * y43) < epsang *
sqrt(s23 * s43) &&
2918 fabs(x14 * x34 + y14 * y34) < epsang *
sqrt(s14 * s34)) {
2919 if (
m_debug) std::cout <<
" Rectangle.\n";
2920 panelsOut.push_back(stack[k]);
2925 if (np >= 4 && SplitTrapezium(stack[k], stack, panelsOut, epsang))
continue;
2928 if (
m_debug) std::cout <<
" Trying to find a right-angle\n";
2929 bool corner =
false;
2930 for (
unsigned int ip = 0; ip < np; ++ip) {
2932 const unsigned int inext = NextPoint(ip, np);
2933 const unsigned int iprev = PrevPoint(ip, np);
2935 const double dxprev = xp1[iprev] - xp1[ip];
2936 const double dyprev = yp1[iprev] - yp1[ip];
2937 const double dxnext = xp1[inext] - xp1[ip];
2938 const double dynext = yp1[inext] - yp1[ip];
2939 if (
fabs(dxprev * dxnext + dyprev * dynext) >
2940 epsang *
sqrt((dxprev * dxprev + dyprev * dyprev) *
2941 (dxnext * dxnext + dynext * dynext))) {
2946 const double xm = 0.5 * (xp1[iprev] + xp1[inext]);
2947 const double ym = 0.5 * (yp1[iprev] + yp1[inext]);
2948 bool inside =
false, edge =
false;
2950 if (!inside)
continue;
2954 for (
unsigned int jp = 0; jp < np; ++jp) {
2956 const unsigned int jnext = NextPoint(jp, np);
2957 if (jp == iprev || jp == ip || jp == inext || jnext == iprev ||
2958 jnext == ip || jnext == inext)
2961 double xc = 0., yc = 0.;
2962 if (Crossing(xp1[iprev], yp1[iprev], xp1[inext], yp1[inext], xp1[jp],
2963 yp1[jp], xp1[jnext], yp1[jnext], xc, yc)) {
2968 if (cross)
continue;
2971 std::cout <<
" Cutting at right-angled corner " << ip <<
"\n";
2974 Panel panel = stack[k];
2975 panel.xv = {xp1[iprev], xp1[ip], xp1[inext]};
2976 panel.yv = {yp1[iprev], yp1[ip], yp1[inext]};
2977 stack.push_back(std::move(panel));
2979 stack[k].xv.erase(stack[k].xv.begin() + ip);
2980 stack[k].yv.erase(stack[k].yv.begin() + ip);
2981 stack.push_back(std::move(stack[k]));
2983 std::cout <<
" Going for another pass, NP = " << np <<
"\n";
2987 if (corner)
continue;
2990 if (
m_debug) std::cout <<
" Trying to find a corner\n";
2992 for (
unsigned int ip = 0; ip < np; ++ip) {
2993 const unsigned int iprev = PrevPoint(ip, np);
2994 const unsigned int inext = NextPoint(ip, np);
2997 const double xm = 0.5 * (xp1[iprev] + xp1[inext]);
2998 const double ym = 0.5 * (yp1[iprev] + yp1[inext]);
2999 bool inside =
false, edge =
false;
3001 if (!inside)
continue;
3005 for (
unsigned int jp = 0; jp < np; ++jp) {
3006 const unsigned int jj = NextPoint(jp, np);
3008 if (jp == iprev || jp == ip || jp == inext || jj == iprev || jj == ip ||
3012 double xc = 0., yc = 0.;
3013 if (Crossing(xp1[iprev], yp1[iprev], xp1[inext], yp1[inext], xp1[jp],
3014 yp1[jp], xp1[jj], yp1[jj], xc, yc)) {
3019 if (cross)
continue;
3021 if (
m_debug) std::cout <<
" Cutting at corner " << ip <<
"\n";
3023 const double x1 = xp1[iprev];
3024 const double x2 = xp1[ip];
3025 const double x3 = xp1[inext];
3026 const double y1 = yp1[iprev];
3027 const double y2 = yp1[ip];
3028 const double y3 = yp1[inext];
3029 const double s21 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
3030 const double s31 = (x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1);
3031 const double s32 = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2);
3032 const double s12 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
3033 const double s13 = (x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3);
3034 const double s23 = (x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3);
3037 ((x2 - x1) * (x3 - x1) + (y2 - y1) * (y3 - y1)) /
sqrt(s21 * s31);
3039 ((x3 - x2) * (x1 - x2) + (y3 - y2) * (y1 - y2)) /
sqrt(s32 * s12);
3041 ((x1 - x3) * (x2 - x3) + (y1 - y3) * (y2 - y3)) /
sqrt(s13 * s23);
3043 const double phi1 =
acos(a1);
3044 const double phi2 =
acos(a2);
3045 const double phi3 =
acos(a3);
3046 std::cout <<
" Angles: " << RadToDegree * phi1 <<
", "
3047 << RadToDegree * phi2 <<
", " << RadToDegree * phi3 <<
"\n";
3048 const double sumphi = phi1 + phi2 + phi3;
3049 std::cout <<
" Sum = " << RadToDegree * sumphi <<
"\n";
3052 if (
fabs(a1) < epsang ||
fabs(a2) < epsang ||
fabs(a3) < epsang) {
3053 if (
m_debug) std::cout <<
" Right-angled corner cut off.\n";
3054 Panel panel = stack[k];
3055 if (
fabs(a1) < epsang) {
3056 panel.xv = {x3, x1, x2};
3057 panel.yv = {y3, y1, y2};
3058 }
else if (
fabs(a2) < epsang) {
3059 panel.xv = {x1, x2, x3};
3060 panel.yv = {y1, y2, y3};
3062 panel.xv = {x2, x3, x1};
3063 panel.yv = {y2, y3, y1};
3065 stack.push_back(std::move(panel));
3066 }
else if (a1 <= a2 && a1 <= a3) {
3067 if (
m_debug) std::cout <<
" A1 < A2, A3 - adding 2 triangles.\n";
3068 const double xc = x2 + a2 * (x3 - x2) *
sqrt(s12 / s32);
3069 const double yc = y2 + a2 * (y3 - y2) *
sqrt(s12 / s32);
3070 Panel panel1 = stack[k];
3071 panel1.xv = {x3, xc, x1};
3072 panel1.yv = {y3, yc, y1};
3073 stack.push_back(std::move(panel1));
3074 Panel panel2 = stack[k];
3075 panel2.xv = {x2, xc, x1};
3076 panel2.yv = {y2, yc, y1};
3077 stack.push_back(std::move(panel2));
3078 }
else if (a2 <= a1 && a2 <= a3) {
3079 if (
m_debug) std::cout <<
" A2 < A1, A3 - adding 2 triangles.\n";
3080 const double xc = x3 + a3 * (x1 - x3) *
sqrt(s23 / s13);
3081 const double yc = y3 + a3 * (y1 - y3) *
sqrt(s23 / s13);
3082 Panel panel1 = stack[k];
3083 panel1.xv = {x1, xc, x2};
3084 panel1.yv = {y1, yc, y2};
3085 stack.push_back(std::move(panel1));
3086 Panel panel2 = stack[k];
3087 panel2.xv = {x3, xc, x2};
3088 panel2.yv = {y3, yc, y2};
3089 stack.push_back(std::move(panel2));
3091 if (
m_debug) std::cout <<
" A3 < A1, A2 - adding 2 triangles.\n";
3092 const double xc = x1 + a1 * (x2 - x1) *
sqrt(s31 / s21);
3093 const double yc = y1 + a1 * (y2 - y1) *
sqrt(s31 / s21);
3094 Panel panel1 = stack[k];
3095 panel1.xv = {x1, xc, x3};
3096 panel1.yv = {y1, yc, y3};
3097 stack.push_back(std::move(panel1));
3098 Panel panel2 = stack[k];
3099 panel2.xv = {x2, xc, x3};
3100 panel2.yv = {y2, yc, y3};
3101 stack.push_back(std::move(panel2));
3104 stack[k].xv.erase(stack[k].xv.begin() + ip);
3105 stack[k].yv.erase(stack[k].yv.begin() + ip);
3106 stack.push_back(std::move(stack[k]));
3108 std::cout <<
" Going for another pass, NP = " << np <<
"\n";
3112 if (corner)
continue;
3113 std::cerr <<
m_className <<
"::MakePrimitives:\n "
3114 <<
"Unable to identify a corner to cut, probably a degenerate "
3118 for (
auto& panel : panelsOut) {
3119 panel.zv.assign(panel.xv.size(), zmean);
3124bool ComponentNeBem3d::SplitTrapezium(
const Panel panelIn,
3125 std::vector<Panel>& stack,
3126 std::vector<Panel>& panelsOut,
3127 const double epsang)
const {
3128 const auto xp1 = panelIn.xv;
3129 const auto yp1 = panelIn.yv;
3130 const unsigned int np = xp1.size();
3131 for (
unsigned int ip = 0; ip < np; ++ip) {
3132 const unsigned int inext = NextPoint(ip, np);
3133 const double xi0 = xp1[ip];
3134 const double yi0 = yp1[ip];
3135 const double xi1 = xp1[inext];
3136 const double yi1 = yp1[inext];
3137 const double dxi = xi0 - xi1;
3138 const double dyi = yi0 - yi1;
3139 const double si2 = dxi * dxi + dyi * dyi;
3140 for (
unsigned int jp = ip + 2; jp < np; ++jp) {
3141 const unsigned int jnext = NextPoint(jp, np);
3143 if (ip == jp || ip == jnext || inext == jp || inext == jnext) {
3146 const double xj0 = xp1[jp];
3147 const double yj0 = yp1[jp];
3148 const double xj1 = xp1[jnext];
3149 const double yj1 = yp1[jnext];
3150 const double dxj = xj0 - xj1;
3151 const double dyj = yj0 - yj1;
3152 const double sj2 = dxj * dxj + dyj * dyj;
3154 const double sij =
sqrt(si2 * sj2);
3155 if (
fabs(dxi * dxj + dyi * dyj + sij) > epsang * sij)
continue;
3157 std::cout <<
" Found parallel sections: " << ip <<
", " << jp
3161 if (sj2 <= 0 || si2 <= 0) {
3162 std::cerr <<
m_className <<
"::SplitTrapezium:\n "
3163 <<
"Zero norm segment found; skipped.\n";
3168 ((xi0 - xj0) * (xj1 - xj0) + (yi0 - yj0) * (yj1 - yj0)) / sj2;
3170 ((xi1 - xj0) * (xj1 - xj0) + (yi1 - yj0) * (yj1 - yj0)) / sj2;
3172 ((xj0 - xi0) * (xi1 - xi0) + (yj0 - yi0) * (yi1 - yi0)) / si2;
3174 ((xj1 - xi0) * (xi1 - xi0) + (yj1 - yi0) * (yi1 - yi0)) / si2;
3176 std::cout <<
" xl1 = " << xl1 <<
", xl2 = " << xl2 <<
", "
3177 <<
"xl3 = " << xl3 <<
", xl4 = " << xl4 <<
"\n";
3180 const double r1 = (xl1 + epsang) * (1. + epsang - xl1);
3181 const double r2 = (xl2 + epsang) * (1. + epsang - xl2);
3182 const double r3 = (xl3 + epsang) * (1. + epsang - xl3);
3183 const double r4 = (xl4 + epsang) * (1. + epsang - xl4);
3184 if ((r1 < 0 && r4 < 0) || (r2 < 0 && r3 < 0)) {
3185 if (
m_debug) std::cout <<
" No rectangle.\n";
3189 std::vector<double> xpl(4, 0.);
3190 std::vector<double> ypl(4, 0.);
3194 xpl[1] = xj0 + xl1 * (xj1 - xj0);
3195 ypl[1] = yj0 + xl1 * (yj1 - yj0);
3196 }
else if (r4 >= 0) {
3197 xpl[0] = xi0 + xl4 * (xi1 - xi0);
3198 ypl[0] = yi0 + xl4 * (yi1 - yi0);
3203 xpl[2] = xj0 + xl2 * (xj1 - xj0);
3204 ypl[2] = yj0 + xl2 * (yj1 - yj0);
3207 }
else if (r3 >= 0) {
3210 xpl[3] = xi0 + xl3 * (xi1 - xi0);
3211 ypl[3] = yi0 + xl3 * (yi1 - yi0);
3214 double xm = 0.5 * (xpl[0] + xpl[1]);
3215 double ym = 0.5 * (ypl[0] + ypl[1]);
3216 bool inside =
false, edge =
false;
3218 if (!(inside || edge)) {
3219 if (
m_debug) std::cout <<
" Midpoint 1 not internal.\n";
3222 xm = 0.5 * (xpl[2] + xpl[3]);
3223 ym = 0.5 * (ypl[2] + ypl[3]);
3225 if (!(inside || edge)) {
3226 if (
m_debug) std::cout <<
" Midpoint 2 not internal.\n";
3230 const unsigned int iprev = PrevPoint(ip, np);
3231 const unsigned int jprev = PrevPoint(jp, np);
3234 for (
unsigned int i = 0; i < np; ++i) {
3235 if ((i == iprev && r1 >= 0) || i == ip || (i == inext && r2 >= 0) ||
3236 (i == jprev && r3 >= 0) || i == jp || (i == jnext && r4 >= 0))
3238 const unsigned int ii = NextPoint(i, np);
3239 double xc = 0., yc = 0.;
3240 if (Crossing(xp1[i], yp1[i], xp1[ii], yp1[ii], xpl[0], ypl[0], xpl[1],
3242 Crossing(xp1[i], yp1[i], xp1[ii], yp1[ii], xpl[2], ypl[2], xpl[3],
3245 std::cout <<
" Crossing (edge " << i <<
", " << ii
3246 <<
"), ip = " << ip <<
", jp = " << jp <<
"\n";
3252 if (cross)
continue;
3254 if ((
fabs(xl1) < epsang &&
fabs(xl3) < epsang) ||
3255 (
fabs(1. - xl2) < epsang &&
fabs(1. - xl4) < epsang)) {
3256 if (
m_debug) std::cout <<
" Not stored, degenerate.\n";
3258 if (
m_debug) std::cout <<
" Adding rectangle.\n";
3259 Panel panel = panelIn;
3262 panelsOut.push_back(std::move(panel));
3267 if (
m_debug) std::cout <<
" First non-rectangular section.\n";
3268 for (
unsigned int i = jp + 1; i <= ip + np; ++i) {
3269 const unsigned int ii = i % np;
3270 xpl.push_back(xp1[ii]);
3271 ypl.push_back(yp1[ii]);
3273 if (r1 >= 0 && r4 >= 0) {
3274 if (
m_debug) std::cout <<
" 1-4 degenerate\n";
3275 }
else if (r1 >= 0) {
3276 if (
m_debug) std::cout <<
" Using 1\n";
3277 xpl.push_back(xj0 + xl1 * (xj1 - xj0));
3278 ypl.push_back(yj0 + xl1 * (yj1 - yj0));
3279 }
else if (r4 >= 0) {
3280 if (
m_debug) std::cout <<
" Using 4\n";
3281 xpl.push_back(xi0 + xl4 * (xi1 - xi0));
3282 ypl.push_back(yi0 + xl4 * (yi1 - yi0));
3284 if (
m_debug) std::cout <<
" Neither 1 nor 4, should not happen\n";
3286 if (xpl.size() < 3) {
3288 std::cout <<
" Not stored, only " << xpl.size()
3293 std::cout <<
" Adding non-rectangular part with " << xpl.size()
3296 Panel panel = panelIn;
3299 stack.push_back(std::move(panel));
3304 if (
m_debug) std::cout <<
" Second non-rectangular section.\n";
3305 for (
unsigned int i = ip + 1; i <= jp; ++i) {
3306 const unsigned int ii = i % np;
3307 xpl.push_back(xp1[ii]);
3308 ypl.push_back(yp1[ii]);
3310 if (r2 >= 0 && r3 >= 0) {
3311 if (
m_debug) std::cout <<
" 2-3 degenerate\n";
3312 }
else if (r2 >= 0) {
3313 if (
m_debug) std::cout <<
" Using 2\n";
3314 xpl.push_back(xj0 + xl2 * (xj1 - xj0));
3315 ypl.push_back(yj0 + xl2 * (yj1 - yj0));
3316 }
else if (r3 >= 0) {
3317 if (
m_debug) std::cout <<
" Using 3\n";
3318 xpl.push_back(xi0 + xl3 * (xi1 - xi0));
3319 ypl.push_back(yi0 + xl3 * (yi1 - yi0));
3321 if (
m_debug) std::cout <<
" Neither 2 nor 3, should not happen\n";
3323 if (xpl.size() < 3) {
3325 std::cout <<
" Not stored, only " << xpl.size()
3330 std::cout <<
" Adding non-rectangular part with " << xpl.size()
3333 Panel panel = panelIn;
3336 stack.push_back(std::move(panel));
3345 double& c, std::vector<double>& xv,
3346 std::vector<double>& yv,
3347 std::vector<double>& zv,
int& interface,
3348 double& v,
double& q,
3349 double& lambda)
const {
3350 if (i >= m_primitives.size()) {
3351 std::cerr <<
m_className <<
"::GetPrimitive: Index out of range.\n";
3354 const auto& primitive = m_primitives[i];
3361 interface = primitive.interface;
3364 lambda = primitive.lambda;
3369 double& c, std::vector<double>& xv,
3370 std::vector<double>& yv,
3371 std::vector<double>& zv,
int& vol1,
3373 if (i >= m_primitives.size()) {
3374 std::cerr <<
m_className <<
"::GetPrimitive: Index out of range.\n";
3377 const auto& primitive = m_primitives[i];
3384 vol1 = primitive.vol1;
3385 vol2 = primitive.vol2;
3390 int& material,
double& epsilon,
3391 double& potential,
double& charge,
int& bc) {
3393 const unsigned int nSolids =
m_geometry->GetNumberOfSolids();
3394 for (
unsigned int i = 0; i < nSolids; ++i) {
3395 Medium* medium =
nullptr;
3396 const auto solid =
m_geometry->GetSolid(i, medium);
3397 if (!solid)
continue;
3398 if (solid->GetId() != vol)
continue;
3399 if (solid->IsTube() || solid->IsWire()) {
3401 }
else if (solid->IsHole()) {
3403 }
else if (solid->IsBox()) {
3405 }
else if (solid->IsSphere()) {
3407 }
else if (solid->IsRidge()) {
3409 }
else if (solid->IsExtrusion()) {
3412 std::cerr <<
m_className <<
"::GetVolume: Unknown solid shape.\n";
3415 material = medium ? medium->
GetId() : 11;
3417 potential = solid->GetBoundaryPotential();
3418 charge = solid->GetBoundaryChargeDensity();
3419 bc = solid->GetBoundaryConditionType();
3428 const unsigned int nSolids =
m_geometry->GetNumberOfSolids();
3429 for (
unsigned int i = 0; i < nSolids; ++i) {
3430 Medium* medium =
nullptr;
3431 const auto solid =
m_geometry->GetSolid(i, medium);
3432 if (!solid)
continue;
3433 if (solid->IsInside(x, y, z))
return solid->GetId();
3439 std::vector<double>& yv,
3440 std::vector<double>& zv,
int& interface,
3441 double& bc,
double& lambda)
const {
3442 if (i >= m_elements.size()) {
3443 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
3446 const auto& element = m_elements[i];
3450 interface = element.interface;
3452 lambda = element.lambda;
3457 m_primitives.clear();
3459 m_ynplan.fill(
false);
3466 for (
unsigned int i = 0; i < 3; ++i) {
3469 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
3470 <<
" Both simple and mirror periodicity requested. Reset.\n";
3476 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
3477 <<
" Periodic length is not set. Reset.\n";
3483 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
3484 <<
" Axial periodicity is not available.\n";
3490 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
3491 <<
" Rotation symmetry is not available.\n";
bool GetPlaneZ(const unsigned int i, double &z, double &v) const
Retrieve the parameters of a plane at constant z.
bool GetPlaneY(const unsigned int i, double &y, double &v) const
Retrieve the parameters of a plane at constant y.
void SetSystemChargeZero(const unsigned int OptSystemChargeZero)
void AddPlaneZ(const double z, const double voltage)
Add a plane at constant z.
ComponentNeBem3d()
Constructor.
bool GetPeriodicityX(double &s) const
Get the periodic length in the x-direction.
void SetFastVolBlocks(const unsigned int NbBlocksFV)
void SetStoreElements(const unsigned int OptStoreElements)
void SetWtFldFastVolVersion(const unsigned int IdWtField, const unsigned int VersionWtFldFV)
bool GetPeriodicityZ(double &s) const
Get the periodic length in the z-direction.
void Reset() override
Reset the component.
void SetUnformattedFile(const unsigned int OptUnformattedFile)
void SetMirrorPeriodicityX(const double s)
Set the periodic length [cm] in the x-direction.
void SetPeriodicityX(const double s)
Set the periodic length [cm] in the x-direction.
void SetWtFldFastVolOptions(const unsigned int IdWtField, const unsigned int OptWtFldFastVol, const unsigned int OptCreateWtFldFastPF, const unsigned int OptReadWtFldFastPF)
void UpdatePeriodicity() override
Verify periodicities.
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
void SetStoreReadOptions(const unsigned int OptStoreInflMatrix, const unsigned int OptReadInflMatrix, const unsigned int OptStoreInvMatrix, const unsigned int OptReadInvMatrix, const unsigned int OptStorePrimitives, const unsigned int OptReadPrimitives, const unsigned int OptStoreElements, const unsigned int OptReadElements, const unsigned int OptFormattedFile, const unsigned int OptUnformattedFile)
unsigned int GetNumberOfPlanesY() const
Get the number of equipotential planes at constant y.
bool GetPeriodicityY(double &s) const
Get the periodic length in the y-direction.
void SetReadPrimitives(const unsigned int OptReadPrimitives)
unsigned int GetNumberOfPlanesZ() const
Get the number of equipotential planes at constant z.
void SetReadInvMatrix(const unsigned int OptReadInvMatrix)
void AddPlaneY(const double y, const double voltage)
Add a plane at constant y.
void AddPlaneX(const double x, const double voltage)
Add a plane at constant x.
void SetForceValidation(const unsigned int OptForceValidation)
void SetRepeatLHMatrix(const unsigned int OptRepeatLHMatrix)
void SetValidateSolution(const unsigned int OptValidateSolution)
void SetMirrorPeriodicityZ(const double s)
Set the periodic length [cm] in the z-direction.
void SetPeriodicityZ(const double s)
Set the periodic length [cm] in the z-direction.
bool GetVolume(const unsigned int vol, int &shape, int &material, double &eps, double &potential, double &charge, int &bc)
void SetPeriodicityY(const double s)
Set the periodic length [cm] in the y-direction.
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
void SetNewMesh(const unsigned int NewMesh)
unsigned int GetNumberOfPlanesX() const
Get the number of equipotential planes at constant x.
bool GetElement(const unsigned int i, std::vector< double > &xv, std::vector< double > &yv, std::vector< double > &zv, int &interface, double &bc, double &lambda) const
void SetTargetElementSize(const double length)
void SetStoreInvMatrix(const unsigned int OptStoreInvMatrix)
void SetWtFldFastVolBlocks(const unsigned int IdWtField, const unsigned int NbBlocksWtFldFV)
void SetMirrorPeriodicityY(const double s)
Set the periodic length [cm] in the y-direction.
void SetPeriodicCopies(const unsigned int nx, const unsigned int ny, const unsigned int nz)
void SetComputeOptions(const unsigned int OptSystemChargeZero, const unsigned int OptValidateSolution, const unsigned int OptForceValidation, const unsigned int OptRepeatLHMatrix)
bool GetPrimitive(const unsigned int i, double &a, double &b, double &c, std::vector< double > &xv, std::vector< double > &yv, std::vector< double > &zv, int &interface, double &v, double &q, double &lambda) const
void SetFastVolOptions(const unsigned int OptFastVol, const unsigned int OptCreateFastPF, const unsigned int OptReadFastPF)
void SetMinMaxNumberOfElements(const unsigned int nmin, const unsigned int nmax)
void SetReadInflMatrix(const unsigned int OptReadInflMatrix)
void SetChargingUpOptions(const unsigned int OptChargingUp)
void SetNewBC(const unsigned int NewBC)
void SetModelOptions(const unsigned int NewModel, const unsigned int NewMesh, const unsigned int NewBC, const unsigned int NewPP)
void SetFastVolVersion(const unsigned int VersionFV)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
void SetStoreInflMatrix(const unsigned int OptStoreInflMatrix)
void SetNewPP(const unsigned int NewPP)
void SetNewModel(const unsigned int NewModel)
void SetReadElements(const unsigned int OptReadElements)
bool GetPlaneX(const unsigned int i, double &x, double &v) const
Retrieve the parameters of a plane at constant x.
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
void SetKnownChargeOptions(const unsigned int OptKnownCharge)
void SetStorePrimitives(const unsigned int OptStorePrimitives)
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
void SetFormattedFile(const unsigned int OptFormattedFile)
std::array< bool, 3 > m_rotationSymmetric
Rotation symmetry around x-axis, y-axis, z-axis.
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
bool m_debug
Switch on/off debugging messages.
Component()=delete
Default constructor.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
std::string m_className
Class name.
Geometry * m_geometry
Pointer to the geometry.
bool m_ready
Ready for use?
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
Abstract base class for media.
double GetDielectricConstant() const
Get the relative static dielectric constant.
int GetId() const
Return the id number of the class instance.
virtual bool IsConductor() const
Is this medium a conductor?
bool IsDriftable() const
Is charge carrier transport enabled in this medium?
void Inside(const std::vector< double > &xpl, const std::vector< double > &ypl, const double x, const double y, bool &inside, bool &edge)
ComponentNeBem3d * gComponentNeBem3d
DoubleAc acos(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)
neBEMGLOBAL int OptRepeatLHMatrix
neBEMGLOBAL int OptReadPrimitives
neBEMGLOBAL int OptStorePrimitives
neBEMGLOBAL int OptFormattedFile
neBEMGLOBAL int OptChargingUp
neBEMGLOBAL int OptWtFldFastVol[MAXWtFld]
neBEMGLOBAL int NbBlocksWtFldFV[MAXWtFld]
neBEMGLOBAL int VersionFV
neBEMGLOBAL int OptCreateFastPF
neBEMGLOBAL double * Lambda
neBEMGLOBAL int OptSystemChargeZero
neBEMGLOBAL int OptCreateWtFldFastPF[MAXWtFld]
neBEMGLOBAL int OptFastVol
neBEMGLOBAL int * InterfaceType
neBEMGLOBAL int OptReadFastPF
neBEMGLOBAL int OptStoreInflMatrix
neBEMGLOBAL int OptReadInflMatrix
neBEMGLOBAL int OptForceValidation
neBEMGLOBAL int OptUnformattedFile
neBEMGLOBAL int OptReadInvMatrix
neBEMGLOBAL int NbBlocksFV
neBEMGLOBAL int VersionWtFldFV[MAXWtFld]
neBEMGLOBAL int OptValidateSolution
neBEMGLOBAL int OptReadElements
neBEMGLOBAL int OptStoreElements
neBEMGLOBAL int OptStoreInvMatrix
neBEMGLOBAL int OptReadWtFldFastPF[MAXWtFld]
std::vector< double > zv
Z-coordinates of vertices.
int volume
Reference to solid to which the panel belongs.
double a
Perpendicular vector.
std::vector< double > xv
X-coordinates of vertices.
std::vector< double > yv
Y-coordinates of vertices.