25 const double z,
double& ex,
double& ey,
26 double& ez,
double& volt,
Medium*& m,
int& status) {
32 const double zin,
double& ex,
double& ey,
33 double& ez,
Medium*& m,
int& status) {
38 status =
Field(xin, yin, zin, ex, ey, ez, iel,
m_pot);
39 if (status < 0 || iel < 0) {
49 <<
"Out-of-range material number.\n";
57 std::cout <<
" Material " << element.matmap <<
", drift flag "
58 << mat.driftmedium <<
".\n";
62 if (mat.driftmedium) {
68 const double zin,
double& fx,
double& fy,
69 double& fz,
int& imap,
70 const std::vector<double>& pot)
const {
76 double x = xin, y = yin;
77 double z =
m_is3d ? zin : 0.;
80 bool xmirr, ymirr, zmirr;
81 double rcoordinate, rotation;
82 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
91 double t1 = 0., t2 = 0., t3 = 0., t4 = 0.;
104 << x <<
", " << y <<
", " << z <<
") is not in the mesh.\n";
112 std::array<double, 6> v;
113 for (
size_t i = 0; i < 6; ++i) v[i] = pot[element.
emap[i]];
114 Field3(v, {t1, t2, t3}, jac, det, fx, fy);
116 std::array<double, 8> v;
117 for (
size_t i = 0; i < 8; ++i) v[i] = pot[element.
emap[i]];
118 Field5(v, {t1, t2}, jac, det, fx, fy);
121 std::array<double, 10> v;
122 for (
size_t i = 0; i < 10; ++i) v[i] = pot[element.
emap[i]];
123 Field13(v, {t1, t2, t3, t4}, jac, 4 * det, fx, fy, fz);
126 PrintElement(
"Field", x, y, z, t1, t2, t3, t4, imap, pot);
129 UnmapFields(fx, fy, fz, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
135 const std::vector<double>& pot)
const {
141 double x = xin, y = yin;
142 double z =
m_is3d ? zin : 0.;
145 bool xmirr, ymirr, zmirr;
146 double rcoordinate, rotation;
147 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
156 double t1 = 0., t2 = 0., t3 = 0., t4 = 0.;
165 if (imap < 0)
return 0.;
171 std::array<double, 6> v;
172 for (
size_t i = 0; i < 6; ++i) v[i] = pot[element.
emap[i]];
175 std::array<double, 8> v;
176 for (
size_t i = 0; i < 8; ++i) v[i] = pot[element.
emap[i]];
180 std::array<double, 10> v;
181 for (
size_t i = 0; i < 10; ++i) v[i] = pot[element.
emap[i]];
185 PrintElement(
"Potential", x, y, z, t1, t2, t3, t4, imap, pot);
191 const double zin,
double& wx,
double& wy,
192 double& wz,
const std::string& label) {
200 if (
m_wpot.count(label) == 0)
return;
201 if (
m_wpot[label].empty())
return;
204 Field(xin, yin, zin, wx, wy, wz, iel,
m_wpot[label]);
208 const std::string& label0) {
215 std::string label = label0;
228 if (
m_wpot.count(label) == 0)
return 0.;
229 if (
m_wpot[label].empty())
return 0.;
237 const std::string& label0) {
247 std::string label = label0;
261 if (
m_dwpot.count(label) == 0)
return 0.;
262 if (
m_dwpot[label].empty())
return 0.;
265 double x = xin, y = yin, z = zin;
268 bool xmirr, ymirr, zmirr;
269 double rcoordinate, rotation;
270 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
275 double t1, t2, t3, t4, jac[4][4], det;
283 if (imap < 0)
return 0.;
299 std::array<double, 6> v0, v1;
300 for (
size_t i = 0; i < 6; ++i) {
307 std::array<double, 8> v0, v1;
308 for (
size_t i = 0; i < 8; ++i) {
316 std::array<double, 10> v0, v1;
317 for (
size_t i = 0; i < 10; ++i) {
325 return f0 * dp0 + f1 * dp1;
331 double x = xin, y = yin;
332 double z =
m_is3d ? zin : 0.;
335 bool xmirr, ymirr, zmirr;
336 double rcoordinate, rotation;
337 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
353 double t1 = 0., t2 = 0., t3 = 0., t4 = 0.;
364 std::cerr <<
m_className <<
"::GetMedium: (" << x <<
", " << y <<
", "
365 << z <<
") is not in the mesh.\n";
372 std::cerr <<
m_className <<
"::GetMedium: Element " << imap
373 <<
" has out-of-range material number " << element.
matmap
395 double vmin = 0., vmax = 0.;
396 for (
size_t i = 0; i < nElements; ++i) {
401 vmin = std::min(vmin, v);
402 vmax = std::max(vmax, v);
406 constexpr int nBins = 100;
408 std::string unit =
"cm";
413 }
else if (vmax < 1.e-3) {
421 }
else if (vmax < 1.e-2) {
429 vmin = std::max(0., vmin - 0.1 * (vmax - vmin));
430 vmax = vmax + 0.1 * (vmax - vmin);
432 vmin -= 1. + std::abs(vmin);
433 vmax += 1. + std::abs(vmax);
436 std::string title =
m_is3d ?
";volume [" :
";surface [";
447 TH1F hElementVolume(
"hElementVolume", title.c_str(), nBins, vmin, vmax);
449 TH1F hAspectRatio(
"hAspectRatio",
";largest / smallest vertex distance;",
454 double rmin = 0., rmax = 0.;
455 for (
size_t i = 0; i < nElements; ++i) {
456 double v = 0., dmin = 0., dmax = 0.;
457 if (!
GetElement(i, v, dmin, dmax))
return false;
461 <<
" Found element with zero-length vertex separation.\n";
464 const double r = dmax / dmin;
465 hAspectRatio.Fill(r);
466 if (v <= 0.) ++nZero;
468 hElementVolume.Fill(v);
474 vmin = std::min(vmin, v);
475 vmax = std::max(vmax, v);
476 rmin = std::min(rmin, r);
477 rmax = std::max(rmax, r);
483 std::cerr <<
" Found " << nZero <<
" element(s) with zero volume.\n";
485 std::cerr <<
" Found " << nZero <<
" element(s) with zero surface.\n";
488 TCanvas* c1 =
new TCanvas(
"cAspectRatio",
"Aspect ratio", 600, 600);
490 hAspectRatio.DrawCopy();
492 TCanvas* c2 =
new TCanvas(
"cElementVolume",
"Element measure", 600, 600);
494 hElementVolume.DrawCopy();
499 <<
" Smallest Largest\n";
500 std::printf(
" Aspect ratios: %15.8f %15.8f\n", rmin, rmax);
502 std::printf(
" Volumes [%s3]: %15.8f %15.8f\n", unit.c_str(), vmin,
505 std::printf(
" Surfaces [%s2]: %15.8f %15.8f\n", unit.c_str(), vmin,
517 <<
" No materials are currently defined.\n";
523 <<
" Currently " << nMaterials <<
" materials are defined.\n"
524 <<
" Index Permittivity Resistivity Notes\n";
525 for (
size_t i = 0; i < nMaterials; ++i) {
528 std::string name =
m_materials[i].medium->GetName();
529 std::cout <<
" " << name;
530 if (
m_materials[i].medium->IsDriftable()) std::cout <<
", drift medium";
531 if (
m_materials[i].medium->IsIonisable()) std::cout <<
", ionisable";
534 std::cout <<
" (drift medium)\n";
547 std::cerr <<
m_className <<
"::DriftMedium: Index out of range.\n";
561 std::cerr <<
m_className <<
"::NotDriftMedium: Index out of range.\n";
571 std::cerr <<
m_className <<
"::GetPermittivity: Index out of range.\n";
579 std::cerr <<
m_className <<
"::GetConductivity: Index out of range.\n";
587 std::cerr <<
m_className <<
"::SetMedium: Index out of range.\n";
591 std::cerr <<
m_className <<
"::SetMedium: Null pointer.\n";
595 std::cout <<
m_className <<
"::SetMedium: Associated material " << imat
596 <<
" with medium " << medium->
GetName() <<
".\n";
603 std::cerr <<
m_className <<
"::GetMedium: Index out of range.\n";
611 std::cerr <<
m_className <<
"::SetGas: Null pointer.\n";
616 for (
size_t i = 0; i < nMaterials; ++i) {
617 if (fabs(
m_materials[i].eps - 1.) > 1.e-4)
continue;
619 std::cout <<
m_className <<
"::SetGas: Associating material " << i
620 <<
" with " << medium->
GetName() <<
".\n";
624 std::cerr <<
m_className <<
"::SetGas: Found no material with eps = 1.\n";
629 double& dmax)
const {
631 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
651 const double vol = (n3.
x - n0.
x) * ((n1.
y - n0.
y) * (n2.
z - n0.
z) -
652 (n2.
y - n0.
y) * (n1.
z - n0.
z)) +
653 (n3.
y - n0.
y) * ((n1.
z - n0.
z) * (n2.
x - n0.
x) -
654 (n2.
z - n0.
z) * (n1.
x - n0.
x)) +
655 (n3.
z - n0.
z) * ((n1.
x - n0.
x) * (n2.
y - n0.
y) -
656 (n3.
x - n0.
x) * (n1.
y - n0.
y));
657 return fabs(vol) / 6.;
663 const double surf = 0.5 *
664 (fabs((n1.
x - n0.
x) * (n2.
y - n0.
y) - (n2.
x - n0.
x) * (n1.
y - n0.
y)) +
665 fabs((n3.
x - n0.
x) * (n2.
y - n0.
y) - (n2.
x - n0.
x) * (n3.
y - n0.
y)));
672 double& dmax)
const {
682 for (
int j = 0; j < np - 1; ++j) {
684 for (
int k = j + 1; k < np; ++k) {
687 const double dx = nj.
x - nk.
x;
688 const double dy = nj.
y - nk.
y;
689 const double dz = nj.
z - nk.
z;
690 const double dist = sqrt(dx * dx + dy * dy + dz * dz);
694 if (dist < dmin) dmin = dist;
695 if (dist > dmax) dmax = dist;
702 for (
int j = 0; j < np - 1; ++j) {
704 for (
int k = j + 1; k < np; ++k) {
707 const double dx = nj.
x - nk.
x;
708 const double dy = nj.
y - nk.
y;
709 const double dist = sqrt(dx * dx + dy * dy);
713 if (dist < dmin) dmin = dist;
714 if (dist > dmax) dmax = dist;
722 std::vector<size_t>& nodes)
const {
724 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
728 mat = element.matmap;
734 nodes.resize(nNodes);
735 for (
size_t j = 0; j < nNodes; ++j) nodes[j] = element.emap[j];
742 std::cerr <<
m_className <<
"::GetNode: Index out of range.\n";
760 for (
size_t i = 0; i < nMaterials; ++i) {
765 std::cerr <<
m_className <<
"::SetDefaultDriftMedium:\n"
766 <<
" Material " << i <<
" has zero permittivity.\n";
768 }
else if (epsmin < 0. || epsmin >
m_materials[i].eps) {
774 std::cerr <<
m_className <<
"::SetDefaultDriftMedium:\n"
775 <<
" Found no material with positive permittivity.\n";
783 const std::array<double, 3>& t) {
785 for (
size_t i = 0; i < 3; ++i) {
786 sum += v[i] * t[i] * (2 * t[i] - 1);
788 sum += 4 * (v[3] * t[0] * t[1] + v[4] * t[0] * t[2] + v[5] * t[1] * t[2]);
793 const std::array<double, 3>& t,
double jac[4][4],
794 const double det,
double& ex,
double& ey) {
795 std::array<double, 3> g;
796 g[0] = v[0] * (4 * t[0] - 1) + v[3] * 4 * t[1] + v[4] * 4 * t[2];
797 g[1] = v[1] * (4 * t[1] - 1) + v[3] * 4 * t[0] + v[5] * 4 * t[2];
798 g[2] = v[2] * (4 * t[2] - 1) + v[4] * 4 * t[0] + v[5] * 4 * t[1];
799 const double invdet = 1. / det;
800 ex = -(jac[0][1] * g[0] + jac[1][1] * g[1] + jac[2][1] * g[2]) * invdet;
801 ey = -(jac[0][2] * g[0] + jac[1][2] * g[1] + jac[2][2] * g[2]) * invdet;
805 const std::array<double, 2>& t) {
806 return -v[0] * (1 - t[0]) * (1 - t[1]) * (1 + t[0] + t[1]) * 0.25 -
807 v[1] * (1 + t[0]) * (1 - t[1]) * (1 - t[0] + t[1]) * 0.25 -
808 v[2] * (1 + t[0]) * (1 + t[1]) * (1 - t[0] - t[1]) * 0.25 -
809 v[3] * (1 - t[0]) * (1 + t[1]) * (1 + t[0] - t[1]) * 0.25 +
810 v[4] * (1 - t[0]) * (1 + t[0]) * (1 - t[1]) * 0.5 +
811 v[5] * (1 + t[0]) * (1 + t[1]) * (1 - t[1]) * 0.5 +
812 v[6] * (1 - t[0]) * (1 + t[0]) * (1 + t[1]) * 0.5 +
813 v[7] * (1 - t[0]) * (1 + t[1]) * (1 - t[1]) * 0.5;
817 const std::array<double, 2>& t,
double jac[4][4],
818 const double det,
double& ex,
double& ey) {
819 std::array<double, 2> g;
820 g[0] = (v[0] * (1 - t[1]) * (2 * t[0] + t[1]) +
821 v[1] * (1 - t[1]) * (2 * t[0] - t[1]) +
822 v[2] * (1 + t[1]) * (2 * t[0] + t[1]) +
823 v[3] * (1 + t[1]) * (2 * t[0] - t[1])) *
825 v[4] * t[0] * (t[1] - 1) + v[5] * (1 - t[1]) * (1 + t[1]) * 0.5 -
826 v[6] * t[0] * (1 + t[1]) + v[7] * (t[1] - 1) * (t[1] + 1) * 0.5;
827 g[1] = (v[0] * (1 - t[0]) * (t[0] + 2 * t[1]) -
828 v[1] * (1 + t[0]) * (t[0] - 2 * t[1]) +
829 v[2] * (1 + t[0]) * (t[0] + 2 * t[1]) -
830 v[3] * (1 - t[0]) * (t[0] - 2 * t[1])) *
832 v[4] * (t[0] - 1) * (t[0] + 1) * 0.5 - v[5] * (1 + t[0]) * t[1] +
833 v[6] * (1 - t[0]) * (1 + t[0]) * 0.5 + v[7] * (t[0] - 1) * t[1];
834 const double invdet = 1. / det;
835 ex = -(g[0] * jac[0][0] + g[1] * jac[1][0]) * invdet;
836 ey = -(g[0] * jac[0][1] + g[1] * jac[1][1]) * invdet;
840 const std::array<double, 4>& t) {
842 for (
size_t i = 0; i < 4; ++i) {
843 sum += v[i] * t[i] * (t[i] - 0.5);
846 sum += 4 * (v[4] * t[0] * t[1] + v[5] * t[0] * t[2] + v[6] * t[0] * t[3] +
847 v[7] * t[1] * t[2] + v[8] * t[1] * t[3] + v[9] * t[2] * t[3]);
852 const std::array<double, 4>& t,
853 double jac[4][4],
const double det,
double& ex,
854 double& ey,
double& ez) {
855 std::array<double, 4> g;
856 g[0] = v[0] * (t[0] - 0.25) + v[4] * t[1] + v[5] * t[2] + v[6] * t[3];
857 g[1] = v[1] * (t[1] - 0.25) + v[4] * t[0] + v[7] * t[2] + v[8] * t[3];
858 g[2] = v[2] * (t[2] - 0.25) + v[5] * t[0] + v[7] * t[1] + v[9] * t[3];
859 g[3] = v[3] * (t[3] - 0.25) + v[6] * t[0] + v[8] * t[1] + v[9] * t[2];
860 std::array<double, 3> f = {0., 0., 0.};
861 for (
size_t j = 0; j < 4; ++j) {
862 for (
size_t i = 0; i < 3; ++i) {
863 f[i] += g[j] * jac[j][i + 1];
872 double& t1,
double& t2,
873 double& t3,
double& t4,
double jac[4][4],
876 double jacbak[4][4], detbak = 1.;
877 double t1bak = 0., t2bak = 0., t3bak = 0., t4bak = 0.;
881 t1 = t2 = t3 = t4 = 0;
886 std::array<double, 8> xn;
887 std::array<double, 8> yn;
888 const auto& elements = (m_useTetrahedralTree && m_octree) ?
889 m_octree->GetElementsInBlock(
Vec3(x, y, 0.)) :
891 for (
const auto i : elements) {
897 for (
size_t j = 0; j < 6; ++j) {
902 if (Coordinates3(x, y, t1, t2, t3, t4, jac, det, xn, yn) != 0) {
905 if (t1 < 0 || t1 > 1 || t2 < 0 || t2 > 1 || t3 < 0 || t3 > 1)
continue;
908 for (
size_t j = 0; j < 8; ++j) {
913 if (Coordinates5(x, y, t1, t2, t3, t4, jac, det, xn, yn) != 0) {
916 if (t1 < -1 || t1 > 1 || t2 < -1 || t2 > 1)
continue;
923 std::cout <<
" Found matching degenerate element ";
925 std::cout <<
" Found matching non-degenerate element ";
927 std::cout << i <<
".\n";
929 if (!m_checkMultipleElement)
return i;
930 for (
int j = 0; j < 4; ++j) {
931 for (
int k = 0; k < 4; ++k) jacbak[j][k] = jac[j][k];
942 if (m_checkMultipleElement) {
946 <<
" No element matching point (" << x <<
", " << y
953 <<
" Found " << nfound <<
" elements matching point ("
954 << x <<
", " << y <<
").\n";
956 for (
int j = 0; j < 4; ++j) {
957 for (
int k = 0; k < 4; ++k) jac[j][k] = jacbak[j][k];
970 <<
" No element matching point (" << x <<
", " << y
977 const double x,
const double y,
const double z,
978 double& t1,
double& t2,
double& t3,
double& t4,
979 double jac[4][4],
double& det)
const {
984 double t1bak = 0., t2bak = 0., t3bak = 0., t4bak = 0.;
988 t1 = t2 = t3 = t4 = 0.;
993 std::array<double, 10> xn;
994 std::array<double, 10> yn;
995 std::array<double, 10> zn;
996 const auto& elements = (m_useTetrahedralTree && m_octree) ?
998 for (
const auto i : elements) {
1003 for (
size_t j = 0; j < 10; ++j) {
1009 if (Coordinates13(x, y, z, t1, t2, t3, t4, jac, det, xn, yn, zn,
m_w12[i]) != 0) {
1012 if (t1 < 0 || t1 > 1 || t2 < 0 || t2 > 1 || t3 < 0 || t3 > 1 || t4 < 0 ||
1018 <<
" Found matching element " << i <<
".\n";
1020 if (!m_checkMultipleElement)
return i;
1023 for (
int j = 0; j < 4; ++j) {
1024 for (
int k = 0; k < 4; ++k) jacbak[j][k] = jac[j][k];
1035 if (m_checkMultipleElement) {
1039 <<
" No element matching point ("
1040 << x <<
", " << y <<
", " << z <<
") found.\n";
1046 <<
" Found << " << nfound <<
" elements matching point ("
1047 << x <<
", " << y <<
", " << z <<
").\n";
1049 for (
int j = 0; j < 4; ++j) {
1050 for (
int k = 0; k < 4; ++k) jac[j][k] = jacbak[j][k];
1062 <<
" No element matching point (" << x <<
", " << y <<
", "
1063 << z <<
") found.\n";
1069 const double z,
double& t1,
double& t2,
1070 double& t3, TMatrixD*& jac,
1071 std::vector<TMatrixD*>& dN)
const {
1074 for (
size_t i = 0; i < nElements; ++i) {
1077 if (x < n3.
x || y < n3.
y || z < n3.
z)
continue;
1081 if (x < n0.
x && y < n2.
y && z < n7.
z) {
1089 std::cout <<
m_className <<
"::FindElementCube:\n"
1090 <<
" Point (" << x <<
"," << y <<
"," << z
1091 <<
") not in the mesh, it is background or PEC.\n";
1096 std::cout <<
" First node (" << first3.
x <<
"," << first3.
y <<
","
1097 << first3.
z <<
") in the mesh.\n";
1098 std::cout <<
" dx= " << (first0.
x - first3.
x)
1099 <<
", dy= " << (first2.
y - first3.
y)
1100 <<
", dz= " << (first7.
z - first3.
z) <<
"\n";
1106 std::cout <<
" Last node (" << last5.
x <<
"," << last5.
y <<
","
1107 << last5.
z <<
") in the mesh.\n";
1108 std::cout <<
" dx= " << (last0.
x - last3.
x)
1109 <<
", dy= " << (last2.
y - last3.
y)
1110 <<
", dz= " << (last7.
z - last3.
z) <<
"\n";
1114 CoordinatesCube(x, y, z, t1, t2, t3, jac, dN,
m_elements[imap]);
1118void ComponentFieldMap::Jacobian3(
1119 const std::array<double, 8>& xn,
1120 const std::array<double, 8>& yn,
1121 const double u,
const double v,
const double w,
1122 double& det,
double jac[4][4]) {
1124 const double fouru = 4 * u;
1125 const double fourv = 4 * v;
1126 const double fourw = 4 * w;
1128 const double j10 = (-1 + fouru) * xn[0] + fourv * xn[3] + fourw * xn[4];
1129 const double j20 = (-1 + fouru) * yn[0] + fourv * yn[3] + fourw * yn[4];
1130 const double j11 = (-1 + fourv) * xn[1] + fouru * xn[3] + fourw * xn[5];
1131 const double j21 = (-1 + fourv) * yn[1] + fouru * yn[3] + fourw * yn[5];
1132 const double j12 = (-1 + fourw) * xn[2] + fouru * xn[4] + fourv * xn[5];
1133 const double j22 = (-1 + fourw) * yn[2] + fouru * yn[4] + fourv * yn[5];
1135 det = -(j11 - j12) * j20 - (j10 - j11) * j22 + (j10 - j12) * j21;
1138 jac[0][0] = j11 * j22 - j12 * j21;
1139 jac[0][1] = j21 - j22;
1140 jac[0][2] = j12 - j11;
1141 jac[1][0] = j12 * j20 - j10 * j22;
1142 jac[1][1] = j22 - j20;
1143 jac[1][2] = j10 - j12;
1144 jac[2][0] = j10 * j21 - j11 * j20;
1145 jac[2][1] = j20 - j21;
1146 jac[2][2] = j11 - j10;
1149void ComponentFieldMap::Jacobian5(
1150 const std::array<double, 8>& xn,
1151 const std::array<double, 8>& yn,
1152 const double u,
const double v,
double& det,
double jac[4][4]) {
1154 const double g0 = (1 - u) * (2 * v + u);
1155 const double g1 = (1 + u) * (2 * v - u);
1156 const double g2 = (1 + u) * (2 * v + u);
1157 const double g3 = (1 - u) * (2 * v - u);
1158 const double g4 = (1 - u) * (1 + u);
1159 const double g5 = (1 + u) * v;
1160 const double g7 = (1 - u) * v;
1161 jac[0][0] = 0.25 * (g0 * yn[0] + g1 * yn[1] + g2 * yn[2] + g3 * yn[3]) -
1162 0.5 * g4 * yn[4] - g5 * yn[5] +
1163 0.5 * g4 * yn[6] - g7 * yn[7];
1164 jac[0][1] = -0.25 * (g0 * xn[0] + g1 * xn[1] + g2 * xn[2] + g3 * xn[3]) +
1165 0.5 * g4 * xn[4] + g5 * xn[5] -
1166 0.5 * g4 * xn[6] + g7 * xn[7];
1167 const double h0 = (1 - v) * (2 * u + v);
1168 const double h1 = (1 - v) * (2 * u - v);
1169 const double h2 = (1 + v) * (2 * u + v);
1170 const double h3 = (1 + v) * (2 * u - v);
1171 const double h4 = (1 - v) * u;
1172 const double h5 = (1 - v) * (1 + v);
1173 const double h6 = (1 + v) * u;
1174 jac[1][0] = -0.25 * (h0 * yn[0] + h1 * yn[1] + h2 * yn[2] + h3 * yn[3]) +
1175 h4 * yn[4] - 0.5 * h5 * yn[5] +
1176 h6 * yn[6] + 0.5 * h5 * yn[7];
1177 jac[1][1] = 0.25 * (h0 * xn[0] + h1 * xn[1] + h2 * xn[2] + h3 * xn[3]) -
1178 h4 * xn[4] + 0.5 * h5 * xn[5] -
1179 h6 * xn[6] - 0.5 * h5 * xn[7];
1182 det = jac[0][0] * jac[1][1] - jac[0][1] * jac[1][0];
1185void ComponentFieldMap::Jacobian13(
1186 const std::array<double, 10>& xn,
1187 const std::array<double, 10>& yn,
1188 const std::array<double, 10>& zn,
1189 const double fourt0,
const double fourt1,
1190 const double fourt2,
const double fourt3,
1191 double& det,
double jac[4][4]) {
1193 const double fourt0m1 = fourt0 - 1.;
1194 const double j10 = fourt0m1 * xn[0] + fourt1 * xn[4] + fourt2 * xn[5] + fourt3 * xn[6];
1195 const double j20 = fourt0m1 * yn[0] + fourt1 * yn[4] + fourt2 * yn[5] + fourt3 * yn[6];
1196 const double j30 = fourt0m1 * zn[0] + fourt1 * zn[4] + fourt2 * zn[5] + fourt3 * zn[6];
1198 const double fourt1m1 = fourt1 - 1.;
1199 const double j11 = fourt1m1 * xn[1] + fourt0 * xn[4] + fourt2 * xn[7] + fourt3 * xn[8];
1200 const double j21 = fourt1m1 * yn[1] + fourt0 * yn[4] + fourt2 * yn[7] + fourt3 * yn[8];
1201 const double j31 = fourt1m1 * zn[1] + fourt0 * zn[4] + fourt2 * zn[7] + fourt3 * zn[8];
1203 const double fourt2m1 = fourt2 - 1.;
1204 const double j12 = fourt2m1 * xn[2] + fourt0 * xn[5] + fourt1 * xn[7] + fourt3 * xn[9];
1205 const double j22 = fourt2m1 * yn[2] + fourt0 * yn[5] + fourt1 * yn[7] + fourt3 * yn[9];
1206 const double j32 = fourt2m1 * zn[2] + fourt0 * zn[5] + fourt1 * zn[7] + fourt3 * zn[9];
1208 const double fourt3m1 = fourt3 - 1.;
1209 const double j13 = fourt3m1 * xn[3] + fourt0 * xn[6] + fourt1 * xn[8] + fourt2 * xn[9];
1210 const double j23 = fourt3m1 * yn[3] + fourt0 * yn[6] + fourt1 * yn[8] + fourt2 * yn[9];
1211 const double j33 = fourt3m1 * zn[3] + fourt0 * zn[6] + fourt1 * zn[8] + fourt2 * zn[9];
1213 const double a1 = j10 * j21 - j20 * j11;
1214 const double a2 = j10 * j22 - j20 * j12;
1215 const double a3 = j10 * j23 - j20 * j13;
1216 const double a4 = j11 * j22 - j21 * j12;
1217 const double a5 = j11 * j23 - j21 * j13;
1218 const double a6 = j12 * j23 - j22 * j13;
1220 const double d1011 = j10 - j11;
1221 const double d1012 = j10 - j12;
1222 const double d1013 = j10 - j13;
1223 const double d1112 = j11 - j12;
1224 const double d1113 = j11 - j13;
1225 const double d1213 = j12 - j13;
1227 const double d2021 = j20 - j21;
1228 const double d2022 = j20 - j22;
1229 const double d2023 = j20 - j23;
1230 const double d2122 = j21 - j22;
1231 const double d2123 = j21 - j23;
1232 const double d2223 = j22 - j23;
1234 jac[0][0] = -a5 * j32 + a4 * j33 + a6 * j31;
1235 jac[0][1] = -d2123 * j32 + d2122 * j33 + d2223 * j31;
1236 jac[0][2] = d1113 * j32 - d1112 * j33 - d1213 * j31;
1237 jac[0][3] = -d1113 * j22 + d1112 * j23 + d1213 * j21;
1239 jac[1][0] = -a6 * j30 + a3 * j32 - a2 * j33;
1240 jac[1][1] = -d2223 * j30 + d2023 * j32 - d2022 * j33;
1241 jac[1][2] = d1213 * j30 - d1013 * j32 + d1012 * j33;
1242 jac[1][3] = -d1213 * j20 + d1013 * j22 - d1012 * j23;
1244 jac[2][0] = a5 * j30 + a1 * j33 - a3 * j31;
1245 jac[2][1] = d2123 * j30 + d2021 * j33 - d2023 * j31;
1246 jac[2][2] = -d1113 * j30 - d1011 * j33 + d1013 * j31;
1247 jac[2][3] = d1113 * j20 + d1011 * j23 - d1013 * j21;
1249 jac[3][0] = -a4 * j30 - a1 * j32 + a2 * j31;
1250 jac[3][1] = -d2122 * j30 - d2021 * j32 + d2022 * j31;
1251 jac[3][2] = d1112 * j30 + d1011 * j32 - d1012 * j31;
1252 jac[3][3] = -d1112 * j20 - d1011 * j22 + d1012 * j21;
1254 det = 1. / (jac[0][3] * j30 + jac[1][3] * j31 + jac[2][3] * j32 + jac[3][3] * j33);
1257void ComponentFieldMap::JacobianCube(
const Element& element,
const double t1,
1258 const double t2,
const double t3,
1260 std::vector<TMatrixD*>& dN)
const {
1263 std::cerr <<
" Pointer to Jacobian matrix is empty!\n";
1269 double N1[3] = {-1 * (1 - t2) * (1 - t3), (1 - t1) * -1 * (1 - t3),
1270 (1 - t1) * (1 - t2) * -1};
1271 double N2[3] = {+1 * (1 - t2) * (1 - t3), (1 + t1) * -1 * (1 - t3),
1272 (1 + t1) * (1 - t2) * -1};
1273 double N3[3] = {+1 * (1 + t2) * (1 - t3), (1 + t1) * +1 * (1 - t3),
1274 (1 + t1) * (1 + t2) * -1};
1275 double N4[3] = {-1 * (1 + t2) * (1 - t3), (1 - t1) * +1 * (1 - t3),
1276 (1 - t1) * (1 + t2) * -1};
1277 double N5[3] = {-1 * (1 - t2) * (1 + t3), (1 - t1) * -1 * (1 + t3),
1278 (1 - t1) * (1 - t2) * +1};
1279 double N6[3] = {+1 * (1 - t2) * (1 + t3), (1 + t1) * -1 * (1 + t3),
1280 (1 + t1) * (1 - t2) * +1};
1281 double N7[3] = {+1 * (1 + t2) * (1 + t3), (1 + t1) * +1 * (1 + t3),
1282 (1 + t1) * (1 + t2) * +1};
1283 double N8[3] = {-1 * (1 + t2) * (1 + t3), (1 - t1) * +1 * (1 + t3),
1284 (1 - t1) * (1 + t2) * +1};
1286 TMatrixD* m_N1 =
new TMatrixD(3, 1, N1);
1287 *m_N1 = (1. / 8. * (*m_N1));
1289 TMatrixD* m_N2 =
new TMatrixD(3, 1, N2);
1290 *m_N2 = (1. / 8. * (*m_N2));
1292 TMatrixD* m_N3 =
new TMatrixD(3, 1, N3);
1293 *m_N3 = (1. / 8. * (*m_N3));
1295 TMatrixD* m_N4 =
new TMatrixD(3, 1, N4);
1296 *m_N4 = (1. / 8. * (*m_N4));
1298 TMatrixD* m_N5 =
new TMatrixD(3, 1, N5);
1299 *m_N5 = (1. / 8. * (*m_N5));
1301 TMatrixD* m_N6 =
new TMatrixD(3, 1, N6);
1302 *m_N6 = (1. / 8. * (*m_N6));
1304 TMatrixD* m_N7 =
new TMatrixD(3, 1, N7);
1305 *m_N7 = (1. / 8. * (*m_N7));
1307 TMatrixD* m_N8 =
new TMatrixD(3, 1, N8);
1308 *m_N8 = (1. / 8. * (*m_N8));
1311 for (
int j = 0; j < 8; ++j) {
1313 (*jac)(0, 0) += node.x * ((*dN.at(j))(0, 0));
1314 (*jac)(0, 1) += node.y * ((*dN.at(j))(0, 0));
1315 (*jac)(0, 2) += node.z * ((*dN.at(j))(0, 0));
1316 (*jac)(1, 0) += node.x * ((*dN.at(j))(1, 0));
1317 (*jac)(1, 1) += node.y * ((*dN.at(j))(1, 0));
1318 (*jac)(1, 2) += node.z * ((*dN.at(j))(1, 0));
1319 (*jac)(2, 0) += node.x * ((*dN.at(j))(2, 0));
1320 (*jac)(2, 1) += node.y * ((*dN.at(j))(2, 0));
1321 (*jac)(2, 2) += node.z * ((*dN.at(j))(2, 0));
1326 std::cout <<
m_className <<
"::JacobianCube:" << std::endl;
1327 std::cout <<
" Det.: " << jac->Determinant() << std::endl;
1328 std::cout <<
" Jacobian matrix.: " << std::endl;
1329 jac->Print(
"%11.10g");
1330 std::cout <<
" Hexahedral coordinates (t, u, v) = (" << t1 <<
"," << t2
1331 <<
"," << t3 <<
")" << std::endl;
1332 std::cout <<
" Node xyzV" << std::endl;
1333 for (
int j = 0; j < 8; ++j) {
1335 std::cout <<
" " << element.emap[j] <<
" " << node.x
1336 <<
" " << node.y <<
" " << node.z <<
" "
1337 <<
m_pot[element.emap[j]] << std::endl;
1342int ComponentFieldMap::Coordinates3(
1343 const double x,
const double y,
1344 double& t1,
double& t2,
double& t3,
double& t4,
1345 double jac[4][4],
double& det,
1346 const std::array<double, 8>& xn,
1347 const std::array<double, 8>& yn)
const {
1350 <<
" Point (" <<
x <<
", " <<
y <<
")\n";
1354 t1 = t2 = t3 = t4 = 0;
1358 (xn[0] - xn[1]) * (yn[2] - yn[1]) -
1359 (xn[2] - xn[1]) * (yn[0] - yn[1]);
1361 (xn[1] - xn[2]) * (yn[0] - yn[2]) -
1362 (xn[0] - xn[2]) * (yn[1] - yn[2]);
1364 (xn[2] - xn[0]) * (yn[1] - yn[0]) -
1365 (xn[1] - xn[0]) * (yn[2] - yn[0]);
1366 if (d1 == 0 || d2 == 0 || d3 == 0) {
1368 <<
" Calculation of linear coordinates failed; abandoned.\n";
1371 t1 = ((
x - xn[1]) * (yn[2] - yn[1]) -
1372 (
y - yn[1]) * (xn[2] - xn[1])) / d1;
1373 t2 = ((
x - xn[2]) * (yn[0] - yn[2]) -
1374 (
y - yn[2]) * (xn[0] - xn[2])) / d2;
1375 t3 = ((
x - xn[0]) * (yn[1] - yn[0]) -
1376 (
y - yn[0]) * (xn[1] - xn[0])) / d3;
1379 double td1 = t1, td2 = t2, td3 = t3;
1380 bool converged =
false;
1381 std::array<double, 6> f;
1382 for (
int iter = 0; iter < 10; iter++) {
1385 std::cout <<
" Iteration " << iter <<
": (u, v, w) = (" << td1
1386 <<
", " << td2 <<
", " << td3 <<
"), sum = " << td1 + td2 + td3
1390 f[0] = td1 * (2 * td1 - 1);
1391 f[1] = td2 * (2 * td2 - 1);
1392 f[2] = td3 * (2 * td3 - 1);
1393 f[3] = 4 * td1 * td2;
1394 f[4] = 4 * td1 * td3;
1395 f[5] = 4 * td2 * td3;
1397 double xr = 0., yr = 0.;
1398 for (
size_t i = 0; i < 6; ++i) {
1402 const double sr = td1 + td2 + td3;
1404 Jacobian3(xn, yn, td1, td2, td3, det, jac);
1406 const double diff[3] = {1 - sr,
x - xr,
y - yr};
1408 const double invdet = 1. / det;
1409 double corr[3] = {0., 0., 0.};
1410 for (
size_t l = 0; l < 3; l++) {
1411 for (
size_t k = 0; k < 3; k++) {
1412 corr[l] += jac[l][k] * diff[k];
1419 std::cout <<
" Difference vector: (1, x, y) = (" << diff[0] <<
", "
1420 << diff[1] <<
", " << diff[2] <<
").\n";
1421 std::cout <<
" Correction vector: (u, v, w) = (" << corr[0] <<
", "
1422 << corr[1] <<
", " << corr[2] <<
").\n";
1429 constexpr double tol = 1.e-5;
1430 if (
fabs(corr[0]) < tol &&
fabs(corr[1]) < tol &&
fabs(corr[2]) < tol) {
1432 std::cout <<
m_className <<
"::Coordinates3: Convergence reached.";
1440 const double xmin = std::min({xn[0], xn[1], xn[2]});
1441 const double xmax = std::max({xn[0], xn[1], xn[2]});
1442 const double ymin = std::min({yn[0], yn[1], yn[2]});
1443 const double ymax = std::max({yn[0], yn[1], yn[2]});
1444 if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) {
1447 <<
" No convergence achieved "
1448 <<
"when refining internal isoparametric coordinates\n"
1449 <<
" at position (" <<
x <<
", " <<
y <<
").\n";
1451 t1 = t2 = t3 = t4 = 0;
1463 std::cout <<
" Convergence reached at (t1, t2, t3) = (" << t1 <<
", "
1464 << t2 <<
", " << t3 <<
").\n";
1466 const double f0 = td1 * (2 * td1 - 1);
1467 const double f1 = td2 * (2 * td2 - 1);
1468 const double f2 = td3 * (2 * td3 - 1);
1469 const double f3 = 4 * td1 * td2;
1470 const double f4 = 4 * td1 * td3;
1471 const double f5 = 4 * td2 * td3;
1473 xn[0] * f0 + xn[1] * f1 + xn[2] * f2 + xn[3] * f3 + xn[4] * f4 + xn[5] * f5;
1475 yn[0] * f0 + yn[1] * f1 + yn[2] * f2 + yn[3] * f3 + yn[4] * f4 + yn[5] * f5;
1476 const double sr = td1 + td2 + td3;
1478 std::cout <<
" Position requested: (" <<
x <<
", " <<
y <<
")\n";
1479 std::cout <<
" Reconstructed: (" << xr <<
", " << yr <<
")\n";
1480 std::cout <<
" Difference: (" <<
x - xr <<
", " <<
y - yr
1482 std::cout <<
" Checksum - 1: " << sr - 1 <<
"\n";
1489int ComponentFieldMap::Coordinates4(
1490 const double x,
const double y,
1491 double& t1,
double& t2,
double& t3,
double& t4,
double& det,
1492 const std::array<double, 8>& xn,
1493 const std::array<double, 8>& yn)
const {
1496 <<
" Point (" <<
x <<
", " <<
y <<
")\n";
1502 t1 = t2 = t3 = t4 = 0.;
1506 -(xn[0] * yn[1]) + xn[3] * yn[2] -
1508 x * (-yn[0] + yn[1] - yn[2] + yn[3]) +
1509 xn[1] * (yn[0] -
y) +
1510 (xn[0] + xn[2] - xn[3]) *
y;
1511 det = -(-((xn[0] - xn[3]) * (yn[1] - yn[2])) +
1512 (xn[1] - xn[2]) * (yn[0] - yn[3])) *
1513 (2 * x * (-yn[0] + yn[1] + yn[2] - yn[3]) -
1514 (xn[0] + xn[3]) * (yn[1] + yn[2] - 2 * y) +
1515 xn[1] * (yn[0] + yn[3] - 2 * y) +
1516 xn[2] * (yn[0] + yn[3] - 2 * y)) +
1524 <<
" No solution found for isoparametric coordinates\n"
1525 <<
" because the determinant " << det <<
" is < 0.\n";
1531 double prod = ((xn[2] - xn[3]) * (yn[0] - yn[1]) -
1532 (xn[0] - xn[1]) * (yn[2] - yn[3]));
1533 if (prod * prod > 1.0e-12 *
1534 ((xn[0] - xn[1]) * (xn[0] - xn[1]) +
1535 (yn[0] - yn[1]) * (yn[0] - yn[1])) *
1536 ((xn[2] - xn[3]) * (xn[2] - xn[3]) +
1537 (yn[2] - yn[3]) * (yn[2] - yn[3]))) {
1538 t1 = (-(xn[3] * yn[0]) +
x * yn[0] + xn[2] * yn[1] -
x * yn[1] - xn[1] * yn[2] +
1539 x * yn[2] + xn[0] * yn[3] -
x * yn[3] - xn[0] *
y + xn[1] *
y - xn[2] *
y +
1540 xn[3] *
y +
sqrt(det)) /
1543 double xp = yn[0] - yn[1];
1544 double yp = xn[1] - xn[0];
1545 double dn =
sqrt(xp * xp + yp * yp);
1548 <<
" Element appears to be degenerate in the 1 - 2 axis.\n";
1553 double dpoint = xp * (
x - xn[0]) + yp * (y - yn[0]);
1554 double dbox = xp * (xn[3] - xn[0]) + yp * (yn[3] - yn[0]);
1557 <<
" Element appears to be degenerate in the 1 - 3 axis.\n";
1560 double t = -1 + 2 * dpoint / dbox;
1561 double xt1 = xn[0] + 0.5 * (t + 1) * (xn[3] - xn[0]);
1562 double yt1 = yn[0] + 0.5 * (t + 1) * (yn[3] - yn[0]);
1563 double xt2 = xn[1] + 0.5 * (t + 1) * (xn[2] - xn[1]);
1564 double yt2 = yn[1] + 0.5 * (t + 1) * (yn[2] - yn[1]);
1565 dn = (xt1 - xt2) * (xt1 - xt2) + (yt1 - yt2) * (yt1 - yt2);
1569 <<
" Coordinate requested at convergence point of element.\n";
1572 t1 = -1 + 2 * ((
x - xt1) * (xt2 - xt1) + (
y - yt1) * (yt2 - yt1)) / dn;
1576 prod = ((xn[0] - xn[3]) * (yn[1] - yn[2]) -
1577 (xn[1] - xn[2]) * (yn[0] - yn[3]));
1578 if (prod * prod > 1.0e-12 *
1579 ((xn[0] - xn[3]) * (xn[0] - xn[3]) +
1580 (yn[0] - yn[3]) * (yn[0] - yn[3])) *
1581 ((xn[1] - xn[2]) * (xn[1] - xn[2]) +
1582 (yn[1] - yn[2]) * (yn[1] - yn[2]))) {
1583 t2 = (-(xn[1] * yn[0]) +
x * yn[0] + xn[0] * yn[1] -
x * yn[1] - xn[3] * yn[2] +
1584 x * yn[2] + xn[2] * yn[3] -
x * yn[3] - xn[0] *
y + xn[1] *
y - xn[2] *
y +
1585 xn[3] *
y -
sqrt(det)) /
1588 double xp = yn[0] - yn[3];
1589 double yp = xn[3] - xn[0];
1590 double dn =
sqrt(xp * xp + yp * yp);
1593 <<
" Element appears to be degenerate in the 1 - 4 axis.\n";
1598 double dpoint = xp * (
x - xn[0]) + yp * (y - yn[0]);
1599 double dbox = xp * (xn[1] - xn[0]) + yp * (yn[1] - yn[0]);
1602 <<
" Element appears to be degenerate in the 1 - 2 axis.\n";
1605 double t = -1 + 2 * dpoint / dbox;
1606 double xt1 = xn[0] + 0.5 * (t + 1) * (xn[1] - xn[0]);
1607 double yt1 = yn[0] + 0.5 * (t + 1) * (yn[1] - yn[0]);
1608 double xt2 = xn[3] + 0.5 * (t + 1) * (xn[2] - xn[3]);
1609 double yt2 = yn[3] + 0.5 * (t + 1) * (yn[2] - yn[3]);
1610 dn = (xt1 - xt2) * (xt1 - xt2) + (yt1 - yt2) * (yt1 - yt2);
1614 <<
" Coordinate requested at convergence point of element.\n";
1617 t2 = -1 + 2 * ((
x - xt1) * (xt2 - xt1) + (
y - yt1) * (yt2 - yt1)) / dn;
1621 std::cout <<
" Isoparametric (u, v): (" << t1 <<
", " << t2 <<
").\n";
1623 const double f0 = (1 - t1) * (1 - t2) * 0.25;
1624 const double f1 = (1 + t1) * (1 - t2) * 0.25;
1625 const double f2 = (1 + t1) * (1 + t2) * 0.25;
1626 const double f3 = (1 - t1) * (1 + t2) * 0.25;
1627 const double xr = xn[0] * f0 + xn[1] * f1 + xn[2] * f2 + xn[3] * f3;
1628 const double yr = yn[0] * f0 + yn[1] * f1 + yn[2] * f2 + yn[3] * f3;
1630 std::cout <<
" Position requested: (" <<
x <<
", " <<
y <<
")\n";
1631 std::cout <<
" Reconstructed: (" << xr <<
", " << yr <<
")\n";
1632 std::cout <<
" Difference: (" <<
x - xr <<
", " <<
y - yr
1641int ComponentFieldMap::Coordinates5(
const double x,
const double y,
1642 double& t1,
double& t2,
double& t3,
double& t4,
1643 double jac[4][4],
double& det,
1644 const std::array<double, 8>& xn,
1645 const std::array<double, 8>& yn)
const {
1649 <<
" Point (" <<
x <<
", " <<
y <<
")\n";
1656 t1 = t2 = t3 = t4 = 0;
1659 if (Coordinates4(x, y, t1, t2, t3, t4, det, xn, yn) > 0) {
1661 std::cout <<
" Failure to obtain linear estimate of isoparametric "
1668 if (t1 < -1.5 || t1 > 1.5 || t2 < -1.5 || t2 > 1.5) {
1670 std::cout <<
" Point far outside, (t1,t2) = (" << t1 <<
", " << t2
1677 double td1 = t1, td2 = t2;
1678 bool converged =
false;
1679 std::array<double, 8> f;
1680 for (
int iter = 0; iter < 10; iter++) {
1682 std::cout <<
" Iteration " << iter <<
": (t1, t2) = (" << td1
1683 <<
", " << td2 <<
").\n";
1686 f[0] = (-(1 - td1) * (1 - td2) * (1 + td1 + td2)) * 0.25;
1687 f[1] = (-(1 + td1) * (1 - td2) * (1 - td1 + td2)) * 0.25;
1688 f[2] = (-(1 + td1) * (1 + td2) * (1 - td1 - td2)) * 0.25;
1689 f[3] = (-(1 - td1) * (1 + td2) * (1 + td1 - td2)) * 0.25;
1690 f[4] = (1 - td1) * (1 + td1) * (1 - td2) * 0.5;
1691 f[5] = (1 + td1) * (1 + td2) * (1 - td2) * 0.5;
1692 f[6] = (1 - td1) * (1 + td1) * (1 + td2) * 0.5;
1693 f[7] = (1 - td1) * (1 + td2) * (1 - td2) * 0.5;
1694 double xr = 0., yr = 0.;
1695 for (
size_t i = 0; i < 8; ++i) {
1700 Jacobian5(xn, yn, td1, td2, det, jac);
1702 double diff[2] = {
x - xr,
y - yr};
1704 double corr[2] = {0., 0.};
1705 const double invdet = 1. / det;
1706 for (
size_t l = 0; l < 2; ++l) {
1707 for (
size_t k = 0; k < 2; ++k) {
1708 corr[l] += jac[l][k] * diff[k];
1714 std::cout <<
" Difference vector: (x, y) = (" << diff[0] <<
", "
1715 << diff[1] <<
").\n";
1716 std::cout <<
" Correction vector: (t1, t2) = (" << corr[0] <<
", "
1717 << corr[1] <<
").\n";
1723 constexpr double tol = 1.e-5;
1724 if (
fabs(corr[0]) < tol &&
fabs(corr[1]) < tol) {
1725 if (
m_debug) std::cout <<
" Convergence reached.\n";
1732 double xmin = *std::min_element(xn.begin(), xn.end());
1733 double xmax = *std::max_element(xn.begin(), xn.end());
1734 double ymin = *std::min_element(yn.begin(), yn.end());
1735 double ymax = *std::max_element(yn.begin(), yn.end());
1736 if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) {
1739 <<
" No convergence achieved "
1740 <<
"when refining internal isoparametric coordinates\n"
1741 <<
" at position (" <<
x <<
", " <<
y <<
").\n";
1754 std::cout <<
" Convergence reached at (t1, t2) = (" << t1 <<
", " << t2
1757 f[0] = (-(1 - td1) * (1 - td2) * (1 + td1 + td2)) * 0.25;
1758 f[1] = (-(1 + td1) * (1 - td2) * (1 - td1 + td2)) * 0.25;
1759 f[2] = (-(1 + td1) * (1 + td2) * (1 - td1 - td2)) * 0.25;
1760 f[3] = (-(1 - td1) * (1 + td2) * (1 + td1 - td2)) * 0.25;
1761 f[4] = (1 - td1) * (1 + td1) * (1 - td2) * 0.5;
1762 f[5] = (1 + td1) * (1 + td2) * (1 - td2) * 0.5;
1763 f[6] = (1 - td1) * (1 + td1) * (1 + td2) * 0.5;
1764 f[7] = (1 - td1) * (1 + td2) * (1 - td2) * 0.5;
1765 double xr = 0., yr = 0.;
1766 for (
size_t i = 0; i < 8; ++i) {
1770 std::cout <<
" Position requested: (" <<
x <<
", " <<
y <<
")\n";
1771 std::cout <<
" Reconstructed: (" << xr <<
", " << yr <<
")\n";
1772 std::cout <<
" Difference: (" <<
x - xr <<
", " <<
y - yr
1781std::array<std::array<double, 3>, 4> ComponentFieldMap::Weights12(
1782 const std::array<double, 10>& xn,
1783 const std::array<double, 10>& yn,
1784 const std::array<double, 10>& zn) {
1786 std::array<std::array<double, 3>, 4> w;
1787 w[0][0] = (yn[2] - yn[1]) * (zn[3] - zn[1]) -
1788 (yn[3] - yn[1]) * (zn[2] - zn[1]);
1789 w[0][1] = (zn[2] - zn[1]) * (xn[3] - xn[1]) -
1790 (zn[3] - zn[1]) * (xn[2] - xn[1]);
1791 w[0][2] = (xn[2] - xn[1]) * (yn[3] - yn[1]) -
1792 (xn[3] - xn[1]) * (yn[2] - yn[1]);
1793 const double s0 = 1. / ((xn[0] - xn[1]) * w[0][0] +
1794 (yn[0] - yn[1]) * w[0][1] +
1795 (zn[0] - zn[1]) * w[0][2]);
1796 for (
size_t i = 0; i < 3; ++i) w[0][i] *= s0;
1798 w[1][0] = (yn[0] - yn[2]) * (zn[3] - zn[2]) -
1799 (yn[3] - yn[2]) * (zn[0] - zn[2]);
1800 w[1][1] = (zn[0] - zn[2]) * (xn[3] - xn[2]) -
1801 (zn[3] - zn[2]) * (xn[0] - xn[2]);
1802 w[1][2] = (xn[0] - xn[2]) * (yn[3] - yn[2]) -
1803 (xn[3] - xn[2]) * (yn[0] - yn[2]);
1804 const double s1 = 1. / ((xn[1] - xn[2]) * w[1][0] +
1805 (yn[1] - yn[2]) * w[1][1] +
1806 (zn[1] - zn[2]) * w[1][2]);
1807 for (
size_t i = 0; i < 3; ++i) w[1][i] *= s1;
1809 w[2][0] = (yn[0] - yn[3]) * (zn[1] - zn[3]) -
1810 (yn[1] - yn[3]) * (zn[0] - zn[3]);
1811 w[2][1] = (zn[0] - zn[3]) * (xn[1] - xn[3]) -
1812 (zn[1] - zn[3]) * (xn[0] - xn[3]);
1813 w[2][2] = (xn[0] - xn[3]) * (yn[1] - yn[3]) -
1814 (xn[1] - xn[3]) * (yn[0] - yn[3]);
1815 const double s2 = 1. / ((xn[2] - xn[3]) * w[2][0] +
1816 (yn[2] - yn[3]) * w[2][1] +
1817 (zn[2] - zn[3]) * w[2][2]);
1818 for (
size_t i = 0; i < 3; ++i) w[2][i] *= s2;
1820 w[3][0] = (yn[2] - yn[0]) * (zn[1] - zn[0]) -
1821 (yn[1] - yn[0]) * (zn[2] - zn[0]);
1822 w[3][1] = (zn[2] - zn[0]) * (xn[1] - xn[0]) -
1823 (zn[1] - zn[0]) * (xn[2] - xn[0]);
1824 w[3][2] = (xn[2] - xn[0]) * (yn[1] - yn[0]) -
1825 (xn[1] - xn[0]) * (yn[2] - yn[0]);
1826 const double s3 = 1. / ((xn[3] - xn[0]) * w[3][0] +
1827 (yn[3] - yn[0]) * w[3][1] +
1828 (zn[3] - zn[0]) * w[3][2]);
1829 for (
size_t i = 0; i < 3; ++i) w[3][i] *= s3;
1833void ComponentFieldMap::Coordinates12(
1834 const double x,
const double y,
const double z,
1835 double& t1,
double& t2,
double& t3,
double& t4,
1836 const std::array<double, 10>& xn,
1837 const std::array<double, 10>& yn,
1838 const std::array<double, 10>& zn,
1839 const std::array<std::array<double, 3>, 4>& w)
const {
1842 <<
" Point (" <<
x <<
", " <<
y <<
", " <<
z <<
").\n";
1846 t1 = (
x - xn[1]) * w[0][0] + (y - yn[1]) * w[0][1] + (
z - zn[1]) * w[0][2];
1847 t2 = (
x - xn[2]) * w[1][0] + (y - yn[2]) * w[1][1] + (
z - zn[2]) * w[1][2];
1848 t3 = (
x - xn[3]) * w[2][0] + (y - yn[3]) * w[2][1] + (
z - zn[3]) * w[2][2];
1849 t4 = (
x - xn[0]) * w[3][0] + (y - yn[0]) * w[3][1] + (
z - zn[0]) * w[3][2];
1853 std::cout <<
" Tetrahedral coordinates (t, u, v, w) = (" << t1 <<
", "
1854 << t2 <<
", " << t3 <<
", " << t4
1855 <<
") sum = " << t1 + t2 + t3 + t4 <<
".\n";
1857 const double xr = xn[0] * t1 + xn[1] * t2 + xn[2] * t3 + xn[3] * t4;
1858 const double yr = yn[0] * t1 + yn[1] * t2 + yn[2] * t3 + yn[3] * t4;
1859 const double zr = zn[0] * t1 + zn[1] * t2 + zn[2] * t3 + zn[3] * t4;
1860 const double sr = t1 + t2 + t3 + t4;
1861 std::cout <<
" Position requested: (" <<
x <<
", " <<
y <<
", " <<
z
1863 std::cout <<
" Reconstructed: (" << xr <<
", " << yr <<
", "
1865 std::cout <<
" Difference: (" <<
x - xr <<
", " <<
y - yr
1866 <<
", " <<
z - zr <<
")\n";
1867 std::cout <<
" Checksum - 1: " << sr - 1 <<
"\n";
1871int ComponentFieldMap::Coordinates13(
1872 const double x,
const double y,
const double z,
1873 double& t1,
double& t2,
double& t3,
double& t4,
1874 double jac[4][4],
double& det,
1875 const std::array<double, 10>& xn,
1876 const std::array<double, 10>& yn,
1877 const std::array<double, 10>& zn,
1878 const std::array<std::array<double, 3>, 4>& w)
const {
1881 t1 = (
x - xn[1]) * w[0][0] + (y - yn[1]) * w[0][1] + (
z - zn[1]) * w[0][2];
1883 if (t1 < -0.5 || t1 > 1.5)
return 1;
1884 t2 = (
x - xn[2]) * w[1][0] + (y - yn[2]) * w[1][1] + (
z - zn[2]) * w[1][2];
1885 if (t2 < -0.5 || t2 > 1.5)
return 1;
1886 t3 = (
x - xn[3]) * w[2][0] + (y - yn[3]) * w[2][1] + (
z - zn[3]) * w[2][2];
1887 if (t3 < -0.5 || t3 > 1.5)
return 1;
1888 t4 = (
x - xn[0]) * w[3][0] + (y - yn[0]) * w[3][1] + (
z - zn[0]) * w[3][2];
1889 if (t4 < -0.5 || t4 > 1.5)
return 1;
1892 std::array<double, 4> td = {t1, t2, t3, t4};
1895 bool converged =
false;
1896 for (
int iter = 0; iter < 10; ++iter) {
1898 std::printf(
" Iteration %4u: t = (%15.8f, %15.8f %15.8f %15.8f)\n",
1899 iter, td[0], td[1], td[2], td[3]);
1903 const double f0 = td[0] * (td[0] - 0.5);
1904 const double f1 = td[1] * (td[1] - 0.5);
1905 const double f2 = td[2] * (td[2] - 0.5);
1906 const double f3 = td[3] * (td[3] - 0.5);
1907 double xr = 2 * (f0 * xn[0] + f1 * xn[1] + f2 * xn[2] + f3 * xn[3]);
1908 double yr = 2 * (f0 * yn[0] + f1 * yn[1] + f2 * yn[2] + f3 * yn[3]);
1909 double zr = 2 * (f0 * zn[0] + f1 * zn[1] + f2 * zn[2] + f3 * zn[3]);
1910 const double fourt0 = 4 * td[0];
1911 const double fourt1 = 4 * td[1];
1912 const double fourt2 = 4 * td[2];
1913 const double fourt3 = 4 * td[3];
1914 const double f4 = fourt0 * td[1];
1915 const double f5 = fourt0 * td[2];
1916 const double f6 = fourt0 * td[3];
1917 const double f7 = fourt1 * td[2];
1918 const double f8 = fourt1 * td[3];
1919 const double f9 = fourt2 * td[3];
1920 xr += f4 * xn[4] + f5 * xn[5] + f6 * xn[6] + f7 * xn[7] +
1921 f8 * xn[8] + f9 * xn[9];
1922 yr += f4 * yn[4] + f5 * yn[5] + f6 * yn[6] + f7 * yn[7] +
1923 f8 * yn[8] + f9 * yn[9];
1924 zr += f4 * zn[4] + f5 * zn[5] + f6 * zn[6] + f7 * zn[7] +
1925 f8 * zn[8] + f9 * zn[9];
1927 Jacobian13(xn, yn, zn, fourt0, fourt1, fourt2, fourt3, det, jac);
1929 const double sr = std::accumulate(td.cbegin(), td.cend(), 0.);
1930 const double diff[4] = {1. - sr,
x - xr,
y - yr,
z - zr};
1932 double corr[4] = {0., 0., 0., 0.};
1933 for (
size_t l = 0; l < 4; ++l) {
1934 for (
size_t k = 0; k < 4; ++k) {
1935 corr[l] += jac[l][k] * diff[k];
1943 std::cout <<
" Difference vector: (1, x, y, z) = (" << diff[0]
1944 <<
", " << diff[1] <<
", " << diff[2] <<
", " << diff[3]
1946 std::cout <<
" Correction vector: (t1,t2,t3,t4) = (" << corr[0]
1947 <<
", " << corr[1] <<
", " << corr[2] <<
", " << corr[3]
1952 constexpr double tol = 1.e-5;
1953 if (
fabs(corr[0]) < tol &&
fabs(corr[1]) < tol &&
fabs(corr[2]) < tol &&
1954 fabs(corr[3]) < tol) {
1955 if (
m_debug) std::cout <<
" Convergence reached.\n";
1963 const double xmin = std::min({xn[0], xn[1], xn[2], xn[3]});
1964 const double xmax = std::max({xn[0], xn[1], xn[2], xn[3]});
1965 const double ymin = std::min({yn[0], yn[1], yn[2], yn[3]});
1966 const double ymax = std::max({yn[0], yn[1], yn[2], yn[3]});
1967 const double zmin = std::min({zn[0], zn[1], zn[2], zn[3]});
1968 const double zmax = std::max({zn[0], zn[1], zn[2], zn[3]});
1969 if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin &&
1973 <<
" No convergence achieved "
1974 <<
"when refining internal isoparametric coordinates\n"
1975 <<
" at position (" <<
x <<
", " <<
y <<
", " <<
z
1978 t1 = t2 = t3 = t4 = -1;
1989 std::cout <<
" Convergence reached at (t1, t2, t3, t4) = (" << t1 <<
", "
1990 << t2 <<
", " << t3 <<
", " << t4 <<
").\n";
1992 const double f0 = td[0] * (td[0] - 0.5);
1993 const double f1 = td[1] * (td[1] - 0.5);
1994 const double f2 = td[2] * (td[2] - 0.5);
1995 const double f3 = td[3] * (td[3] - 0.5);
1996 double xr = 2 * (f0 * xn[0] + f1 * xn[1] + f2 * xn[2] + f3 * xn[3]);
1997 double yr = 2 * (f0 * yn[0] + f1 * yn[1] + f2 * yn[2] + f3 * yn[3]);
1998 double zr = 2 * (f0 * zn[0] + f1 * zn[1] + f2 * zn[2] + f3 * zn[3]);
1999 const double fourt0 = 4 * td[0];
2000 const double fourt1 = 4 * td[1];
2001 const double fourt2 = 4 * td[2];
2002 const double f4 = fourt0 * td[1];
2003 const double f5 = fourt0 * td[2];
2004 const double f6 = fourt0 * td[3];
2005 const double f7 = fourt1 * td[2];
2006 const double f8 = fourt1 * td[3];
2007 const double f9 = fourt2 * td[3];
2008 xr += f4 * xn[4] + f5 * xn[5] + f6 * xn[6] + f7 * xn[7] +
2009 f8 * xn[8] + f9 * xn[9];
2010 yr += f4 * yn[4] + f5 * yn[5] + f6 * yn[6] + f7 * yn[7] +
2011 f8 * yn[8] + f9 * yn[9];
2012 zr += f4 * zn[4] + f5 * zn[5] + f6 * zn[6] + f7 * zn[7] +
2013 f8 * zn[8] + f9 * zn[9];
2014 const double sr = std::accumulate(td.cbegin(), td.cend(), 0.);
2015 std::cout <<
" Position requested: (" <<
x <<
", " <<
y <<
", " <<
z
2017 std::cout <<
" Reconstructed: (" << xr <<
", " << yr <<
", "
2019 std::cout <<
" Difference: (" <<
x - xr <<
", " <<
y - yr
2020 <<
", " <<
z - zr <<
")\n";
2021 std::cout <<
" Checksum - 1: " << sr - 1 <<
"\n";
2028int ComponentFieldMap::CoordinatesCube(
const double x,
const double y,
2029 const double z,
double& t1,
double& t2,
2030 double& t3, TMatrixD*& jac,
2031 std::vector<TMatrixD*>& dN,
2032 const Element& element)
const {
2057 t2 = (2. * (
x - n3.x) / (n0.x - n3.x) - 1) * -1.;
2058 t1 = 2. * (
y - n3.y) / (n2.y - n3.y) - 1;
2059 t3 = 2. * (
z - n3.z) / (n7.z - n3.z) - 1;
2063 n[0] = 1. / 8 * (1 - t1) * (1 - t2) * (1 - t3);
2064 n[1] = 1. / 8 * (1 + t1) * (1 - t2) * (1 - t3);
2065 n[2] = 1. / 8 * (1 + t1) * (1 + t2) * (1 - t3);
2066 n[3] = 1. / 8 * (1 - t1) * (1 + t2) * (1 - t3);
2067 n[4] = 1. / 8 * (1 - t1) * (1 - t2) * (1 + t3);
2068 n[5] = 1. / 8 * (1 + t1) * (1 - t2) * (1 + t3);
2069 n[6] = 1. / 8 * (1 + t1) * (1 + t2) * (1 + t3);
2070 n[7] = 1. / 8 * (1 - t1) * (1 + t2) * (1 + t3);
2076 for (
int i = 0; i < 8; i++) {
2078 xr += node.x * n[i];
2079 yr += node.y * n[i];
2080 zr += node.z * n[i];
2082 double sr = n[0] + n[1] + n[2] + n[3] + n[4] + n[5] + n[6] + n[7];
2083 std::cout <<
m_className <<
"::CoordinatesCube:\n";
2084 std::cout <<
" Position requested: (" <<
x <<
"," <<
y <<
"," <<
z
2086 std::cout <<
" Position reconstructed: (" << xr <<
"," << yr <<
"," << zr
2088 std::cout <<
" Difference: (" << (
x - xr) <<
"," << (y - yr)
2089 <<
"," << (
z - zr) <<
")\n";
2090 std::cout <<
" Hexahedral coordinates (t, u, v) = (" << t1 <<
"," << t2
2091 <<
"," << t3 <<
")\n";
2092 std::cout <<
" Checksum - 1: " << (sr - 1) <<
"\n";
2094 if (jac != 0) JacobianCube(element, t1, t2, t3, jac, dN);
2117 m_octree.reset(
nullptr);
2118 m_cacheElemBoundingBoxes =
false;
2126 <<
" Caching the bounding boxes of all elements...";
2127 CalculateElementBoundingBoxes();
2128 std::cout <<
" done.\n";
2130 if (InitializeTetrahedralTree()) {
2131 std::cout <<
" Initialized tetrahedral tree.\n";
2137 std::array<double, 10> xn;
2138 std::array<double, 10> yn;
2139 std::array<double, 10> zn;
2141 for (
size_t j = 0; j < 10; ++j) {
2142 const auto& node =
m_nodes[element.emap[j]];
2147 m_w12.emplace_back(Weights12(xn, yn, zn));
2159 for (
size_t i = 0; i < 3; ++i) {
2162 std::cerr <<
m_className <<
"::UpdatePeriodicityCommon:\n"
2163 <<
" Both simple and mirror periodicity requested. Reset.\n";
2178 std::cerr <<
m_className <<
"::UpdatePeriodicityCommon:\n"
2179 <<
" Axial symmetry has been requested but map does not\n"
2180 <<
" cover an integral fraction of 2 pi. Reset.\n";
2191 std::cerr <<
m_className <<
"::UpdatePeriodicityCommon:\n"
2192 <<
" Only one rotational symmetry allowed; reset.\n";
2201 std::cerr <<
m_className <<
"::UpdatePeriodicityCommon:\n"
2202 <<
" Not allowed to combine rotational symmetry\n"
2203 <<
" and axial periodicity; reset.\n";
2213 std::cerr <<
m_className <<
"::UpdatePeriodicityCommon:\n"
2214 <<
" Rotational symmetry requested, \n"
2215 <<
" but x-range straddles 0; reset.\n";
2222 for (
size_t i = 0; i < 3; ++i) {
2227 for (
size_t i = 0; i < 3; ++i) {
2260 for (
size_t i = 0; i < 3; ++i) {
2280 std::cerr <<
m_className <<
"::UpdatePeriodicity2d:\n"
2281 <<
" Simple or mirror periodicity along z\n"
2282 <<
" requested for a 2d map; reset.\n";
2290 std::cerr <<
m_className <<
"::UpdatePeriodicity2d:\n"
2291 <<
" Axial symmetry has been requested \n"
2292 <<
" around x or y for a 2d map; reset.\n";
2310 std::cerr <<
m_className <<
"::SetRange: Field map not yet set.\n";
2322 for (
const auto& node :
m_nodes) {
2323 const std::array<double, 3> pos = {{node.x, node.y, node.z}};
2324 for (
unsigned int i = 0; i < 3; ++i) {
2329 if (node.y != 0 || node.z != 0) {
2330 const double ang = atan2(node.z, node.y);
2340 if (node.z != 0 || node.x != 0) {
2341 const double ang = atan2(node.x, node.z);
2351 if (node.x != 0 || node.y != 0) {
2352 const double ang = atan2(node.y, node.x);
2364 for (
unsigned int i = 0; i < 3; ++i) {
2392 std::cout <<
" Dimensions of the elementary block\n";
2398 std::cout <<
" Periodicities\n";
2399 const std::array<std::string, 3> axes = {{
"x",
"y",
"z"}};
2400 for (
unsigned int i = 0; i < 3; ++i) {
2401 std::cout <<
" " << axes[i] <<
":";
2403 std::cout <<
" simple with length " <<
m_cells[i] <<
" cm";
2406 std::cout <<
" mirror with length " <<
m_cells[i] <<
" cm";
2409 std::cout <<
" axial " << int(0.5 +
m_mapna[i]) <<
"-fold repetition";
2414 std::cout <<
" none";
2420 double& xmax,
double& ymax,
2434 double& zmin,
double& xmax,
2435 double& ymax,
double& zmax) {
2447 bool& xmirrored,
bool& ymirrored,
2448 bool& zmirrored,
double& rcoordinate,
2449 double& rotation)
const {
2458 if (xpos <
m_mapmin[0]) xpos += xrange;
2462 if (xnew <
m_mapmin[0]) xnew += xrange;
2463 int nx = int(floor(0.5 + (xnew - xpos) / xrange));
2464 if (nx != 2 * (nx / 2)) {
2471 const double auxr = sqrt(zpos * zpos + ypos * ypos);
2472 double auxphi = atan2(zpos, ypos);
2475 rotation = phirange * floor(0.5 + (auxphi - phim) / phirange);
2476 if (auxphi - rotation <
m_mapamin[0]) rotation -= phirange;
2477 if (auxphi - rotation >
m_mapamax[0]) rotation += phirange;
2478 auxphi = auxphi - rotation;
2479 ypos = auxr * cos(auxphi);
2480 zpos = auxr * sin(auxphi);
2487 if (ypos <
m_mapmin[1]) ypos += yrange;
2491 if (ynew <
m_mapmin[1]) ynew += yrange;
2492 int ny = int(floor(0.5 + (ynew - ypos) / yrange));
2493 if (ny != 2 * (ny / 2)) {
2500 const double auxr = sqrt(xpos * xpos + zpos * zpos);
2501 double auxphi = atan2(xpos, zpos);
2504 rotation = phirange * floor(0.5 + (auxphi - phim) / phirange);
2505 if (auxphi - rotation <
m_mapamin[1]) rotation -= phirange;
2506 if (auxphi - rotation >
m_mapamax[1]) rotation += phirange;
2507 auxphi = auxphi - rotation;
2508 zpos = auxr * cos(auxphi);
2509 xpos = auxr * sin(auxphi);
2516 if (zpos <
m_mapmin[2]) zpos += zrange;
2520 if (znew <
m_mapmin[2]) znew += zrange;
2521 int nz = int(floor(0.5 + (znew - zpos) / zrange));
2522 if (nz != 2 * (nz / 2)) {
2529 const double auxr = sqrt(ypos * ypos + xpos * xpos);
2530 double auxphi = atan2(ypos, xpos);
2533 rotation = phirange * floor(0.5 + (auxphi - phim) / phirange);
2534 if (auxphi - rotation <
m_mapamin[2]) rotation -= phirange;
2535 if (auxphi - rotation >
m_mapamax[2]) rotation += phirange;
2536 auxphi = auxphi - rotation;
2537 xpos = auxr * cos(auxphi);
2538 ypos = auxr * sin(auxphi);
2543 double zcoordinate = 0;
2545 rcoordinate = sqrt(ypos * ypos + zpos * zpos);
2548 rcoordinate = sqrt(xpos * xpos + zpos * zpos);
2551 rcoordinate = sqrt(xpos * xpos + ypos * ypos);
2564 const double xpos,
const double ypos,
const double zpos,
2565 const bool xmirrored,
const bool ymirrored,
const bool zmirrored,
2566 const double rcoordinate,
const double rotation)
const {
2568 if (xmirrored) ex = -ex;
2569 if (ymirrored) ey = -ey;
2570 if (zmirrored) ez = -ez;
2575 er = sqrt(ey * ey + ez * ez);
2576 theta = atan2(ez, ey);
2578 ey = er * cos(theta);
2579 ez = er * sin(theta);
2582 er = sqrt(ez * ez + ex * ex);
2583 theta = atan2(ex, ez);
2585 ez = er * cos(theta);
2586 ex = er * sin(theta);
2589 er = sqrt(ex * ex + ey * ey);
2590 theta = atan2(ey, ex);
2592 ex = er * cos(theta);
2593 ey = er * sin(theta);
2603 if (rcoordinate <= 0) {
2609 ey = er * ypos / rcoordinate;
2610 ez = er * zpos / rcoordinate;
2614 if (rcoordinate <= 0) {
2619 ex = er * xpos / rcoordinate;
2621 ez = er * zpos / rcoordinate;
2625 if (rcoordinate <= 0) {
2630 ex = er * xpos / rcoordinate;
2631 ey = er * ypos / rcoordinate;
2638 std::transform(unit.begin(), unit.end(), unit.begin(), toupper);
2639 if (unit ==
"MUM" || unit ==
"MICRON" || unit ==
"MICROMETER") {
2641 }
else if (unit ==
"MM" || unit ==
"MILLIMETER") {
2643 }
else if (unit ==
"CM" || unit ==
"CENTIMETER") {
2645 }
else if (unit ==
"M" || unit ==
"METER") {
2668void ComponentFieldMap::CalculateElementBoundingBoxes() {
2679 for (
size_t i = 0; i < nElements; ++i) {
2681 const Node& n0 =
m_nodes[element.emap[0]];
2682 const Node& n1 =
m_nodes[element.emap[1]];
2683 const Node& n2 =
m_nodes[element.emap[2]];
2684 const Node& n3 =
m_nodes[element.emap[3]];
2685 m_bbMin[i][0] = std::min({n0.x, n1.x, n2.x, n3.x});
2686 m_bbMax[i][0] = std::max({n0.x, n1.x, n2.x, n3.x});
2687 m_bbMin[i][1] = std::min({n0.y, n1.y, n2.y, n3.y});
2688 m_bbMax[i][1] = std::max({n0.y, n1.y, n2.y, n3.y});
2689 m_bbMin[i][2] = std::min({n0.z, n1.z, n2.z, n3.z});
2690 m_bbMax[i][2] = std::max({n0.z, n1.z, n2.z, n3.z});
2692 constexpr double f = 0.2;
2705bool ComponentFieldMap::InitializeTetrahedralTree() {
2713 std::cout <<
m_className <<
"::InitializeTetrahedralTree:\n"
2714 <<
" About to initialize the tetrahedral tree.\n";
2718 if (!m_cacheElemBoundingBoxes) CalculateElementBoundingBoxes();
2721 std::cerr <<
m_className <<
"::InitializeTetrahedralTree: Empty mesh.\n";
2726 auto xmin =
m_nodes.front().x;
2727 auto ymin =
m_nodes.front().y;
2728 auto zmin =
m_nodes.front().z;
2732 for (
const auto& node :
m_nodes) {
2733 xmin = std::min(xmin, node.x);
2734 xmax = std::max(xmax, node.x);
2735 ymin = std::min(ymin, node.y);
2736 ymax = std::max(ymax, node.y);
2737 zmin = std::min(zmin, node.z);
2738 zmax = std::max(zmax, node.z);
2742 std::cout <<
" Bounding box:\n"
2743 << std::scientific <<
"\tx: " << xmin <<
" -> " << xmax <<
"\n"
2744 << std::scientific <<
"\ty: " << ymin <<
" -> " << ymax <<
"\n"
2745 << std::scientific <<
"\tz: " << zmin <<
" -> " << zmax <<
"\n";
2748 const double hx = 0.5 * (xmax - xmin);
2749 const double hy = 0.5 * (ymax - ymin);
2750 const double hz = 0.5 * (zmax - zmin);
2751 m_octree.reset(
new TetrahedralTree(Vec3(xmin + hx, ymin + hy, zmin + hz),
2754 if (
m_debug) std::cout <<
" Tree instantiated.\n";
2757 for (
unsigned int i = 0; i <
m_nodes.size(); i++) {
2759 m_octree->InsertMeshNode(Vec3(n.x, n.y, n.z), i);
2762 if (
m_debug) std::cout <<
" Tree nodes initialized successfully.\n";
2765 for (
unsigned int i = 0; i <
m_elements.size(); i++) {
2768 m_octree->InsertMeshElement(bb, i);
2775 std::cerr <<
m_className <<
"::" << header <<
":\n"
2776 <<
" Warnings have been issued for this field map.\n";
2781 std::cerr <<
m_className <<
"::" << header <<
":\n"
2782 <<
" Field map not yet initialised.\n";
2786 const std::string& filename)
const {
2787 std::cerr <<
m_className <<
"::" << header <<
":\n"
2788 <<
" Could not open file " << filename <<
" for reading.\n"
2789 <<
" The file perhaps does not exist.\n";
2793 const double y,
const double z,
2794 const double t1,
const double t2,
2795 const double t3,
const double t4,
2797 const std::vector<double>& pot)
const {
2798 std::cout <<
m_className <<
"::" << header <<
":\n"
2799 <<
" Global = (" << x <<
", " << y <<
", " << z <<
")\n"
2800 <<
" Local = (" << t1 <<
", " << t2 <<
", " << t3 <<
", " << t4
2802 if (
m_degenerate[i]) std::cout <<
" Element is degenerate.\n";
2803 std::cout <<
" Node x y z V\n";
2804 unsigned int nN = 0;
2815 for (
unsigned int ii = 0; ii < nN; ++ii) {
2817 const double v = pot[element.emap[ii]];
2818 printf(
" %-5d %12g %12g %12g %12g\n", element.emap[ii], node.
x, node.
y,
2824 const std::string& label,
const std::string& labelSource,
const double x,
2825 const double y,
const double z,
const double alpha,
const double beta,
2826 const double gamma) {
2828 if (
m_wpot.count(label) > 0) {
2829 std::cout <<
m_className <<
"::CopyWeightingPotential:\n"
2830 <<
" Electrode " << label <<
" exists already.\n";
2834 std::cout <<
m_className <<
"::CopyWeightingPotential:\n"
2835 <<
" A copy named " << label <<
" exists already.\n";
2839 if (
m_wpot.count(labelSource) == 0) {
2840 std::cout <<
m_className <<
"::CopyWeightingPotential:\n"
2841 <<
" Source electrode " << labelSource
2842 <<
" does not exist.\n";
2847 wfieldCopy.
source = labelSource;
2851 Rx(1, 1) = TMath::Cos(-alpha);
2852 Rx(1, 2) = -TMath::Sin(-alpha);
2853 Rx(2, 1) = TMath::Sin(-alpha);
2854 Rx(2, 2) = TMath::Cos(-alpha);
2858 Ry(0, 0) = TMath::Cos(-beta);
2859 Ry(2, 0) = -TMath::Sin(-beta);
2860 Ry(0, 2) = TMath::Sin(-beta);
2861 Ry(2, 2) = TMath::Cos(-beta);
2865 Rz(0, 0) = TMath::Cos(-gamma);
2866 Rz(0, 1) = -TMath::Sin(-gamma);
2867 Rz(1, 0) = TMath::Sin(-gamma);
2868 Rz(1, 1) = TMath::Cos(-gamma);
2874 wfieldCopy.
rot = Rx * Ry * Rz;
2875 wfieldCopy.
trans = trans;
2878 std::cout <<
m_className <<
"::CopyWeightingPotential:\n"
2879 <<
" Copy named " << label <<
" of weighting potential "
2880 << labelSource <<
" made.\n";
2884 double& f1,
int& i0,
int& i1) {
2886 const auto it0 = std::prev(it1);
2888 const double dt = t - *it0;
2892 f1 = dt / (*it1 - *it0);
virtual void GetAspectRatio(const size_t i, double &dmin, double &dmax) const
static double Potential3(const std::array< double, 6 > &v, const std::array< double, 3 > &t)
Interpolate the potential in a triangle.
int FindElement5(const double x, const double y, double &t1, double &t2, double &t3, double &t4, double jac[4][4], double &det) const
Find the element for a point in curved quadratic quadrilaterals.
double GetConductivity(const size_t imat) const
Return the conductivity of a field map material.
virtual bool GetNode(const size_t i, double &x, double &y, double &z) const
double DelayedWeightingPotential(double x, double y, double z, const double t, const std::string &label) override
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
void PrintRange()
Show x, y, z, V and angular ranges.
void PrintMaterials()
List all currently defined materials.
bool SetDefaultDriftMedium()
Find lowest epsilon, check for eps = 0, set default drift media flags.
std::map< std::string, WeightingFieldCopy > m_wfieldCopies
static void Field5(const std::array< double, 8 > &v, const std::array< double, 2 > &t, double jac[4][4], const double det, double &ex, double &ey)
Interpolate the field in a curved quadrilateral.
void TimeInterpolation(const double t, double &f0, double &f1, int &i0, int &i1)
Interpolation of potential between two time slices.
void NotDriftMedium(const size_t imat)
Flag a field map materials as a non-drift medium.
std::array< double, 3 > m_mapamin
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
static double ReadDouble(char *token, double def, bool &error)
double GetPotential(const size_t i) const
virtual double GetElementVolume(const size_t i) const
int FindElement13(const double x, const double y, const double z, double &t1, double &t2, double &t3, double &t4, double jac[4][4], double &det) const
Find the element for a point in curved quadratic tetrahedra.
void DriftMedium(const size_t imat)
Flag a field map material as a drift medium.
void MapCoordinates(double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (xpos, ypos, zpos) to field map coordinates.
std::vector< std::array< double, 3 > > m_bbMax
void PrintWarning(const std::string &header)
std::array< double, 3 > m_maxBoundingBox
std::array< double, 3 > m_mapmin
std::vector< double > m_pot
void SetMedium(const size_t imat, Medium *medium)
Associate a field map material with a Medium object.
std::array< double, 3 > m_minBoundingBox
static double ScalingFactor(std::string unit)
double Potential(const double x, const double y, const double z, const std::vector< double > &potentials) const
Compute the electrostatic/weighting potential.
void UpdatePeriodicity() override
Verify periodicities.
double GetPermittivity(const size_t imat) const
Return the relative permittivity of a field map material.
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
void UpdatePeriodicityCommon()
static int ReadInteger(char *token, int def, bool &error)
std::vector< Material > m_materials
static void Field3(const std::array< double, 6 > &v, const std::array< double, 3 > &t, double jac[4][4], const double det, double &ex, double &ey)
Interpolate the field in a triangle.
void UnmapFields(double &ex, double &ey, double &ez, const double xpos, const double ypos, const double zpos, const bool xmirrored, const bool ymirrored, const bool zmirrored, const double rcoordinate, const double rotation) const
Move (ex, ey, ez) to global coordinates.
static void Field13(const std::array< double, 10 > &v, const std::array< double, 4 > &t, double jac[4][4], const double det, double &ex, double &ey, double &ez)
Interpolate the field in a curved quadratic tetrahedron.
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
static double Potential5(const std::array< double, 8 > &v, const std::array< double, 2 > &t)
Interpolate the potential in a curved quadrilateral.
void CopyWeightingPotential(const std::string &label, const std::string &labelSource, const double x, const double y, const double z, const double alpha, const double beta, const double gamma)
virtual ~ComponentFieldMap()
Destructor.
static double Potential13(const std::array< double, 10 > &v, const std::array< double, 4 > &t)
Interpolate the potential in a curved quadratic tetrahedron.
int Field(const double x, const double y, const double z, double &fx, double &fy, double &fz, int &iel, const std::vector< double > &potentials) const
Compute the electric/weighting field.
bool m_printConvergenceWarnings
std::array< double, 3 > m_mapna
std::vector< std::array< std::array< double, 3 >, 4 > > m_w12
ComponentFieldMap()=delete
Default constructor.
std::vector< Node > m_nodes
bool GetElement(const size_t i, double &vol, double &dmin, double &dmax) const
Return the volume and aspect ratio of a mesh element.
void PrintCouldNotOpen(const std::string &header, const std::string &filename) const
std::map< std::string, std::vector< double > > m_wpot
bool Check()
Check element aspect ratio.
int FindElementCube(const double x, const double y, const double z, double &t1, double &t2, double &t3, TMatrixD *&jac, std::vector< TMatrixD * > &dN) const
Find the element for a point in a cube.
std::vector< double > m_wdtimes
void UpdatePeriodicity2d()
std::vector< int > m_elementIndices
void SetGas(Medium *medium)
bool GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the coordinates of the elementary cell.
std::vector< Element > m_elements
std::array< double, 3 > m_mapamax
std::array< double, 3 > m_cells
std::array< bool, 3 > m_setang
std::vector< bool > m_degenerate
Medium * GetMedium(const size_t imat) const
Return the Medium associated to a field map material.
ElementType m_elementType
void PrintElement(const std::string &header, const double x, const double y, const double z, const double t1, const double t2, const double t3, const double t4, const size_t i, const std::vector< double > &potential) const
std::array< double, 3 > m_mapmax
std::map< std::string, std::vector< std::vector< double > > > m_dwpot
void Reset() override
Reset the component.
std::vector< std::array< double, 3 > > m_bbMin
void PrintNotReady(const std::string &header) const
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.
bool m_ready
Ready for use?
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
Abstract base class for media.
const std::string & GetName() const
Get the medium name/identifier.
bool IsDriftable() const
Is charge carrier transport enabled in this medium?
DoubleAc fabs(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)