18constexpr double Internal2Newton = 1.e-15 * Garfield::TwoPiEpsilon0 * 100.;
20std::pair<std::complex<double>, std::complex<double> > Th1(
21 const std::complex<double>& zeta,
const double p1,
const double p2) {
22 const std::complex<double> zsin =
sin(zeta);
23 const std::complex<double> zcof = 4. * zsin * zsin - 2.;
24 std::complex<double> zu = -p1 - zcof * p2;
25 std::complex<double> zunew = 1. - zcof * zu - p2;
26 const std::complex<double> zterm1 = (zunew + zu) * zsin;
27 zu = -3. * p1 - zcof * 5. * p2;
28 zunew = 1. - zcof * zu - 5. * p2;
29 const std::complex<double> zterm2 = (zunew - zu) *
cos(zeta);
30 return std::make_pair(std::move(zterm1), std::move(zterm2));
34void Cartesian2Polar(
const double x,
const double y,
double& r,
36 if (x == 0. && y == 0.) {
40 r =
sqrt(x * x + y * y);
41 theta = atan2(y, x) * Garfield::RadToDegree;
45void Polar2Cartesian(
const double r,
const double theta,
double& x,
47 const double thetap =
theta * Garfield::DegreeToRad;
54void Internal2Polar(
const double rho,
const double phi,
double& r,
63void Polar2Internal(
const double r,
const double theta,
double& rho,
66 rho = r > 0. ? log(r) : -25.;
72void Cartesian2Internal(
const double x,
const double y,
double& rho,
75 if (x == 0 && y == 0) {
83 rho = 0.5 * log(x * x + y * y);
89void Internal2Cartesian(
const double rho,
const double phi,
double& x,
95 const double r =
exp(rho);
100bool FitDipoleMoment(
const std::vector<double>& angle,
101 const std::vector<double>& volt,
102 double& ampdip,
double& phidip,
const bool dbg) {
110 const unsigned int n = angle.size();
114 constexpr unsigned int nTry = 100;
115 std::array<double, nTry> phiTry;
116 std::array<double, nTry> sumTry;
117 for (
unsigned int i = 0; i < nTry; ++i) {
119 phiTry[i] = i * Garfield::TwoPi / nTry;
121 for (
unsigned int j = 0; j < n; ++j) {
122 sumTry[i] += volt[j] *
cos(phiTry[i] - angle[j]);
126 if (sumTry[i] > sumMax) {
132 std::printf(
" Maximum of scan at phi = %12.5f, product = %12.5f\n",
140 constexpr double eps = 0.1;
141 double x1 = phiMax - eps;
143 double x3 = phiMax + eps;
147 for (
unsigned int j = 0; j < n; ++j) {
148 f1 += volt[j] *
cos(x1 - angle[j]);
149 f3 += volt[j] *
cos(x3 - angle[j]);
154 const double epsf = 1.e-3 * sumMax;
155 constexpr double epsx = 1.e-3 * Garfield::TwoPi;
156 constexpr unsigned int nMaxIter = 10;
157 for (
unsigned int i = 0; i < nMaxIter; ++i) {
158 if (dbg) std::cout <<
" Start of iteration " << i <<
".\n";
160 const double det = (f1 - f2) * x3 + (f3 - f1) * x2 + (f2 - f3) * x1;
161 if (std::abs(det) <= 0.) {
162 std::cerr <<
" Warning: Determinant = 0; parabolic search stopped.\n";
167 const double xp = ((f1 - f2) * x3 * x3 + (f3 - f1) * x2 * x2 +
168 (f2 - f3) * x1 * x1) / (2 * det);
170 for (
unsigned int j = 0; j < n; ++j) {
171 fp += volt[j] *
cos(xp - angle[j]);
176 std::printf(
" Point 1: x = %15.8f f = %15.8f\n", x1, f1);
177 std::printf(
" Point 2: x = %15.8f f = %15.8f\n", x2, f2);
178 std::printf(
" Point 3: x = %15.8f f = %15.8f\n", x3, f3);
179 std::printf(
" Parabola: x = %15.8f f = %15.8f\n", xp, fp);
182 const double tol = epsx * (epsx + std::abs(xp));
183 if (
fabs(xp - x1) < tol ||
fabs(xp - x2) < tol ||
fabs(xp - x3) < tol) {
185 std::cout <<
" Location convergence criterion satisfied.\n";
192 if (std::abs(fp - f1) < epsf * (std::abs(fp) + std::abs(f1) + epsf)) {
194 std::cout <<
" Function value convergence criterion satisfied.\n";
208 }
else if (fp > f2) {
213 }
else if (fp > f3) {
217 std::cerr <<
" Warning: Parabolic extremum is worse "
218 <<
"than current optimum; search stopped.\n";
219 std::printf(
" Point 1: x = %15.8f f = %15.8f\n", x1, f1);
220 std::printf(
" Point 2: x = %15.8f f = %15.8f\n", x2, f2);
221 std::printf(
" Point 3: x = %15.8f f = %15.8f\n", x3, f3);
222 std::printf(
" Parabola: x = %15.8f f = %15.8f\n", xp, fp);
229 std::cerr <<
" Warning: No convergence after maximum number of steps.\n"
230 <<
" Current extremum f = " << f2 <<
"\n"
231 <<
" Found for x = " << x2 <<
"\n";
237double MirrorCoordinate(
const double x,
const double xp,
const double xw,
241 double cx = xp - sx * int(round((xp - xw) / sx));
242 return 2 * cx -
x - xw;
258 if (!m_cellset && !Prepare())
return nullptr;
260 double xpos = xin, ypos = yin;
261 if (m_polar) Cartesian2Internal(xin, yin, xpos, ypos);
264 xpos -= m_sx * int(round(xin / m_sx));
267 if (m_pery && m_tube) {
268 Cartesian2Polar(xin, yin, xpos, ypos);
269 arot = RadToDegree * m_sy * int(round(DegreeToRad * ypos / m_sy));
271 Polar2Cartesian(xpos, ypos, xpos, ypos);
273 ypos -= m_sy * int(round(ypos / m_sy));
277 if (m_perx && m_ynplan[0] && xpos <= m_coplan[0]) xpos += m_sx;
278 if (m_perx && m_ynplan[1] && xpos >= m_coplan[1]) xpos -= m_sx;
279 if (m_pery && m_ynplan[2] && ypos <= m_coplan[2]) ypos += m_sy;
280 if (m_pery && m_ynplan[3] && ypos >= m_coplan[3]) ypos -= m_sy;
284 if (!InTube(xpos, ypos, m_cotube, m_ntube))
return nullptr;
286 if ((m_ynplan[0] && xpos < m_coplan[0]) ||
287 (m_ynplan[1] && xpos > m_coplan[1]) ||
288 (m_ynplan[2] && ypos < m_coplan[2]) ||
289 (m_ynplan[3] && ypos > m_coplan[3])) {
295 for (
const auto& wire : m_w) {
296 double dx = xpos - wire.x;
297 double dy = ypos - wire.y;
299 if (m_perx) dx -= m_sx * int(round(dx / m_sx));
300 if (m_pery) dy -= m_sy * int(round(dy / m_sy));
302 if (dx * dx + dy * dy < wire.r * wire.r)
return nullptr;
309 if (!m_cellset && !Prepare()) {
310 std::cerr <<
m_className <<
"::GetVoltageRange: Cell not set up.\n";
320 double& x0,
double& y0,
double& z0,
321 double& x1,
double& y1,
double& z1) {
331 double& x0,
double& y0,
double& z0,
332 double& x1,
double& y1,
double& z1) {
333 if (!m_cellset && !Prepare())
return false;
335 double rmax, thetamax;
336 Internal2Polar(m_xmax, m_ymax, rmax, thetamax);
358 if (!m_cellset && !Prepare()) {
359 std::cerr <<
m_className <<
"::PrintCell: Cell not set up.\n";
363 <<
"::PrintCell: Cell identification: " <<
GetCellType() <<
"\n";
366 std::cout <<
" Table of the wires\n";
368 std::cout <<
" Nr Diameter r phi Voltage";
370 std::cout <<
" Nr Diameter x y Voltage";
372 std::cout <<
" Charge Tension Length Density Label\n";
374 std::cout <<
" [micron] [cm] [deg] [Volt]";
376 std::cout <<
" [micron] [cm] [cm] [Volt]";
378 std::cout <<
" [pC/cm] [g] [cm] [g/cm3]\n";
379 for (
unsigned int i = 0; i < m_nWires; ++i) {
380 const auto& w = m_w[i];
385 Internal2Polar(w.x, w.y, xw, yw);
389 "%4d %9.2f %9.4f %9.4f %9.3f %12.4f %9.2f %9.2f %9.2f \"%s\"\n", i,
390 1.e4 * dw, xw, yw, w.v, w.e * TwoPiEpsilon0 * 1.e-3, w.tension,
391 w.u, w.density, w.type.c_str());
399 }
else if (m_ntube == 3) {
400 shape =
"Triangular";
401 }
else if (m_ntube == 4) {
403 }
else if (m_ntube == 5) {
404 shape =
"Pentagonal";
405 }
else if (m_ntube == 6) {
407 }
else if (m_ntube == 7) {
408 shape =
"Heptagonal";
409 }
else if (m_ntube == 8) {
412 shape =
"Polygonal with " + std::to_string(m_ntube) +
" corners";
414 std::cout <<
" Enclosing tube\n"
415 <<
" Potential: " << m_vttube <<
" V\n"
416 <<
" Radius: " << m_cotube <<
" cm\n"
417 <<
" Shape: " << shape <<
"\n"
418 <<
" Label: " << m_planes[4].type <<
"\n";
421 if (m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3]) {
422 std::cout <<
" Equipotential planes\n";
424 const std::string xr = m_polar ?
"r" :
"x";
425 if (m_ynplan[0] && m_ynplan[1]) {
426 std::cout <<
" There are two planes at constant " << xr <<
":\n";
427 }
else if (m_ynplan[0] || m_ynplan[1]) {
428 std::cout <<
" There is one plane at constant " << xr <<
":\n";
430 for (
unsigned int i = 0; i < 2; ++i) {
431 if (!m_ynplan[i])
continue;
433 std::cout <<
" r = " << exp(m_coplan[i]) <<
" cm, ";
435 std::cout <<
" x = " << m_coplan[i] <<
" cm, ";
437 if (fabs(m_vtplan[i]) > 1.e-4) {
438 std::cout <<
"potential = " << m_vtplan[i] <<
" V, ";
440 std::cout <<
"earthed, ";
442 const auto& plane = m_planes[i];
443 if (plane.type.empty() && plane.type !=
"?") {
444 std::cout <<
"label = " << plane.type <<
", ";
446 const unsigned int nStrips = plane.strips1.size() + plane.strips2.size();
447 const unsigned int nPixels = plane.pixels.size();
448 if (nStrips == 0 && nPixels == 0) {
449 std::cout <<
"no strips or pixels.\n";
450 }
else if (nPixels == 0) {
451 std::cout << nStrips <<
" strips.\n";
452 }
else if (nStrips == 0) {
453 std::cout << nPixels <<
" pixels.\n";
455 std::cout << nStrips <<
" strips, " << nPixels <<
" pixels.\n";
457 for (
const auto& strip : plane.strips2) {
460 double gap = i == 0 ? expm1(strip.gap) : -expm1(-strip.gap);
461 gap *= exp(m_coplan[i]);
462 std::cout << RadToDegree * strip.smin <<
" < phi < "
463 << RadToDegree * strip.smax
464 <<
" degrees, gap = " << gap <<
" cm";
466 std::cout << strip.smin <<
" < y < " << strip.smax
467 <<
" cm, gap = " << strip.gap <<
" cm";
469 if (!strip.type.empty() && strip.type !=
"?") {
470 std::cout <<
" (\"" << strip.type <<
"\")";
474 for (
const auto& strip : plane.strips1) {
475 std::cout <<
" " << strip.smin <<
" < z < " << strip.smax;
477 double gap = i == 0 ? expm1(strip.gap) : -expm1(-strip.gap);
478 gap *= exp(m_coplan[i]);
479 std::cout <<
" cm, gap = " << gap <<
" cm";
481 std::cout <<
" cm, gap = " << strip.gap <<
" cm";
483 if (!strip.type.empty() && strip.type !=
"?") {
484 std::cout <<
" (\"" << strip.type <<
"\")";
488 for (
const auto& pix : plane.pixels) {
491 std::cout << RadToDegree * pix.smin <<
" < phi < "
492 << RadToDegree * pix.smax <<
" degrees, ";
494 std::cout << pix.smin <<
" < y < " << pix.smax <<
" cm, ";
496 std::cout << pix.zmin <<
" < z < " << pix.zmax <<
" cm, gap = ";
498 double gap = i == 0 ? expm1(pix.gap) : -expm1(-pix.gap);
499 gap *= exp(m_coplan[i]);
500 std::cout << gap <<
" cm";
502 std::cout << pix.gap <<
" cm";
504 if (!pix.type.empty() && pix.type !=
"?") {
505 std::cout <<
" (\"" << pix.type <<
"\")";
511 const std::string yphi = m_polar ?
"phi" :
"y";
512 if (m_ynplan[2] && m_ynplan[3]) {
513 std::cout <<
" There are two planes at constant " << yphi <<
":\n";
514 }
else if (m_ynplan[2] || m_ynplan[3]) {
515 std::cout <<
" There is one plane at constant " << yphi <<
":\n";
517 for (
unsigned int i = 2; i < 4; ++i) {
518 if (!m_ynplan[i])
continue;
520 std::cout <<
" phi = " << RadToDegree * m_coplan[i] <<
" degrees, ";
522 std::cout <<
" y = " << m_coplan[i] <<
" cm, ";
524 if (fabs(m_vtplan[i]) > 1.e-4) {
525 std::cout <<
"potential = " << m_vtplan[i] <<
" V, ";
527 std::cout <<
"earthed, ";
529 const auto& plane = m_planes[i];
530 if (plane.type.empty() && plane.type !=
"?") {
531 std::cout <<
"label = " << plane.type <<
", ";
533 const unsigned int nStrips = plane.strips1.size() + plane.strips2.size();
534 const unsigned int nPixels = plane.pixels.size();
535 if (nStrips == 0 && nPixels == 0) {
536 std::cout <<
"no strips or pixels.\n";
537 }
else if (nPixels == 0) {
538 std::cout << nStrips <<
" strips.\n";
539 }
else if (nStrips == 0) {
540 std::cout << nPixels <<
" pixels.\n";
542 std::cout << nStrips <<
" strips, " << nPixels <<
" pixels.\n";
544 for (
const auto& strip : plane.strips2) {
547 std::cout << exp(strip.smin) <<
" < r < " << exp(strip.smax)
548 <<
" cm, gap = " << RadToDegree * strip.gap <<
" degrees";
550 std::cout << strip.smin <<
" < x < " << strip.smax
551 <<
" cm, gap = " << strip.gap <<
" cm";
553 if (!strip.type.empty() && strip.type !=
"?") {
554 std::cout <<
" (\"" << strip.type <<
"\")";
558 for (
const auto& strip : plane.strips1) {
559 std::cout <<
" " << strip.smin <<
" < z < " << strip.smax;
561 std::cout <<
" cm, gap = " << RadToDegree * strip.gap <<
" degrees";
563 std::cout <<
" cm, gap = " << strip.gap <<
" cm";
565 if (!strip.type.empty() && strip.type !=
"?") {
566 std::cout <<
" (\"" << strip.type <<
"\")";
570 for (
const auto& pix : plane.pixels) {
573 std::cout << exp(pix.smin) <<
" < r < " << exp(pix.smax) <<
" cm, ";
575 std::cout << pix.smin <<
" < x < " << pix.smax <<
" cm, ";
577 std::cout << pix.zmin <<
" < z < " << pix.zmax <<
" cm, gap = ";
579 std::cout << RadToDegree * pix.gap <<
" degrees";
581 std::cout << pix.gap <<
" cm";
583 if (!pix.type.empty() && pix.type !=
"?") {
584 std::cout <<
" (\"" << pix.type <<
"\")";
591 std::cout <<
" Periodicity\n";
593 std::cout <<
" The cell is repeated every ";
595 std::cout << exp(m_sx) <<
" cm in r.\n";
597 std::cout << m_sx <<
" cm in x.\n";
601 std::cout <<
" The cell is not periodic in r.\n";
603 std::cout <<
" The cell has no translation periodicity in x.\n";
607 std::cout <<
" The cell is repeated every ";
609 std::cout << RadToDegree * m_sy <<
" degrees in phi.\n";
611 std::cout << m_sy <<
" cm in y.\n";
615 std::cout <<
" The cell is not periodic in phi.\n";
617 std::cout <<
" The cell has no translation periodicity in y.\n";
620 std::cout <<
" Other data\n";
621 std::cout <<
" Gravity vector: (" << m_down[0] <<
", " << m_down[1]
622 <<
", " << m_down[2] <<
") [g].\n";
623 std::cout <<
" Cell dimensions:\n ";
625 std::cout << m_xmin <<
" < x < " << m_xmax <<
" cm, " << m_ymin <<
" < y < "
626 << m_ymax <<
" cm.\n";
629 Internal2Polar(m_xmin, m_ymin, xminp, yminp);
631 Internal2Polar(m_xmax, m_ymax, xmaxp, ymaxp);
632 std::cout << xminp <<
" < r < " << xmaxp <<
" cm, " << yminp <<
" < phi < "
633 << ymaxp <<
" degrees.\n";
635 std::cout <<
" Potential range:\n " << m_vmin <<
" < V < " << m_vmax
638 if (!(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3] || m_tube)) {
639 std::cout <<
" All voltages have been shifted by " << m_v0
640 <<
" V to avoid net wire charge.\n";
644 for (
const auto& w : m_w) sum += w.e;
645 std::cout <<
" The net charge on the wires is "
646 << 1.e-3 * TwoPiEpsilon0 * sum <<
" pC/cm.\n";
651 const double z0,
const double xx1,
652 const double yy1,
const double z1,
653 double& xc,
double& yc,
double& zc,
654 const bool centre,
double& rc) {
659 if (m_w.empty())
return false;
666 Cartesian2Internal(xx0, yy0, x0, y0);
667 Cartesian2Internal(xx1, yy1, x1, y1);
669 const double dx = x1 - x0;
670 const double dy = y1 - y0;
671 const double d2 = dx * dx + dy * dy;
673 if (d2 < Small)
return false;
674 const double invd2 = 1. / d2;
677 if ((m_perx && fabs(dx) >= m_sx) || (m_pery && fabs(dy) >= m_sy)) {
679 <<
" Particle crossed more than one period.\n";
687 const double xm = 0.5 * (x0 + x1);
688 const double ym = 0.5 * (y0 + y1);
690 for (
const auto& wire : m_w) {
693 xw += m_sx * int(round((xm - xw) / m_sx));
697 yw += m_sy * int(round((ym - yw) / m_sy));
700 const double xIn0 = dx * (xw - x0) + dy * (yw - y0);
702 if (xIn0 < 0.)
continue;
703 const double xIn1 = -(dx * (xw - x1) + dy * (yw - y1));
705 if (xIn1 < 0.)
continue;
707 const double xw0 = xw - x0;
708 const double xw1 = xw - x1;
709 const double yw0 = yw - y0;
710 const double yw1 = yw - y1;
711 const double dw02 = xw0 * xw0 + yw0 * yw0;
712 const double dw12 = xw1 * xw1 + yw1 * yw1;
713 if (xIn1 * xIn1 * dw02 > xIn0 * xIn0 * dw12) {
714 dMin2 = dw02 - xIn0 * xIn0 * invd2;
716 dMin2 = dw12 - xIn1 * xIn1 * invd2;
719 const double r2 = wire.r * wire.r;
724 Internal2Cartesian(xw, yw, xc, yc);
731 const double p = -xIn0 * invd2;
732 const double q = (dw02 - r2) * invd2;
733 const double s = sqrt(p * p - q);
734 const double t = std::min(-p + s, -p - s);
736 Internal2Cartesian(x0 + t * dx, y0 + t * dy, xc, yc);
741 zc = z0 + t * (z1 - z0);
744 if (m_polar) rc *= exp(wire.x);
752 const double yin,
const double zin,
753 double& xw,
double& yw,
759 Cartesian2Internal(xin, yin, x0, y0);
762 int nX = 0, nY = 0, nPhi = 0;
764 nX = int(round(x0 / m_sx));
767 if (m_pery && m_tube) {
768 Cartesian2Polar(xin, yin, x0, y0);
769 nPhi = int(round(DegreeToRad * y0 / m_sy));
770 y0 -= RadToDegree * m_sy * nPhi;
771 Polar2Cartesian(x0, y0, x0, y0);
773 nY = int(round(y0 / m_sy));
777 std::array<bool, 4> shift = {
false,
false,
false,
false};
778 if (m_perx && m_ynplan[0] && x0 <= m_coplan[0]) {
782 if (m_perx && m_ynplan[1] && x0 >= m_coplan[1]) {
786 if (m_pery && m_ynplan[2] && y0 <= m_coplan[2]) {
790 if (m_pery && m_ynplan[3] && y0 >= m_coplan[3]) {
795 for (
const auto& wire : m_w) {
797 if (qin * wire.e > 0.)
continue;
798 const double dxw0 = wire.x - x0;
799 const double dyw0 = wire.y - y0;
800 const double r2 = dxw0 * dxw0 + dyw0 * dyw0;
801 const double rTrap = wire.r * wire.nTrap;
802 if (r2 < rTrap * rTrap) {
806 if (shift[0]) xw -= m_sx;
807 if (shift[1]) xw += m_sx;
808 if (shift[2]) yw -= m_sy;
809 if (shift[3]) yw += m_sy;
810 if (m_pery && m_tube) {
812 Cartesian2Polar(xw, yw, rhow, phiw);
813 phiw += RadToDegree * m_sy * nPhi;
814 Polar2Cartesian(rhow, phiw, xw, yw);
818 if (m_perx) xw += m_sx * nX;
820 Internal2Cartesian(xw, yw, xw, yw);
824 std::cout <<
m_className <<
"::IsInTrapRadius: (" << xin <<
", "
825 << yin <<
", " << zin <<
")" <<
" within trap radius.\n";
835 const double diameter,
836 const double voltage,
837 const std::string& label,
838 const double length,
const double tension,
839 double rho,
const int ntrap) {
841 if (diameter <= 0.) {
842 std::cerr <<
m_className <<
"::AddWire: Unphysical wire diameter.\n";
847 std::cerr <<
m_className <<
"::AddWire: Unphysical wire tension.\n";
852 std::cerr <<
m_className <<
"::AddWire: Unphysical wire density.\n";
857 std::cerr <<
m_className <<
"::AddWire: Unphysical wire length.\n";
862 std::cerr <<
m_className <<
"::AddWire: Nbr. of trap radii must be > 0.\n";
866 if (m_polar && x <= diameter) {
867 std::cerr <<
m_className <<
"::AddWire: Wire is too close to the origin.\n";
874 double r = 0., phi = 0.;
875 Polar2Internal(x, y, r, phi);
878 wire.r = 0.5 * diameter / x;
882 wire.r = 0.5 * diameter;
890 wire.tension = tension;
893 m_w.push_back(std::move(wire));
903 const std::string& label) {
906 std::cerr <<
m_className <<
"::AddTube: Unphysical tube dimension.\n";
910 if (nEdges < 3 && nEdges != 0) {
911 std::cerr <<
m_className <<
"::AddTube: Unphysical number of tube edges ("
919 <<
" Warning: Existing tube settings will be overwritten.\n";
928 m_cotube2 = radius * radius;
933 m_planes[4].type = label;
934 m_planes[4].ind = -1;
942 const std::string& label) {
945 <<
" Not compatible with polar coordinates; ignored.\n";
948 if (m_ynplan[0] && m_ynplan[1]) {
950 <<
" Cannot have more than two planes at constant x.\n";
958 m_planes[1].type = label;
959 m_planes[1].ind = -1;
964 m_planes[0].type = label;
965 m_planes[0].ind = -1;
974 const std::string& label) {
977 <<
" Not compatible with polar coordinates; ignored.\n";
980 if (m_ynplan[2] && m_ynplan[3]) {
982 <<
" Cannot have more than two planes at constant y.\n";
990 m_planes[3].type = label;
991 m_planes[3].ind = -1;
996 m_planes[2].type = label;
997 m_planes[2].ind = -1;
1006 const std::string& label) {
1009 <<
" Not compatible with Cartesian coordinates; ignored.\n";
1014 <<
" Radius must be larger than zero; plane ignored.\n";
1018 if (m_ynplan[0] && m_ynplan[1]) {
1020 <<
" Cannot have more than two circular planes.\n";
1026 m_coplan[1] = log(r);
1028 m_planes[1].type = label;
1029 m_planes[1].ind = -1;
1032 m_coplan[0] = log(r);
1034 m_planes[0].type = label;
1035 m_planes[0].ind = -1;
1044 const std::string& label) {
1047 <<
" Not compatible with Cartesian coordinates; ignored.\n";
1050 if (m_ynplan[2] && m_ynplan[3]) {
1052 <<
" Cannot have more than two planes at constant phi.\n";
1058 m_coplan[3] = phi * DegreeToRad;
1060 m_planes[3].type = label;
1061 m_planes[3].ind = -1;
1064 m_coplan[2] = phi * DegreeToRad;
1066 m_planes[2].type = label;
1067 m_planes[2].ind = -1;
1069 if (m_pery && std::abs(m_sy - TwoPi) < 1.e-4) {
1082 const std::string& label,
1084 if (m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1085 std::cerr <<
m_className <<
"::AddStripOnPlaneX:\n"
1086 <<
" There are no planes at constant x.\n";
1090 if (dir !=
'y' && dir !=
'Y' && dir !=
'z' && dir !=
'Z') {
1091 std::cerr <<
m_className <<
"::AddStripOnPlaneX:\n"
1092 <<
" Invalid direction (" << dir <<
").\n"
1093 <<
" Only strips in y or z direction are possible.\n";
1097 if (fabs(smax - smin) < Small) {
1098 std::cerr <<
m_className <<
"::AddStripOnPlaneX:\n"
1099 <<
" Strip width must be greater than zero.\n";
1104 newStrip.type = label;
1106 newStrip.smin = std::min(smin, smax);
1107 newStrip.smax = std::max(smin, smax);
1108 newStrip.gap = gap > Small ? gap : -1.;
1112 const double d0 = fabs(m_coplan[0] - x);
1113 const double d1 = fabs(m_coplan[1] - x);
1114 if (d1 < d0) iplane = 1;
1117 if (dir ==
'y' || dir ==
'Y') {
1118 m_planes[iplane].strips1.push_back(std::move(newStrip));
1120 m_planes[iplane].strips2.push_back(std::move(newStrip));
1127 const std::string& label,
1129 if (m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1130 std::cerr <<
m_className <<
"::AddStripOnPlaneY:\n"
1131 <<
" There are no planes at constant y.\n";
1135 if (dir !=
'x' && dir !=
'X' && dir !=
'z' && dir !=
'Z') {
1136 std::cerr <<
m_className <<
"::AddStripOnPlaneY:\n"
1137 <<
" Invalid direction (" << dir <<
").\n"
1138 <<
" Only strips in x or z direction are possible.\n";
1142 if (fabs(smax - smin) < Small) {
1143 std::cerr <<
m_className <<
"::AddStripOnPlaneY:\n"
1144 <<
" Strip width must be greater than zero.\n";
1149 newStrip.type = label;
1151 newStrip.smin = std::min(smin, smax);
1152 newStrip.smax = std::max(smin, smax);
1153 newStrip.gap = gap > Small ? gap : -1.;
1157 const double d2 = fabs(m_coplan[2] - y);
1158 const double d3 = fabs(m_coplan[3] - y);
1159 if (d3 < d2) iplane = 3;
1162 if (dir ==
'x' || dir ==
'X') {
1163 m_planes[iplane].strips1.push_back(std::move(newStrip));
1165 m_planes[iplane].strips2.push_back(std::move(newStrip));
1172 const std::string& label,
1174 if (!m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1175 std::cerr <<
m_className <<
"::AddStripOnPlaneR:\n"
1176 <<
" There are no planes at constant r.\n";
1180 if (dir !=
'p' && dir !=
'P' && dir !=
'z' && dir !=
'Z') {
1181 std::cerr <<
m_className <<
"::AddStripOnPlaneR:\n"
1182 <<
" Invalid direction (" << dir <<
").\n"
1183 <<
" Only strips in p(hi) or z direction are possible.\n";
1187 if (fabs(smax - smin) < Small) {
1188 std::cerr <<
m_className <<
"::AddStripOnPlaneR:\n"
1189 <<
" Strip width must be greater than zero.\n";
1194 newStrip.type = label;
1196 if (dir ==
'z' || dir ==
'Z') {
1197 const double phimin = smin * DegreeToRad;
1198 const double phimax = smax * DegreeToRad;
1199 newStrip.smin = std::min(phimin, phimax);
1200 newStrip.smax = std::max(phimin, phimax);
1202 newStrip.smin = std::min(smin, smax);
1203 newStrip.smax = std::max(smin, smax);
1205 newStrip.gap = gap > Small ? gap : -1.;
1209 const double rho = r > 0. ? log(r) : -25.;
1210 const double d0 = fabs(m_coplan[0] - rho);
1211 const double d1 = fabs(m_coplan[1] - rho);
1212 if (d1 < d0) iplane = 1;
1215 if (dir ==
'p' || dir ==
'P') {
1216 m_planes[iplane].strips1.push_back(std::move(newStrip));
1218 m_planes[iplane].strips2.push_back(std::move(newStrip));
1226 const std::string& label,
1228 if (!m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1229 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1230 <<
" There are no planes at constant phi.\n";
1234 if (dir !=
'r' && dir !=
'R' && dir !=
'z' && dir !=
'Z') {
1235 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1236 <<
" Invalid direction (" << dir <<
").\n"
1237 <<
" Only strips in r or z direction are possible.\n";
1241 if (fabs(smax - smin) < Small) {
1242 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1243 <<
" Strip width must be greater than zero.\n";
1248 newStrip.type = label;
1250 if (dir==
'z' || dir ==
'Z') {
1251 if (smin < Small || smax < Small) {
1252 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1253 <<
" Radius must be greater than zero.\n";
1256 const double rhomin = log(smin);
1257 const double rhomax = log(smax);
1258 newStrip.smin = std::min(rhomin, rhomax);
1259 newStrip.smax = std::max(rhomin, rhomax);
1261 newStrip.smin = std::min(smin, smax);
1262 newStrip.smax = std::max(smin, smax);
1264 newStrip.gap = gap > Small ? DegreeToRad * gap : -1.;
1268 const double d2 = fabs(m_coplan[2] - phi * DegreeToRad);
1269 const double d3 = fabs(m_coplan[3] - phi * DegreeToRad);
1270 if (d3 < d2) iplane = 3;
1273 if (dir ==
'r' || dir ==
'R') {
1274 m_planes[iplane].strips1.push_back(std::move(newStrip));
1276 m_planes[iplane].strips2.push_back(std::move(newStrip));
1282 const double x,
const double ymin,
const double ymax,
const double zmin,
1283 const double zmax,
const std::string& label,
const double gap,
1285 if (m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1286 std::cerr <<
m_className <<
"::AddPixelOnPlaneX:\n"
1287 <<
" There are no planes at constant x.\n";
1291 if (fabs(ymax - ymin) < Small || fabs(zmax - zmin) < Small) {
1292 std::cerr <<
m_className <<
"::AddPixelOnPlaneX:\n"
1293 <<
" Pixel width must be greater than zero.\n";
1300 pixel.smin = std::min(ymin, ymax);
1301 pixel.smax = std::max(ymin, ymax);
1302 pixel.zmin = std::min(zmin, zmax);
1303 pixel.zmax = std::max(zmin, zmax);
1304 pixel.gap = gap > Small ? gap : -1.;
1305 if (fabs(rot) > 1.e-9) {
1306 pixel.cphi = cos(rot);
1307 pixel.sphi = sin(rot);
1312 const double d0 = fabs(m_coplan[0] - x);
1313 const double d1 = fabs(m_coplan[1] - x);
1314 if (d1 < d0) iplane = 1;
1317 m_planes[iplane].pixels.push_back(std::move(pixel));
1321 const double y,
const double xmin,
const double xmax,
const double zmin,
1322 const double zmax,
const std::string& label,
const double gap,
1324 if (m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1325 std::cerr <<
m_className <<
"::AddPixelOnPlaneY:\n"
1326 <<
" There are no planes at constant y.\n";
1330 if (fabs(xmax - xmin) < Small || fabs(zmax - zmin) < Small) {
1331 std::cerr <<
m_className <<
"::AddPixelOnPlaneY:\n"
1332 <<
" Pixel width must be greater than zero.\n";
1339 pixel.smin = std::min(xmin, xmax);
1340 pixel.smax = std::max(xmin, xmax);
1341 pixel.zmin = std::min(zmin, zmax);
1342 pixel.zmax = std::max(zmin, zmax);
1343 pixel.gap = gap > Small ? gap : -1.;
1344 if (fabs(rot) > 1.e-9) {
1345 pixel.cphi = cos(rot);
1346 pixel.sphi = sin(rot);
1351 const double d0 = fabs(m_coplan[2] - y);
1352 const double d1 = fabs(m_coplan[3] - y);
1353 if (d1 < d0) iplane = 3;
1356 m_planes[iplane].pixels.push_back(std::move(pixel));
1360 const double r,
const double phimin,
const double phimax,
1361 const double zmin,
const double zmax,
const std::string& label,
1363 if (!m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1364 std::cerr <<
m_className <<
"::AddPixelOnPlaneR:\n"
1365 <<
" There are no planes at constant r.\n";
1369 if (fabs(phimax - phimin) < Small || fabs(zmax - zmin) < Small) {
1370 std::cerr <<
m_className <<
"::AddPixelOnPlaneR:\n"
1371 <<
" Pixel width must be greater than zero.\n";
1378 const double smin = phimin * DegreeToRad;
1379 const double smax = phimax * DegreeToRad;
1380 pixel.smin = std::min(smin, smax);
1381 pixel.smax = std::max(smin, smax);
1382 pixel.zmin = std::min(zmin, zmax);
1383 pixel.zmax = std::max(zmin, zmax);
1384 pixel.gap = gap > Small ? gap : -1.;
1388 const double rho = r > 0. ? log(r) : -25.;
1389 const double d0 = fabs(m_coplan[0] - rho);
1390 const double d1 = fabs(m_coplan[1] - rho);
1391 if (d1 < d0) iplane = 1;
1394 m_planes[iplane].pixels.push_back(std::move(pixel));
1398 const double phi,
const double rmin,
const double rmax,
1399 const double zmin,
const double zmax,
const std::string& label,
1401 if (!m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1402 std::cerr <<
m_className <<
"::AddPixelOnPlanePhi:\n"
1403 <<
" There are no planes at constant phi.\n";
1407 if (fabs(rmax - rmin) < Small || fabs(zmax - zmin) < Small) {
1408 std::cerr <<
m_className <<
"::AddPixelOnPlanePhi:\n"
1409 <<
" Pixel width must be greater than zero.\n";
1412 if (rmin < Small || rmax < Small) {
1413 std::cerr <<
m_className <<
"::AddPixelOnPlanePhi:\n"
1414 <<
" Radius must be greater than zero.\n";
1420 const double smin = log(rmin);
1421 const double smax = log(rmax);
1422 pixel.smin = std::min(smin, smax);
1423 pixel.smax = std::max(smin, smax);
1424 pixel.zmin = std::min(zmin, zmax);
1425 pixel.zmax = std::max(zmin, zmax);
1426 pixel.gap = gap > Small ? DegreeToRad * gap : -1.;
1430 const double d0 = fabs(m_coplan[2] - phi * DegreeToRad);
1431 const double d1 = fabs(m_coplan[3] - phi * DegreeToRad);
1432 if (d1 < d0) iplane = 3;
1435 m_planes[iplane].pixels.push_back(std::move(pixel));
1447 std::cerr <<
m_className <<
"::SetPeriodicityX:\n"
1448 <<
" Cannot use x-periodicity with polar coordinates.\n";
1452 std::cerr <<
m_className <<
"::SetPeriodicityX:\n"
1453 <<
" Periodic length must be greater than zero.\n";
1459 UpdatePeriodicity();
1464 std::cerr <<
m_className <<
"::SetPeriodicityY:\n"
1465 <<
" Cannot use y-periodicity with polar coordinates.\n";
1469 std::cerr <<
m_className <<
"::SetPeriodicityY:\n"
1470 <<
" Periodic length must be greater than zero.\n";
1476 UpdatePeriodicity();
1480 if (!m_polar && !m_tube) {
1481 std::cerr <<
m_className <<
"::SetPeriodicityPhi:\n"
1482 <<
" Cannot use phi-periodicity with Cartesian coordinates.\n";
1485 if (std::abs(360. - s *
int(360. / s)) > 1.e-4) {
1486 std::cerr <<
m_className <<
"::SetPeriodicityPhi:\n"
1487 <<
" Phi periods must divide 360; ignored.\n";
1492 m_sy = DegreeToRad * s;
1493 m_mtube = int(360. / s);
1494 UpdatePeriodicity();
1518 if (!
m_periodic[1] || (!m_polar && !m_tube)) {
1523 s = RadToDegree * m_sy;
1527void ComponentAnalyticField::UpdatePeriodicity() {
1535 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n";
1536 std::cerr <<
" Periodicity in x direction was enabled"
1537 <<
" but periodic length is not set.\n";
1551 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n";
1552 std::cerr <<
" Periodicity in y direction was enabled"
1553 <<
" but periodic length is not set.\n";
1563 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1564 <<
" Periodicity in z is not possible.\n";
1568 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1569 <<
" Mirror periodicity is not possible.\n";
1573 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1574 <<
" Axial periodicity is not possible.\n";
1579 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1580 <<
" Rotation symmetry is not possible.\n";
1586 std::cout <<
m_className <<
"::SetCartesianCoordinates:\n "
1587 <<
"Switching to Cartesian coordinates; resetting the cell.\n";
1595 std::cout <<
m_className <<
"::SetPolarCoordinates:\n "
1596 <<
"Switching to polar coordinates; resetting the cell.\n";
1606 const double z,
const double q) {
1612 charge.e = q / FourPiEpsilon0;
1613 m_ch3d.push_back(std::move(charge));
1624 if (m_ch3d.empty()) {
1625 std::cout <<
" No charges present.\n";
1628 std::cout <<
" x [cm] y [cm] z [cm] charge [fC]\n";
1629 for (
const auto& charge : m_ch3d) {
1630 std::cout <<
" " << std::setw(9) << charge.x <<
" " << std::setw(9)
1631 << charge.y <<
" " << std::setw(9) << charge.z <<
" "
1632 << std::setw(11) << charge.e * FourPiEpsilon0 <<
"\n";
1639 }
else if (m_ynplan[0] && m_ynplan[1]) {
1641 }
else if (m_ynplan[0] || m_ynplan[1]) {
1650 }
else if (m_ynplan[2] && m_ynplan[3]) {
1652 }
else if (m_ynplan[2] || m_ynplan[3]) {
1661 }
else if (m_ynplan[0] && m_ynplan[1]) {
1663 }
else if (m_ynplan[0] || m_ynplan[1]) {
1672 }
else if (m_ynplan[2] && m_ynplan[3]) {
1674 }
else if (m_ynplan[2] || m_ynplan[3]) {
1681 double& diameter,
double& voltage,
1682 std::string& label,
double& length,
1683 double& charge,
int& ntrap)
const {
1684 if (i >= m_nWires) {
1685 std::cerr <<
m_className <<
"::GetWire: Index out of range.\n";
1690 double r = 0., theta = 0.;
1691 Internal2Polar(m_w[i].x, m_w[i].y, r, theta);
1694 diameter = 2 * m_w[i].r * r;
1698 diameter = 2 * m_w[i].r;
1701 label = m_w[i].type;
1704 ntrap = m_w[i].nTrap;
1710 std::string& label)
const {
1711 if (m_polar || i >= 2 || (i == 1 && !m_ynplan[1])) {
1712 std::cerr <<
m_className <<
"::GetPlaneX: Index out of range.\n";
1717 voltage = m_vtplan[i];
1718 label = m_planes[i].type;
1724 std::string& label)
const {
1725 if (m_polar || i >= 2 || (i == 1 && !m_ynplan[3])) {
1726 std::cerr <<
m_className <<
"::GetPlaneY: Index out of range.\n";
1730 y = m_coplan[i + 2];
1731 voltage = m_vtplan[i + 2];
1732 label = m_planes[i + 2].type;
1738 std::string& label)
const {
1739 if (!m_polar || i >= 2 || (i == 1 && !m_ynplan[1])) {
1740 std::cerr <<
m_className <<
"::GetPlaneR: Index out of range.\n";
1744 r = exp(m_coplan[i]);
1745 voltage = m_vtplan[i];
1746 label = m_planes[i].type;
1752 std::string& label)
const {
1753 if (!m_polar || i >= 2 || (i == 1 && !m_ynplan[3])) {
1754 std::cerr <<
m_className <<
"::GetPlanePhi: Index out of range.\n";
1758 phi = RadToDegree * m_coplan[i + 2];
1759 voltage = m_vtplan[i + 2];
1760 label = m_planes[i + 2].type;
1765 std::string& label)
const {
1766 if (!m_tube)
return false;
1770 label = m_planes[4].type;
1775 double& ex,
double& ey) {
1786 if (iw >= m_nWires) {
1787 std::cerr <<
m_className <<
"::ElectricFieldAtWire: Index out of range.\n";
1791 std::vector<bool> cnalso(m_nWires,
true);
1794 const double xpos = m_w[iw].x;
1795 const double ypos = m_w[iw].y;
1797 switch (m_cellType) {
1799 FieldAtWireA00(xpos, ypos, ex, ey, cnalso);
1802 FieldAtWireB1X(xpos, ypos, ex, ey, cnalso);
1805 FieldAtWireB1Y(xpos, ypos, ex, ey, cnalso);
1808 FieldAtWireB2X(xpos, ypos, ex, ey, cnalso);
1811 FieldAtWireB2Y(xpos, ypos, ex, ey, cnalso);
1814 FieldAtWireC10(xpos, ypos, ex, ey, cnalso);
1817 FieldAtWireC2X(xpos, ypos, ex, ey, cnalso);
1820 FieldAtWireC2Y(xpos, ypos, ex, ey, cnalso);
1823 FieldAtWireC30(xpos, ypos, ex, ey, cnalso);
1826 FieldAtWireD10(xpos, ypos, ex, ey, cnalso);
1829 FieldAtWireD20(xpos, ypos, ex, ey, cnalso);
1832 FieldAtWireD30(xpos, ypos, ex, ey, cnalso);
1835 std::cerr <<
m_className <<
"::ElectricFieldAtWire:\n"
1836 <<
" Unknown cell type (id " << m_cellType <<
")\n";
1843 const double r = exp(xpos);
1844 const double er = ex / r;
1845 const double ep = ey / r;
1846 const double ct = cos(ypos);
1847 const double st = sin(ypos);
1848 ex = +ct * er - st * ep;
1849 ey = +st * er + ct * ep;
1855 const unsigned int nY) {
1857 std::cerr <<
m_className <<
"::SetScanningGrid:\n"
1858 <<
" Number of x-lines must be > 1.\n";
1863 std::cerr <<
m_className <<
"::SetScanningGrid:\n"
1864 <<
" Number of y-lines must be > 1.\n";
1873 const double ymax) {
1874 if (std::abs(xmax - xmin) < Small || std::abs(ymax - ymin) < Small) {
1875 std::cerr <<
m_className <<
"::SetScanningArea:\n"
1876 <<
" Zero range not permitted.\n";
1879 m_scanRange = ScanningRange::User;
1880 m_xScanMin = std::min(xmin, xmax);
1881 m_xScanMax = std::max(xmin, xmax);
1882 m_yScanMin = std::min(ymin, ymax);
1883 m_yScanMax = std::max(ymin, ymax);
1887 m_scanRange = ScanningRange::FirstOrder;
1889 m_scaleRange = scale;
1891 std::cerr <<
m_className <<
"::SetScanningAreaFirstOrder:\n"
1892 <<
" Scaling factor must be > 0.\n";
1899 const double d = sqrt(dx * dx + dy * dy + dz * dz);
1906 <<
" The gravity vector has zero norm ; ignored.\n";
1919 const unsigned int iw, std::vector<double>& xMap, std::vector<double>& yMap,
1920 std::vector<std::vector<double> >& fxMap,
1921 std::vector<std::vector<double> >& fyMap) {
1922 if (!m_cellset && !Prepare()) {
1923 std::cerr <<
m_className <<
"::ForcesOnWire: Cell not set up.\n";
1927 if (iw >= m_nWires) {
1928 std::cerr <<
m_className <<
"::ForcesOnWire: Wire index out of range.\n";
1932 std::cerr <<
m_className <<
"::ForcesOnWire: Cannot handle polar cells.\n";
1935 const auto& wire = m_w[iw];
1937 double bxmin = m_perx ? wire.x - 0.5 * m_sx : 2 * m_xmin - m_xmax;
1938 double bxmax = m_perx ? wire.x + 0.5 * m_sx : 2 * m_xmax - m_xmin;
1939 double bymin = m_pery ? wire.y - 0.5 * m_sy : 2 * m_ymin - m_ymax;
1940 double bymax = m_pery ? wire.y + 0.5 * m_sy : 2 * m_ymax - m_ymin;
1943 if (std::abs(bxmax - bxmin) < 0.1 * std::abs(bymax - bymin)) {
1944 bxmin = wire.x - 0.5 * std::abs(bymax - bymin);
1945 bxmax = wire.x + 0.5 * std::abs(bymax - bymin);
1946 }
else if (std::abs(bymax - bymin) < 0.1 * std::abs(bxmax - bxmin)) {
1947 bymin = wire.y - 0.5 * std::abs(bxmax - bxmin);
1948 bymax = wire.y + 0.5 * std::abs(bxmax - bxmin);
1950 const double dw = 2 * wire.r;
1952 for (
unsigned int j = 0; j < m_nWires; ++j) {
1953 if (j == iw)
continue;
1954 const double xj = m_w[j].x;
1955 const double yj = m_w[j].y;
1956 const double dj = 2 * m_w[j].r;
1957 double xnear = m_perx ? xj - m_sx * int(round((xj - wire.x) / m_sx)) : xj;
1958 double ynear = m_pery ? yj - m_sy * int(round((yj - wire.y) / m_sy)) : yj;
1959 if (std::abs(xnear - wire.x) > std::abs(ynear - wire.y)) {
1960 if (xnear < wire.x) {
1961 bxmin = std::max(bxmin, xnear + dj + dw);
1962 if (m_perx) bxmax = std::min(bxmax, xnear + m_sx - dj - dw);
1964 bxmax = std::min(bxmax, xnear - dj - dw);
1965 if (m_perx) bxmin = std::max(bxmin, xnear - m_sx + dj + dw);
1968 if (ynear < wire.y) {
1969 bymin = std::max({bymin, ynear - dj - dw, ynear + dj + dw});
1970 if (m_pery) bymax = std::min(bymax, ynear + m_sy - dj - dw);
1972 bymax = std::min({bymax, ynear - dj - dw, ynear + dj + dw});
1973 if (m_pery) bymin = std::max(bymin, ynear - m_sy + dj + dw);
1978 if (m_ynplan[0]) bxmin = std::max(bxmin, m_coplan[0] + dw);
1979 if (m_ynplan[1]) bxmax = std::min(bxmax, m_coplan[1] - dw);
1980 if (m_ynplan[2]) bymin = std::max(bymin, m_coplan[2] + dw);
1981 if (m_ynplan[3]) bymax = std::min(bymax, m_coplan[3] - dw);
1985 const double d2 = m_cotube2 - dw * dw;
1987 std::cerr <<
m_className <<
"::ForcesOnWire:\n Diameter of wire " << iw
1988 <<
" is too large compared to the tube.\n";
1992 double corr = sqrt((bxmin * bxmin + bymin * bymin) / d2);
1997 corr = sqrt((bxmin * bxmin + bymax * bymax) / d2);
2002 corr = sqrt((bxmax * bxmax + bymin * bymin) / d2);
2007 corr = sqrt((bxmax * bxmax + bymax * bymax) / d2);
2014 if ((bxmin - wire.x) * (wire.x - bxmax) <= 0 ||
2015 (bymin - wire.y) * (wire.y - bymax) <= 0) {
2016 std::cerr <<
m_className <<
"::ForcesOnWire:\n Unable to find an area "
2017 <<
"free of elements around wire " << iw <<
".\n";
2021 double sxmin = bxmin;
2022 double sxmax = bxmax;
2023 double symin = bymin;
2024 double symax = bymax;
2025 if (m_scanRange == ScanningRange::User) {
2027 sxmin = wire.x + m_xScanMin;
2028 symin = wire.y + m_yScanMin;
2029 sxmax = wire.x + m_xScanMax;
2030 symax = wire.y + m_yScanMax;
2031 }
else if (m_scanRange == ScanningRange::FirstOrder) {
2033 double ex = 0., ey = 0.;
2035 double fx = -ex * wire.e * Internal2Newton;
2036 double fy = -ey * wire.e * Internal2Newton;
2037 if (m_useGravitationalForce) {
2039 const double m = 1.e-3 * wire.density * Pi * wire.r * wire.r;
2040 fx -= m_down[0] * GravitationalAcceleration * m;
2041 fy -= m_down[1] * GravitationalAcceleration * m;
2043 const double u2 = wire.u * wire.u;
2044 const double shiftx =
2045 -125 * fx * u2 / (GravitationalAcceleration * wire.tension);
2046 const double shifty =
2047 -125 * fy * u2 / (GravitationalAcceleration * wire.tension);
2049 const double tol = 0.1 * wire.r;
2050 if (std::abs(shiftx) > tol || std::abs(shifty) > tol) {
2051 sxmin = std::max(bxmin, std::min(wire.x + m_scaleRange * shiftx,
2052 wire.x - shiftx / m_scaleRange));
2053 symin = std::max(bymin, std::min(wire.y + m_scaleRange * shifty,
2054 wire.y - shifty / m_scaleRange));
2055 sxmax = std::min(bxmax, std::max(wire.x + m_scaleRange * shiftx,
2056 wire.x - shiftx / m_scaleRange));
2057 symax = std::min(bymax, std::max(wire.y + m_scaleRange * shifty,
2058 wire.y - shifty / m_scaleRange));
2060 if (std::abs(sxmax - sxmin) < 0.1 * std::abs(symax - symin)) {
2061 sxmin = std::max(bxmin, wire.x - 0.5 * std::abs(symax - symin));
2062 sxmax = std::min(bxmax, wire.x + 0.5 * std::abs(symax - symin));
2063 }
else if (std::abs(symax - symin) < 0.1 * std::abs(sxmax - sxmin)) {
2064 symin = std::max(bymin, wire.y - 0.5 * std::abs(sxmax - sxmin));
2065 symax = std::min(bymax, wire.y + 0.5 * std::abs(sxmax - sxmin));
2071 std::printf(
" Free area %12.5e < x < %12.5e\n", bxmin, bxmax);
2072 std::printf(
" %12.5e < y < %12.5e\n", bymin, bymax);
2073 std::printf(
" Scan area %12.5e < x < %12.5e\n", sxmin, sxmax);
2074 std::printf(
" %12.5e < y < %12.5e\n", symin, symax);
2077 xMap.resize(m_nScanX);
2078 const double stepx = (sxmax - sxmin) / (m_nScanX - 1);
2079 for (
unsigned int i = 0; i < m_nScanX; ++i) {
2080 xMap[i] = sxmin + i * stepx;
2082 yMap.resize(m_nScanY);
2083 const double stepy = (symax - symin) / (m_nScanY - 1);
2084 for (
unsigned int i = 0; i < m_nScanY; ++i) {
2085 yMap[i] = symin + i * stepy;
2088 const double x0 = wire.x;
2089 const double y0 = wire.y;
2091 fxMap.assign(m_nScanX, std::vector<double>(m_nScanY, 0.));
2092 fyMap.assign(m_nScanX, std::vector<double>(m_nScanY, 0.));
2094 for (
unsigned int i = 0; i < m_nScanX; ++i) {
2095 for (
unsigned int j = 0; j < m_nScanY; ++j) {
2097 m_w[iw].x = xMap[i];
2098 m_w[iw].y = yMap[j];
2101 std::cerr <<
m_className <<
"::ForcesOnWire: Wire " << iw <<
".\n"
2102 <<
" Scan involves a disallowed wire position.\n";
2108 std::cerr <<
m_className <<
"::ForcesOnWire: Wire " << iw <<
".\n"
2109 <<
" Failed to compute charges at a scan point.\n";
2114 double ex = 0., ey = 0.;
2116 fxMap[i][j] = -ex * wire.e * Internal2Newton;
2117 fyMap[i][j] = -ey * wire.e * Internal2Newton;
2129 std::cerr <<
m_className <<
"::SetNumberOfSteps:\n"
2130 <<
" Number of steps must be > 0.\n";
2137 const unsigned int iw,
const bool detailed, std::vector<double>& csag,
2138 std::vector<double>& xsag, std::vector<double>& ysag,
double& stretch,
2140 if (!m_cellset && !Prepare()) {
2141 std::cerr <<
m_className <<
"::WireDisplacement: Cell not set up.\n";
2144 if (iw >= m_nWires) {
2146 <<
"::WireDisplacement: Wire index out of range.\n";
2151 <<
"::WireDisplacement: Cannot handle polar cells.\n";
2154 const auto& wire = m_w[iw];
2156 const double x0 = wire.x;
2157 const double y0 = wire.y;
2160 std::cerr <<
m_className <<
"::WireDisplacement:\n"
2161 <<
" Charge calculation failed at central position.\n";
2165 double fx = 0., fy = 0.;
2166 if (m_useElectrostaticForce) {
2167 double ex = 0., ey = 0.;
2169 fx -= ex * wire.e * Internal2Newton;
2170 fy -= ey * wire.e * Internal2Newton;
2172 if (m_useGravitationalForce) {
2174 const double m = 1.e-3 * wire.density * Pi * wire.r * wire.r;
2175 fx -= m_down[0] * GravitationalAcceleration * m;
2176 fy -= m_down[1] * GravitationalAcceleration * m;
2178 const double u2 = wire.u * wire.u;
2179 const double shiftx =
2180 -125 * fx * u2 / (GravitationalAcceleration * wire.tension);
2181 const double shifty =
2182 -125 * fy * u2 / (GravitationalAcceleration * wire.tension);
2184 const double s = 4 * sqrt(shiftx * shiftx + shifty * shifty) / wire.u;
2185 double length = wire.u;
2187 const double t = sqrt(1 + s * s);
2188 length *= 0.5 * (t + log(s + t) / s);
2190 stretch = (length - wire.u) / wire.u;
2193 <<
"::WireDisplacement:\n"
2194 <<
" Forces and displacement in 0th order.\n"
2195 <<
" Wire information: number = " << iw <<
"\n"
2196 <<
" type = " << wire.type <<
"\n"
2197 <<
" location = (" << wire.x <<
", " << wire.y
2199 <<
" voltage = " << wire.v <<
" V\n"
2200 <<
" length = " << wire.u <<
" cm\n"
2201 <<
" tension = " << wire.tension <<
" g\n"
2202 <<
" In this position: Fx = " << fx <<
" N/cm\n"
2203 <<
" Fy = " << fy <<
" N/cm\n"
2204 <<
" x-shift = " << shiftx <<
" cm\n"
2205 <<
" y-shift = " << shifty <<
" cm\n"
2206 <<
" stretch = " << 100. * stretch <<
"%\n";
2214 std::vector<double> xMap(m_nScanX, 0.);
2215 std::vector<double> yMap(m_nScanY, 0.);
2216 std::vector<std::vector<double> > fxMap(m_nScanX,
2217 std::vector<double>(m_nScanY, 0.));
2218 std::vector<std::vector<double> > fyMap(m_nScanX,
2219 std::vector<double>(m_nScanY, 0.));
2221 std::cerr <<
m_className <<
"::WireDisplacement:\n"
2222 <<
" Could not compute the electrostatic force table.\n";
2226 if (!SagDetailed(wire, xMap, yMap, fxMap, fyMap, csag, xsag, ysag)) {
2227 std::cerr <<
m_className <<
"::WireDisplacement: Wire " << iw <<
".\n"
2228 <<
" Computation of the wire sag failed.\n";
2232 const double sxmin = xMap.front();
2233 const double sxmax = xMap.back();
2234 const double symin = yMap.front();
2235 const double symax = yMap.back();
2236 const unsigned int nSag = xsag.size();
2237 bool outside =
false;
2243 for (
unsigned int i = 0; i < nSag; ++i) {
2244 if (x0 + xsag[i] < sxmin || x0 + xsag[i] > sxmax || y0 + ysag[i] < symin ||
2245 y0 + ysag[i] > symax) {
2250 xMax = std::max(xMax, std::abs(xsag[i]));
2251 yMax = std::max(yMax, std::abs(ysag[i]));
2252 if (i == 0)
continue;
2253 const double dx = xsag[i] - xsag[i - 1];
2254 const double dy = ysag[i] - ysag[i - 1];
2255 const double dz = csag[i] - csag[i - 1];
2256 length += sqrt(dx * dx + dy * dy + dz * dz);
2260 stretch = (length - wire.u) / wire.u;
2264 <<
m_className <<
"::WireDisplacement: Warning.\n "
2265 <<
"The wire profile is located partially outside the scanning area.\n";
2268 std::cout <<
" Sag profile for wire " << iw <<
".\n"
2269 <<
" Point z [cm] x-sag [um] y-sag [um]\n";
2270 for (
unsigned int i = 0; i < nSag; ++i) {
2271 std::printf(
" %3d %10.4f %10.4f %10.4f\n",
2272 i, csag[i], xsag[i] * 1.e4, ysag[i] * 1.e4);
2274 std::printf(
" Average sag in x and y: %10.4f and %10.4f micron\n",
2275 1.e4 * xAvg, 1.e4 * yAvg);
2276 std::printf(
" Maximum sag in x and y: %10.4f and %10.4f micron\n",
2277 1.e4 * xMax, 1.e4 * yMax);
2278 std::cout <<
" Elongation: " << 100. * stretch <<
"%\n";
2283int ComponentAnalyticField::Field(
const double xin,
const double yin,
2284 const double zin,
double& ex,
double& ey,
2285 double& ez,
double& volt,
const bool opt) {
2305 ex = ey = ez = volt = 0.;
2308 if (!m_cellset && !Prepare())
return -11;
2310 double xpos = xin, ypos = yin;
2311 if (m_polar) Cartesian2Internal(xin, yin, xpos, ypos);
2314 xpos -= m_sx * int(round(xin / m_sx));
2317 if (m_pery && m_tube) {
2318 Cartesian2Polar(xin, yin, xpos, ypos);
2319 arot = RadToDegree * m_sy * int(round(DegreeToRad * ypos / m_sy));
2321 Polar2Cartesian(xpos, ypos, xpos, ypos);
2322 }
else if (m_pery) {
2323 ypos -= m_sy * int(round(ypos / m_sy));
2327 if (m_perx && m_ynplan[0] && xpos <= m_coplan[0]) xpos += m_sx;
2328 if (m_perx && m_ynplan[1] && xpos >= m_coplan[1]) xpos -= m_sx;
2329 if (m_pery && m_ynplan[2] && ypos <= m_coplan[2]) ypos += m_sy;
2330 if (m_pery && m_ynplan[3] && ypos >= m_coplan[3]) ypos -= m_sy;
2334 if (!InTube(xpos, ypos, m_cotube, m_ntube)) {
2339 if (m_ynplan[0] && xpos < m_coplan[0]) {
2343 if (m_ynplan[1] && xpos > m_coplan[1]) {
2347 if (m_ynplan[2] && ypos < m_coplan[2]) {
2351 if (m_ynplan[3] && ypos > m_coplan[3]) {
2358 for (
int i = m_nWires; i--;) {
2359 double dx = xpos - m_w[i].x;
2360 double dy = ypos - m_w[i].y;
2362 if (m_perx) dx -= m_sx * int(round(dx / m_sx));
2363 if (m_pery) dy -= m_sy * int(round(dy / m_sy));
2365 if (dx * dx + dy * dy < m_w[i].r * m_w[i].r) {
2372 switch (m_cellType) {
2374 FieldA00(xpos, ypos, ex, ey, volt, opt);
2377 FieldB1X(xpos, ypos, ex, ey, volt, opt);
2380 FieldB1Y(xpos, ypos, ex, ey, volt, opt);
2383 FieldB2X(xpos, ypos, ex, ey, volt, opt);
2386 FieldB2Y(xpos, ypos, ex, ey, volt, opt);
2389 FieldC10(xpos, ypos, ex, ey, volt, opt);
2392 FieldC2X(xpos, ypos, ex, ey, volt, opt);
2395 FieldC2Y(xpos, ypos, ex, ey, volt, opt);
2398 FieldC30(xpos, ypos, ex, ey, volt, opt);
2401 FieldD10(xpos, ypos, ex, ey, volt, opt);
2404 FieldD20(xpos, ypos, ex, ey, volt, opt);
2407 FieldD30(xpos, ypos, ex, ey, volt, opt);
2412 std::cerr <<
" Unknown cell type (id " << m_cellType <<
")\n";
2418 double exd = 0., eyd = 0., voltd = 0.;
2419 switch (m_cellType) {
2421 DipoleFieldA00(xpos, ypos, exd, eyd, voltd, opt);
2424 DipoleFieldB1X(xpos, ypos, exd, eyd, voltd, opt);
2427 DipoleFieldB1Y(xpos, ypos, exd, eyd, voltd, opt);
2430 DipoleFieldB2X(xpos, ypos, exd, eyd, voltd, opt);
2433 DipoleFieldB2Y(xpos, ypos, exd, eyd, voltd, opt);
2444 if (m_pery && m_tube) {
2446 Cartesian2Polar(ex, ey, xaux, yaux);
2448 Polar2Cartesian(xaux, yaux, ex, ey);
2454 volt += m_corvta * xpos + m_corvtb * ypos + m_corvtc;
2457 if (!m_ch3d.empty()) {
2458 double ex3d = 0., ey3d = 0., ez3d = 0., volt3d = 0.;
2459 switch (m_cellType) {
2463 Field3dA00(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2466 Field3dB2X(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2469 Field3dB2Y(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2472 Field3dD10(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2475 Field3dA00(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2485 const double r =
exp(xpos);
2486 const double er = ex / r;
2487 const double ep = ey / r;
2488 const double theta = atan2(yin, xin);
2489 const double ct =
cos(theta);
2490 const double st =
sin(theta);
2491 ex = +ct * er -
st * ep;
2492 ey = +
st * er + ct * ep;
2497void ComponentAnalyticField::CellInit() {
2509 m_xmin = m_xmax = 0.;
2510 m_ymin = m_ymax = 0.;
2511 m_zmin = m_zmax = 0.;
2512 m_vmin = m_vmax = 0.;
2515 m_perx = m_pery =
false;
2521 m_cellTypeFourier =
A00;
2546 m_zmult = std::complex<double>(0., 0.);
2547 m_p1 = m_p2 = m_c1 = 0.;
2554 m_corvta = m_corvtb = m_corvtc = 0.;
2557 for (
int i = 0; i < 5; ++i) {
2558 m_planes[i].type =
'?';
2559 m_planes[i].ind = -1;
2560 m_planes[i].ewxcor = 0.;
2561 m_planes[i].ewycor = 0.;
2562 m_planes[i].strips1.clear();
2563 m_planes[i].strips2.clear();
2564 m_planes[i].pixels.clear();
2566 for (
int i = 0; i < 4; ++i) {
2567 m_ynplan[i] =
false;
2572 m_ynplax = m_ynplay =
false;
2573 m_coplax = m_coplay = 1.;
2595bool ComponentAnalyticField::Prepare() {
2596 std::lock_guard<std::mutex> guard(m_mutex);
2600 <<
" The cell does not meet the requirements.\n";
2608 <<
" Type identification of the cell failed.\n";
2613 <<
" Cell is of type " << CellType() <<
".\n";
2618 std::cerr <<
m_className <<
"::Prepare: Calculation of charges failed.\n";
2623 <<
" Calculation of charges was successful.\n";
2627 if (!PrepareStrips()) {
2628 std::cerr <<
m_className <<
"::Prepare: Strip/pixel preparation failed.\n";
2636 if (!SetupDipoleTerms()) {
2638 <<
" Computing the dipole moments failed.\n";
2645bool ComponentAnalyticField::CellCheck() {
2659 const std::string xr = m_polar ?
"r" :
"x";
2660 double conew1 = m_coplan[0] - m_sx * int(round(m_coplan[0] / m_sx));
2661 double conew2 = m_coplan[1] - m_sx * int(round(m_coplan[1] / m_sx));
2663 if (m_ynplan[0] && m_ynplan[1] && conew1 == conew2) {
2670 if ((conew1 != m_coplan[0] && m_ynplan[0]) ||
2671 (conew2 != m_coplan[1] && m_ynplan[1])) {
2672 std::cout <<
m_className <<
"::CellCheck:\n The planes in "
2673 << xr <<
" are moved to the basic period.\n"
2674 <<
" This should not affect the results.\n";
2676 m_coplan[0] = conew1;
2677 m_coplan[1] = conew2;
2680 if (m_ynplan[0] && m_ynplan[1] &&
fabs(m_coplan[1] - m_coplan[0]) != m_sx) {
2681 std::cerr <<
m_className <<
"::CellCheck:\n The separation of the "
2682 << xr <<
" planes does not match the period.\n"
2683 <<
" The periodicity is cancelled.\n";
2687 if (m_ynplan[0] && m_ynplan[1] && m_vtplan[0] != m_vtplan[1]) {
2688 std::cerr <<
m_className <<
"::CellCheck:\n The voltages of the two "
2689 << xr <<
" planes differ.\n"
2690 <<
" The periodicity is cancelled.\n";
2697 const std::string yp = m_polar ?
"phi" :
"y";
2698 double conew3 = m_coplan[2] - m_sy * int(round(m_coplan[2] / m_sy));
2699 double conew4 = m_coplan[3] - m_sy * int(round(m_coplan[3] / m_sy));
2701 if (m_ynplan[2] && m_ynplan[3] && conew3 == conew4) {
2708 if ((conew3 != m_coplan[2] && m_ynplan[2]) ||
2709 (conew4 != m_coplan[3] && m_ynplan[3])) {
2710 std::cout <<
m_className <<
"::CellCheck:\n The planes in "
2711 << yp <<
" are moved to the basic period.\n"
2712 <<
" This should not affect the results.\n";
2714 m_coplan[2] = conew3;
2715 m_coplan[3] = conew4;
2718 if (m_ynplan[2] && m_ynplan[3] &&
fabs(m_coplan[3] - m_coplan[2]) != m_sy) {
2719 std::cerr <<
m_className <<
"::CellCheck:\n The separation of the two "
2720 << yp <<
" planes does not match the period.\n"
2721 <<
" The periodicity is cancelled.\n";
2725 if (m_ynplan[2] && m_ynplan[3] && m_vtplan[2] != m_vtplan[3]) {
2726 std::cerr <<
m_className <<
"::CellCheck:\n The voltages of the two "
2727 << yp <<
" planes differ.\n"
2728 <<
" The periodicity is cancelled.\n";
2734 for (
int i = 0; i < 2; ++i) {
2735 for (
int j = 2; j < 3; ++j) {
2736 if (m_ynplan[i] && m_ynplan[j] && m_vtplan[i] != m_vtplan[j]) {
2737 const std::string yp = m_polar ?
"phi" :
"y";
2739 <<
" Conflicting potential of two crossing planes.\n"
2740 <<
" One " << yp <<
" plane is removed.\n";
2741 m_ynplan[j] =
false;
2747 for (
int i = 0; i < 3; i += 2) {
2748 if (m_ynplan[i] && m_ynplan[i + 1]) {
2749 if (m_coplan[i] == m_coplan[i + 1]) {
2751 <<
" Two planes are on top of each other.\n"
2752 <<
" One of them is removed.\n";
2753 m_ynplan[i + 1] =
false;
2755 if (m_coplan[i] > m_coplan[i + 1]) {
2757 std::cout <<
m_className <<
"::CellCheck:\n Planes "
2758 << i <<
" and " << i + 1 <<
" are interchanged.\n";
2761 const double cohlp = m_coplan[i];
2762 m_coplan[i] = m_coplan[i + 1];
2763 m_coplan[i + 1] = cohlp;
2765 const double vthlp = m_vtplan[i];
2766 m_vtplan[i] = m_vtplan[i + 1];
2767 m_vtplan[i + 1] = vthlp;
2769 Plane plahlp = m_planes[i];
2770 m_planes[i] = m_planes[i + 1];
2771 m_planes[i + 1] = plahlp;
2778 for (
auto& wire : m_w) {
2779 double xnew = wire.x - m_sx * int(round(wire.x / m_sx));
2780 if (m_ynplan[0] && xnew <= m_coplan[0]) xnew += m_sx;
2781 if (m_ynplan[1] && xnew >= m_coplan[1]) xnew -= m_sx;
2782 if (
fabs(xnew - wire.x) > 1.e-8) {
2783 double xprt = wire.x;
2784 double yprt = wire.y;
2785 if (m_polar) Internal2Polar(wire.x, wire.y, xprt, yprt);
2786 const std::string xr = m_polar ?
"r" :
"x";
2787 std::cout <<
m_className <<
"::CellCheck:\n The " << wire.type
2788 <<
"-wire at (" << xprt <<
", " << yprt
2789 <<
") is moved to the basic " << xr <<
" period.\n"
2790 <<
" This should not affect the results.\n";
2797 if (m_tube && m_pery) {
2798 for (
unsigned int i = 0; i < m_nWires; ++i) {
2799 double xnew = m_w[i].x;
2800 double ynew = m_w[i].y;
2801 Cartesian2Polar(xnew, ynew, xnew, ynew);
2802 if (
int(round(DegreeToRad * ynew / m_sy)) != 0) {
2804 std::cout <<
" The " << m_w[i].type <<
"-wire at (" << m_w[i].x
2806 <<
") is moved to the basic phi period.\n";
2807 std::cout <<
" This should not affect the results.\n";
2808 ynew -= RadToDegree * m_sy * int(round(DegreeToRad * ynew / m_sy));
2809 Polar2Cartesian(xnew, ynew, m_w[i].x, m_w[i].y);
2812 }
else if (m_pery) {
2813 for (
auto& wire : m_w) {
2814 double ynew = wire.y - m_sy * int(round(wire.y / m_sy));
2815 if (m_ynplan[2] && ynew <= m_coplan[2]) ynew += m_sy;
2816 if (m_ynplan[3] && ynew >= m_coplan[3]) ynew -= m_sy;
2817 if (
fabs(ynew - wire.y) > 1.e-8) {
2818 double xprt = wire.x;
2819 double yprt = wire.y;
2820 if (m_polar) Internal2Polar(wire.x, wire.y, xprt, yprt);
2821 const std::string yp = m_polar ?
"phi" :
"y";
2822 std::cout <<
m_className <<
"::CellCheck:\n The " << wire.type
2823 <<
"-wire at (" << xprt <<
", " << yprt
2824 <<
") is moved to the basic " << yp <<
" period.\n"
2825 <<
" This should not affect the results.\n";
2832 int iplan1 = 0, iplan2 = 0, iplan3 = 0, iplan4 = 0;
2833 for (
const auto& wire : m_w) {
2834 if (m_ynplan[0] && wire.x <= m_coplan[0]) ++iplan1;
2835 if (m_ynplan[1] && wire.x <= m_coplan[1]) ++iplan2;
2836 if (m_ynplan[2] && wire.y <= m_coplan[2]) ++iplan3;
2837 if (m_ynplan[3] && wire.y <= m_coplan[3]) ++iplan4;
2841 const int imid = int(m_nWires) / 2;
2842 if (m_ynplan[0] && m_ynplan[1]) {
2843 if (iplan1 > imid) {
2844 m_ynplan[1] =
false;
2849 if (iplan2 < imid) {
2850 m_ynplan[0] =
false;
2856 if (m_ynplan[0] && !m_ynplan[1]) {
2857 if (iplan1 > imid) {
2863 if (m_ynplan[1] && !m_ynplan[0]) {
2864 if (iplan2 < imid) {
2871 if (m_ynplan[2] && m_ynplan[3]) {
2872 if (iplan3 > imid) {
2873 m_ynplan[3] =
false;
2878 if (iplan4 < imid) {
2879 m_ynplan[2] =
false;
2885 if (m_ynplan[2] && !m_ynplan[3]) {
2886 if (iplan3 > imid) {
2892 if (m_ynplan[3] && !m_ynplan[2]) {
2893 if (iplan4 < imid) {
2902 m_ynplan[0] =
false;
2904 m_coplan[1] = m_coplan[0];
2905 m_vtplan[1] = m_vtplan[0];
2906 m_planes[1] = m_planes[0];
2910 m_ynplan[1] =
false;
2912 m_coplan[0] = m_coplan[1];
2913 m_vtplan[0] = m_vtplan[1];
2914 m_planes[0] = m_planes[1];
2918 m_ynplan[2] =
false;
2920 m_coplan[3] = m_coplan[2];
2921 m_vtplan[3] = m_vtplan[2];
2922 m_planes[3] = m_planes[2];
2926 m_ynplan[3] =
false;
2928 m_coplan[2] = m_coplan[3];
2929 m_vtplan[2] = m_vtplan[3];
2930 m_planes[2] = m_planes[3];
2933 std::vector<bool> wrong(m_nWires,
false);
2935 for (
unsigned int i = 0; i < m_nWires; ++i) {
2936 const double rw = m_w[i].r;
2937 const double dw = 2. * rw;
2938 if (m_ynplan[0] && m_w[i].x - rw <= m_coplan[0]) wrong[i] =
true;
2939 if (m_ynplan[1] && m_w[i].x + rw >= m_coplan[1]) wrong[i] =
true;
2940 if (m_ynplan[2] && m_w[i].y - rw <= m_coplan[2]) wrong[i] =
true;
2941 if (m_ynplan[3] && m_w[i].y + rw >= m_coplan[3]) wrong[i] =
true;
2943 if (!InTube(m_w[i].x, m_w[i].y, m_cotube, m_ntube)) {
2945 std::cerr <<
" The " << m_w[i].type <<
"-wire at (" << m_w[i].x
2946 <<
", " << m_w[i].y <<
") is located outside the tube.\n";
2947 std::cerr <<
" This wire is removed.\n";
2950 }
else if (wrong[i]) {
2951 double xprt = m_w[i].x;
2952 double yprt = m_w[i].y;
2953 if (m_polar) Internal2Polar(m_w[i].x, m_w[i].y, xprt, yprt);
2954 std::cerr <<
m_className <<
"::CellCheck:\n The " << m_w[i].type
2955 <<
"-wire at (" << xprt <<
", " << yprt <<
") is located "
2956 <<
"outside the planes.\n This wire is removed.\n";
2957 }
else if ((m_perx && dw >= m_sx) || (m_pery && dw >= m_sy)) {
2958 double xprt = m_w[i].x;
2959 double yprt = m_w[i].y;
2960 if (m_polar) Internal2Polar(m_w[i].x, m_w[i].y, xprt, yprt);
2961 std::cerr <<
m_className <<
"::CellCheck:\n The diameter of the "
2962 << m_w[i].type <<
"-wire at (" << xprt <<
", " << yprt
2963 <<
") exceeds 1 period.\n This wire is removed.\n";
2969 for (
unsigned int i = 0; i < m_nWires; ++i) {
2970 if (wrong[i])
continue;
2971 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
2972 if (wrong[j])
continue;
2977 double xaux1, xaux2, yaux1, yaux2;
2978 Cartesian2Polar(m_w[i].x, m_w[i].y, xaux1, yaux1);
2979 Cartesian2Polar(m_w[j].x, m_w[j].y, xaux2, yaux2);
2980 yaux1 -= m_sy * int(round(yaux1 / m_sy));
2981 yaux2 -= m_sy * int(round(yaux2 / m_sy));
2982 Polar2Cartesian(xaux1, yaux1, xaux1, yaux1);
2983 Polar2Cartesian(xaux2, yaux2, xaux2, yaux2);
2984 xsepar = xaux1 - xaux2;
2985 ysepar = yaux1 - yaux2;
2987 xsepar = m_w[i].x - m_w[j].x;
2988 ysepar = m_w[i].y - m_w[j].y;
2991 xsepar =
fabs(m_w[i].x - m_w[j].x);
2992 if (m_perx) xsepar -= m_sx * int(round(xsepar / m_sx));
2993 ysepar =
fabs(m_w[i].y - m_w[j].y);
2994 if (m_pery) ysepar -= m_sy * int(round(ysepar / m_sy));
2996 const double rij = m_w[i].r + m_w[j].r;
2997 if (xsepar * xsepar + ysepar * ysepar > rij * rij)
continue;
2998 double xprti = m_w[i].x;
2999 double yprti = m_w[i].y;
3000 double xprtj = m_w[j].x;
3001 double yprtj = m_w[j].y;
3003 Internal2Polar(m_w[i].x, m_w[i].y, xprti, yprti);
3004 Internal2Polar(m_w[j].x, m_w[j].y, xprtj, yprtj);
3006 std::cerr <<
m_className <<
"::CellCheck:\n Wires " << m_w[i].type
3007 <<
" at (" << xprti <<
", " << yprti <<
") and " << m_w[j].type
3008 <<
" at (" << xprtj <<
", " << yprtj
3009 <<
") overlap at least partially.\n"
3010 <<
" The latter wire is removed.\n";
3016 const int iWires = m_nWires;
3018 for (
int i = 0; i < iWires; ++i) {
3020 m_w[m_nWires] = m_w[i];
3026 int nElements = m_nWires;
3027 if (m_ynplan[0]) ++nElements;
3028 if (m_ynplan[1]) ++nElements;
3029 if (m_ynplan[2]) ++nElements;
3030 if (m_ynplan[3]) ++nElements;
3031 if (m_tube) ++nElements;
3033 if (nElements < 2) {
3035 std::cerr <<
" At least 2 elements are necessary.\n";
3036 std::cerr <<
" Cell rejected.\n";
3046 m_xmin = m_xmax = 0.;
3047 m_ymin = m_ymax = 0.;
3048 m_zmin = m_zmax = 0.;
3049 m_vmin = m_vmax = 0.;
3052 for (
const auto& wire : m_w) {
3053 const double rw = wire.r;
3055 m_xmin = std::min(m_xmin, wire.x - rw);
3056 m_xmax = std::max(m_xmax, wire.x + rw);
3058 m_xmin = wire.x - rw;
3059 m_xmax = wire.x + rw;
3063 m_ymin = std::min(m_ymin, wire.y - rw);
3064 m_ymax = std::max(m_ymax, wire.y + rw);
3066 m_ymin = wire.y - rw;
3067 m_ymax = wire.y + rw;
3071 m_zmin = std::min(m_zmin, -0.5 * wire.u);
3072 m_zmax = std::max(m_zmax, +0.5 * wire.u);
3074 m_zmin = -0.5 * wire.u;
3075 m_zmax = +0.5 * wire.u;
3079 m_vmin = std::min(m_vmin, wire.v);
3080 m_vmax = std::max(m_vmax, wire.v);
3082 m_vmin = m_vmax = wire.v;
3087 for (
int i = 0; i < 4; ++i) {
3088 if (!m_ynplan[i])
continue;
3091 m_xmin = std::min(m_xmin, m_coplan[i]);
3092 m_xmax = std::max(m_xmax, m_coplan[i]);
3094 m_xmin = m_xmax = m_coplan[i];
3099 m_ymin = std::min(m_ymin, m_coplan[i]);
3100 m_ymax = std::max(m_ymax, m_coplan[i]);
3102 m_ymin = m_ymax = m_coplan[i];
3107 m_vmin = std::min(m_vmin, m_vtplan[i]);
3108 m_vmax = std::max(m_vmax, m_vtplan[i]);
3110 m_vmin = m_vmax = m_vtplan[i];
3117 m_xmin = -1.1 * m_cotube;
3118 m_xmax = +1.1 * m_cotube;
3120 m_ymin = -1.1 * m_cotube;
3121 m_ymax = +1.1 * m_cotube;
3123 m_vmin = std::min(m_vmin, m_vttube);
3124 m_vmax = std::max(m_vmax, m_vttube);
3129 if (m_perx && m_sx > (m_xmax - m_xmin)) {
3130 m_xmin = -0.5 * m_sx;
3131 m_xmax = +0.5 * m_sx;
3135 if (m_pery && m_sy > (m_ymax - m_ymin)) {
3136 m_ymin = -0.5 * m_sy;
3137 m_ymax = +0.5 * m_sy;
3141 if (m_polar && (m_ymax - m_ymin) >= TwoPi) {
3148 if (setx && m_xmin != m_xmax && (m_ymin == m_ymax || !sety)) {
3149 m_ymin -= 0.5 *
fabs(m_xmax - m_xmin);
3150 m_ymax += 0.5 *
fabs(m_xmax - m_xmin);
3153 if (sety && m_ymin != m_ymax && (m_xmin == m_xmax || !setx)) {
3154 m_xmin -= 0.5 *
fabs(m_ymax - m_ymin);
3155 m_xmax += 0.5 *
fabs(m_ymax - m_ymin);
3160 m_zmin = -0.25 * (
fabs(m_xmax - m_xmin) +
fabs(m_ymax - m_ymin));
3161 m_zmax = +0.25 * (
fabs(m_xmax - m_xmin) +
fabs(m_ymax - m_ymin));
3166 if (!(setx && sety && setz)) {
3168 std::cerr <<
" Unable to establish"
3169 <<
" default dimensions in all directions.\n";
3173 if (m_vmin == m_vmax || !setv) {
3175 std::cerr <<
" All potentials in the cell are the same.\n";
3176 std::cerr <<
" There is no point in going on.\n";
3184bool ComponentAnalyticField::WireCheck()
const {
3190 if (m_nWires == 0)
return false;
3192 if (m_nWires == 1 &&
3193 !(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3]) && !m_tube) {
3197 for (
unsigned int i = 0; i < m_nWires; ++i) {
3198 const auto& wire = m_w[i];
3199 if (m_ynplan[0] && wire.x - wire.r <= m_coplan[0])
return false;
3200 if (m_ynplan[1] && wire.x + wire.r >= m_coplan[1])
return false;
3201 if (m_ynplan[2] && wire.y - wire.r <= m_coplan[2])
return false;
3202 if (m_ynplan[3] && wire.y + wire.r >= m_coplan[3])
return false;
3204 if (!InTube(wire.x, wire.y, m_cotube, m_ntube))
return false;
3205 }
else if ((m_perx && 2 * wire.r >= m_sx) ||
3206 (m_pery && 2 * wire.r >= m_sy)) {
3211 for (
unsigned int i = 0; i < m_nWires; ++i) {
3212 const double xi = m_w[i].x;
3213 const double yi = m_w[i].y;
3214 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3215 const double xj = m_w[j].x;
3216 const double yj = m_w[j].y;
3217 double xsepar = std::abs(xi - xj);
3218 double ysepar = std::abs(yi - yj);
3221 double xaux1 = 0., yaux1 = 0.;
3222 double xaux2 = 0., yaux2 = 0.;
3223 Cartesian2Polar(xi, yi, xaux1, yaux1);
3224 Cartesian2Polar(xj, yj, xaux2, yaux2);
3225 yaux1 -= m_sy * int(round(yaux1 / m_sy));
3226 yaux2 -= m_sy * int(round(yaux2 / m_sy));
3227 Polar2Cartesian(xaux1, yaux1, xaux1, yaux1);
3228 Polar2Cartesian(xaux2, yaux2, xaux2, yaux2);
3229 xsepar = xaux1 - xaux2;
3230 ysepar = yaux1 - yaux2;
3233 if (m_perx) xsepar -= m_sx * int(round(xsepar / m_sx));
3234 if (m_pery) ysepar -= m_sy * int(round(ysepar / m_sy));
3236 const double rij = m_w[i].r + m_w[j].r;
3237 if (xsepar * xsepar + ysepar * ysepar < rij * rij)
return false;
3243bool ComponentAnalyticField::CellType() {
3252 }
else if (m_ntube >= 3 && m_ntube <= 8) {
3260 <<
" Potentials for tube with " << m_ntube
3261 <<
" edges are not yet available.\n"
3262 <<
" Using a round tube instead.\n";
3270 if (!(m_perx || m_pery) && !(m_ynplan[0] && m_ynplan[1]) &&
3271 !(m_ynplan[2] && m_ynplan[3])) {
3277 if (m_perx && !m_pery && !(m_ynplan[0] || m_ynplan[1]) &&
3278 !(m_ynplan[2] && m_ynplan[3])) {
3284 if (m_pery && !m_perx && !(m_ynplan[0] && m_ynplan[1]) &&
3285 !(m_ynplan[2] || m_ynplan[3])) {
3291 if (m_perx && !m_pery && !(m_ynplan[2] && m_ynplan[3])) {
3296 if (!(m_perx || m_pery) && !(m_ynplan[2] && m_ynplan[3]) &&
3297 (m_ynplan[0] && m_ynplan[1])) {
3298 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3304 if (m_pery && !m_perx && !(m_ynplan[0] && m_ynplan[1])) {
3309 if (!(m_perx || m_pery) && !(m_ynplan[0] && m_ynplan[1]) &&
3310 (m_ynplan[2] && m_ynplan[3])) {
3311 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3317 if (!(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3]) && m_perx &&
3324 if (!((m_ynplan[2] && m_pery) || (m_ynplan[2] && m_ynplan[3]))) {
3325 if (m_ynplan[0] && m_ynplan[1]) {
3326 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3330 if (m_perx && m_ynplan[0]) {
3337 if (!((m_ynplan[0] && m_perx) || (m_ynplan[0] && m_ynplan[1]))) {
3338 if (m_ynplan[2] && m_ynplan[3]) {
3339 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3343 if (m_pery && m_ynplan[2]) {
3350 if (m_perx && m_pery) {
3356 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3362 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3367 if (m_ynplan[0] && m_ynplan[1] && m_ynplan[2] && m_ynplan[3]) {
3368 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3369 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3379 switch (m_cellType) {
3412bool ComponentAnalyticField::PrepareStrips() {
3418 double gapDef[4] = {0., 0., 0., 0.};
3423 gapDef[0] = m_coplan[1] - m_coplan[0];
3424 }
else if (m_nWires <= 0) {
3427 gapDef[0] = m_w[0].x - m_coplan[0];
3428 for (
const auto& wire : m_w) {
3429 gapDef[0] = std::min(wire.x - m_coplan[0], gapDef[0]);
3436 gapDef[1] = m_coplan[1] - m_coplan[0];
3437 }
else if (m_nWires <= 0) {
3440 gapDef[1] = m_coplan[1] - m_w[0].x;
3441 for (
const auto& wire : m_w) {
3442 gapDef[1] = std::min(m_coplan[1] - wire.x, gapDef[1]);
3449 gapDef[2] = m_coplan[3] - m_coplan[2];
3450 }
else if (m_nWires <= 0) {
3453 gapDef[2] = m_w[0].y - m_coplan[2];
3454 for (
const auto& wire : m_w) {
3455 gapDef[2] = std::min(wire.y - m_coplan[2], gapDef[2]);
3462 gapDef[3] = m_coplan[3] - m_coplan[2];
3463 }
else if (m_nWires <= 0) {
3466 gapDef[3] = m_coplan[3] - m_w[0].y;
3467 for (
const auto& wire : m_w) {
3468 gapDef[3] = std::min(m_coplan[3] - wire.y, gapDef[3]);
3474 for (
unsigned int i = 0; i < 4; ++i) {
3475 for (
auto& strip : m_planes[i].strips1) {
3476 if (strip.gap < 0. && gapDef[i] < 0.) {
3478 <<
" Not able to set a default anode-cathode gap\n";
3480 std::cerr <<
" for r/phi-strips of plane " << i <<
".\n";
3482 std::cerr <<
" for x/y-strips of plane " << i <<
".\n";
3486 if (strip.gap < 0.) {
3487 strip.gap = gapDef[i];
3488 }
else if (m_polar && i < 2) {
3490 strip.gap = log1p(strip.gap /
exp(m_coplan[i]));
3492 strip.gap = -log1p(-strip.gap /
exp(m_coplan[i]));
3496 for (
auto& strip : m_planes[i].strips2) {
3497 if (strip.gap < 0. && gapDef[i] < 0.) {
3499 <<
" Not able to set a default anode-cathode gap\n"
3500 <<
" for z-strips of plane " << i <<
".\n";
3503 if (strip.gap < 0.) {
3504 strip.gap = gapDef[i];
3505 }
else if (m_polar && i < 2) {
3507 strip.gap = log1p(strip.gap /
exp(m_coplan[i]));
3509 strip.gap = -log1p(-strip.gap /
exp(m_coplan[i]));
3513 for (
auto& pixel : m_planes[i].pixels) {
3514 if (pixel.gap < 0. && gapDef[i] < 0.) {
3516 <<
" Not able to set a default anode-cathode gap\n"
3517 <<
" for pixels on plane " << i <<
".\n";
3520 if (pixel.gap < 0.) {
3521 pixel.gap = gapDef[i];
3522 }
else if (m_polar && i < 2) {
3524 pixel.gap = log1p(pixel.gap /
exp(m_coplan[i]));
3526 pixel.gap = -log1p(-pixel.gap /
exp(m_coplan[i]));
3537 if (std::find(m_readout.begin(), m_readout.end(), label) != m_readout.end()) {
3539 std::cout <<
" Readout group " << label <<
" already exists.\n";
3542 m_readout.push_back(label);
3544 unsigned int nWiresFound = 0;
3545 for (
const auto& wire : m_w) {
3546 if (wire.type == label) ++nWiresFound;
3549 unsigned int nPlanesFound = 0;
3550 unsigned int nStripsFound = 0;
3551 unsigned int nPixelsFound = 0;
3552 for (
int i = 0; i < 5; ++i) {
3553 if (m_planes[i].type == label) ++nPlanesFound;
3554 for (
const auto& strip : m_planes[i].strips1) {
3555 if (strip.type == label) ++nStripsFound;
3557 for (
const auto& strip : m_planes[i].strips2) {
3558 if (strip.type == label) ++nStripsFound;
3560 for (
const auto& pixel : m_planes[i].pixels) {
3561 if (pixel.type == label) ++nPixelsFound;
3565 if (nWiresFound == 0 && nPlanesFound == 0 && nStripsFound == 0 &&
3566 nPixelsFound == 0) {
3568 std::cerr <<
" At present there are no wires, planes or strips\n";
3569 std::cerr <<
" associated to readout group " << label <<
".\n";
3572 std::cout <<
" Readout group " << label <<
" comprises:\n";
3573 if (nWiresFound > 1) {
3574 std::cout <<
" " << nWiresFound <<
" wires\n";
3575 }
else if (nWiresFound == 1) {
3576 std::cout <<
" 1 wire\n";
3578 if (nPlanesFound > 1) {
3579 std::cout <<
" " << nPlanesFound <<
" planes\n";
3580 }
else if (nPlanesFound == 1) {
3581 std::cout <<
" 1 plane\n";
3583 if (nStripsFound > 1) {
3584 std::cout <<
" " << nStripsFound <<
" strips\n";
3585 }
else if (nStripsFound == 1) {
3586 std::cout <<
" 1 strip\n";
3588 if (nPixelsFound > 1) {
3589 std::cout <<
" " << nPixelsFound <<
" pixels\n";
3590 }
else if (nPixelsFound == 1) {
3591 std::cout <<
" 1 pixel\n";
3598bool ComponentAnalyticField::Setup() {
3606 m_coplax = m_coplan[0];
3608 }
else if (m_ynplan[1]) {
3609 m_coplax = m_coplan[1];
3616 m_coplay = m_coplan[2];
3618 }
else if (m_ynplan[3]) {
3619 m_coplay = m_coplan[3];
3629 m_corvtc = m_vttube;
3630 }
else if ((m_ynplan[0] && m_ynplan[1]) && !(m_ynplan[2] || m_ynplan[3])) {
3631 m_corvta = (m_vtplan[0] - m_vtplan[1]) / (m_coplan[0] - m_coplan[1]);
3633 m_corvtc = (m_vtplan[1] * m_coplan[0] - m_vtplan[0] * m_coplan[1]) /
3634 (m_coplan[0] - m_coplan[1]);
3635 }
else if ((m_ynplan[2] && m_ynplan[3]) && !(m_ynplan[0] || m_ynplan[1])) {
3637 m_corvtb = (m_vtplan[2] - m_vtplan[3]) / (m_coplan[2] - m_coplan[3]);
3638 m_corvtc = (m_vtplan[3] * m_coplan[2] - m_vtplan[2] * m_coplan[3]) /
3639 (m_coplan[2] - m_coplan[3]);
3641 m_corvta = m_corvtb = m_corvtc = 0.;
3642 if (m_ynplan[0]) m_corvtc = m_vtplan[0];
3643 if (m_ynplan[1]) m_corvtc = m_vtplan[1];
3644 if (m_ynplan[2]) m_corvtc = m_vtplan[2];
3645 if (m_ynplan[3]) m_corvtc = m_vtplan[3];
3649 if (m_nWires <= 0)
return true;
3652 m_a.assign(m_nWires, std::vector<double>(m_nWires, 0.));
3657 switch (m_cellType) {
3695 std::cerr <<
m_className <<
"::Setup: Unknown cell type.\n";
3704 std::cerr <<
" Preparing the cell for field calculations"
3705 <<
" did not succeed.\n";
3711bool ComponentAnalyticField::SetupA00() {
3720 for (
unsigned int i = 0; i < m_nWires; ++i) {
3721 m_a[i][i] = m_w[i].r * m_w[i].r;
3723 if (m_ynplax) m_a[i][i] /= 4. *
pow(m_w[i].x - m_coplax, 2);
3724 if (m_ynplay) m_a[i][i] /= 4. *
pow(m_w[i].y - m_coplay, 2);
3726 if (m_ynplax && m_ynplay)
3728 4.0 * (
pow(m_w[i].x - m_coplax, 2) +
pow(m_w[i].y - m_coplay, 2));
3730 m_a[i][i] = -0.5 * log(m_a[i][i]);
3732 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3733 m_a[i][j] =
pow(m_w[i].x - m_w[j].x, 2) +
pow(m_w[i].y - m_w[j].y, 2);
3736 m_a[i][j] = m_a[i][j] / (
pow(m_w[i].x + m_w[j].x - 2. * m_coplax, 2) +
3737 pow(m_w[i].y - m_w[j].y, 2));
3739 m_a[i][j] = m_a[i][j] / (
pow(m_w[i].x - m_w[j].x, 2) +
3740 pow(m_w[i].y + m_w[j].y - 2. * m_coplay, 2));
3742 if (m_ynplax && m_ynplay)
3743 m_a[i][j] *=
pow(m_w[i].x + m_w[j].x - 2. * m_coplax, 2) +
3744 pow(m_w[i].y + m_w[j].y - 2. * m_coplay, 2);
3746 m_a[i][j] = -0.5 * log(m_a[i][j]);
3748 m_a[j][i] = m_a[i][j];
3755bool ComponentAnalyticField::SetupB1X() {
3766 double xx = 0., yy = 0., yymirr = 0.;
3770 for (
unsigned int i = 0; i < m_nWires; ++i) {
3771 m_a[i][i] = -log(m_w[i].r * Pi / m_sx);
3774 yy = (Pi / m_sx) * 2. * (m_w[i].y - m_coplay);
3775 if (
fabs(yy) > 20.) m_a[i][i] +=
fabs(yy) - CLog2;
3776 if (
fabs(yy) <= 20.) m_a[i][i] += log(
fabs(sinh(yy)));
3779 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3780 xx = (Pi / m_sx) * (m_w[i].x - m_w[j].x);
3781 yy = (Pi / m_sx) * (m_w[i].y - m_w[j].y);
3782 if (
fabs(yy) > 20.) m_a[i][j] = -
fabs(yy) + CLog2;
3783 if (
fabs(yy) <= 20.) {
3784 const double sinhy = sinh(yy);
3785 const double sinx =
sin(xx);
3786 m_a[i][j] = -0.5 * log(sinhy * sinhy + sinx * sinx);
3791 yymirr = (Pi / m_sx) * (m_w[i].y + m_w[j].y - 2. * m_coplay);
3792 if (
fabs(yymirr) > 20.) r2plan =
fabs(yymirr) - CLog2;
3793 if (
fabs(yymirr) <= 20.) {
3794 const double sinhy = sinh(yymirr);
3795 const double sinx =
sin(xx);
3796 r2plan = 0.5 * log(sinhy * sinhy + sinx * sinx);
3798 m_a[i][j] += r2plan;
3801 m_a[j][i] = m_a[i][j];
3808bool ComponentAnalyticField::SetupB1Y() {
3818 double xx = 0., yy = 0., xxmirr = 0.;
3822 for (
unsigned int i = 0; i < m_nWires; ++i) {
3823 m_a[i][i] = -log(m_w[i].r * Pi / m_sy);
3826 xx = (Pi / m_sy) * 2. * (m_w[i].x - m_coplax);
3827 if (
fabs(xx) > 20.) m_a[i][i] +=
fabs(xx) - CLog2;
3828 if (
fabs(xx) <= 20.) m_a[i][i] += log(
fabs(sinh(xx)));
3831 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3832 xx = (Pi / m_sy) * (m_w[i].x - m_w[j].x);
3833 yy = (Pi / m_sy) * (m_w[i].y - m_w[j].y);
3834 if (
fabs(xx) > 20.) m_a[i][j] = -
fabs(xx) + CLog2;
3835 if (
fabs(xx) <= 20.) {
3836 const double sinhx = sinh(xx);
3837 const double siny =
sin(yy);
3838 m_a[i][j] = -0.5 * log(sinhx * sinhx + siny * siny);
3842 xxmirr = (Pi / m_sy) * (m_w[i].x + m_w[j].x - 2. * m_coplax);
3844 if (
fabs(xxmirr) > 20.) r2plan =
fabs(xxmirr) - CLog2;
3845 if (
fabs(xxmirr) <= 20.) {
3846 const double sinhx = sinh(xxmirr);
3847 const double siny =
sin(yy);
3848 r2plan = 0.5 * log(sinhx * sinhx + siny * siny);
3850 m_a[i][j] += r2plan;
3853 m_a[j][i] = m_a[i][j];
3860bool ComponentAnalyticField::SetupB2X() {
3872 m_b2sin.resize(m_nWires);
3875 for (
unsigned int i = 0; i < m_nWires; ++i) {
3876 double xx = (Pi / m_sx) * (m_w[i].x - m_coplax);
3877 m_a[i][i] = (0.5 * m_w[i].r * Pi / m_sx) /
sin(xx);
3880 const double yymirr = (Pi / m_sx) * (m_w[i].y - m_coplay);
3881 if (
fabs(yymirr) <= 20.) {
3882 const double sinhy = sinh(yymirr);
3883 const double sinx =
sin(xx);
3884 m_a[i][i] *=
sqrt(sinhy * sinhy + sinx * sinx) / sinhy;
3888 m_a[i][i] = -log(
fabs(m_a[i][i]));
3890 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3891 xx = HalfPi * (m_w[i].x - m_w[j].x) / m_sx;
3892 const double yy = HalfPi * (m_w[i].y - m_w[j].y) / m_sx;
3893 const double xxneg =
3894 HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplax) / m_sx;
3895 if (
fabs(yy) <= 20.) {
3896 const double sinhy = sinh(yy);
3897 const double sinxx =
sin(xx);
3898 const double sinxxneg =
sin(xxneg);
3899 m_a[i][j] = (sinhy * sinhy + sinxx * sinxx) /
3900 (sinhy * sinhy + sinxxneg * sinxxneg);
3902 if (
fabs(yy) > 20.) m_a[i][j] = 1.0;
3905 const double yymirr =
3906 HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplay) / m_sx;
3907 if (
fabs(yymirr) <= 20.) {
3908 const double sinhy = sinh(yymirr);
3909 const double sinxx =
sin(xx);
3910 const double sinxxneg =
sin(xxneg);
3911 m_a[i][j] *= (sinhy * sinhy + sinxxneg * sinxxneg) /
3912 (sinhy * sinhy + sinxx * sinxx);
3916 m_a[i][j] = -0.5 * log(m_a[i][j]);
3917 m_a[j][i] = m_a[i][j];
3920 m_b2sin[i] =
sin(Pi * (m_coplax - m_w[i].x) / m_sx);
3926bool ComponentAnalyticField::SetupB2Y() {
3938 m_b2sin.resize(m_nWires);
3941 for (
unsigned int i = 0; i < m_nWires; ++i) {
3942 double yy = (Pi / m_sy) * (m_w[i].y - m_coplay);
3943 m_a[i][i] = (0.5 * m_w[i].r * Pi / m_sy) /
sin(yy);
3946 const double xxmirr = (Pi / m_sy) * (m_w[i].x - m_coplax);
3947 if (
fabs(xxmirr) <= 20.) {
3948 const double sinhx = sinh(xxmirr);
3949 const double sinyy =
sin(yy);
3950 m_a[i][i] *=
sqrt(sinhx * sinhx + sinyy * sinyy) / sinhx;
3954 m_a[i][i] = -log(
fabs(m_a[i][i]));
3956 for (
unsigned int j = i + 1; j < m_nWires; j++) {
3957 const double xx = HalfPi * (m_w[i].x - m_w[j].x) / m_sy;
3958 yy = HalfPi * (m_w[i].y - m_w[j].y) / m_sy;
3959 const double yyneg =
3960 HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplay) / m_sy;
3961 if (
fabs(xx) <= 20.) {
3962 const double sinhx = sinh(xx);
3963 const double sinyy =
sin(yy);
3964 const double sinyyneg =
sin(yyneg);
3965 m_a[i][j] = (sinhx * sinhx + sinyy * sinyy) /
3966 (sinhx * sinhx + sinyyneg * sinyyneg);
3968 if (
fabs(xx) > 20.) m_a[i][j] = 1.0;
3971 const double xxmirr =
3972 HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplax) / m_sy;
3973 if (
fabs(xxmirr) <= 20.) {
3974 const double sinhx = sinh(xxmirr);
3975 const double sinyy =
sin(yy);
3976 const double sinyyneg =
sin(yyneg);
3977 m_a[i][j] *= (sinhx * sinhx + sinyyneg * sinyyneg) /
3978 (sinhx * sinhx + sinyy * sinyy);
3982 m_a[i][j] = -0.5 * log(m_a[i][j]);
3983 m_a[j][i] = m_a[i][j];
3986 m_b2sin[i] =
sin(Pi * (m_coplay - m_w[i].y) / m_sy);
3992bool ComponentAnalyticField::SetupC10() {
4010 if (m_sy / m_sx < 8.) p =
exp(-Pi * m_sy / m_sx);
4011 m_zmult = std::complex<double>(Pi / m_sx, 0.);
4014 if (m_sx / m_sy < 8.) p =
exp(-Pi * m_sx / m_sy);
4015 m_zmult = std::complex<double>(0., Pi / m_sy);
4018 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
4022 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4024 std::cout <<
" zmult = " << m_zmult <<
"\n";
4025 std::cout <<
" mode = " << m_mode <<
"\n";
4029 for (
unsigned int i = 0; i < m_nWires; ++i) {
4030 for (
unsigned int j = 0; j < m_nWires; ++j) {
4031 const double xyi = m_mode == 0 ? m_w[i].x : m_w[i].y;
4032 const double xyj = m_mode == 0 ? m_w[j].x : m_w[j].y;
4033 const double temp = xyi * xyj * TwoPi / (m_sx * m_sy);
4035 m_a[i][j] = Ph2Lim(m_w[i].r) - temp;
4037 m_a[i][j] = Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) - temp;
4042 if (!Charge())
return false;
4045 for (
unsigned int j = 0; j < m_nWires; ++j) {
4046 const double xyj = m_mode == 0 ? m_w[j].x : m_w[j].y;
4047 s += m_w[j].e * xyj;
4049 m_c1 = -s * 2. * Pi / (m_sx * m_sy);
4053bool ComponentAnalyticField::SetupC2X() {
4067 if (2. * m_sx <= m_sy) {
4069 if (m_sy / m_sx < 25.) p =
exp(-HalfPi * m_sy / m_sx);
4070 m_zmult = std::complex<double>(HalfPi / m_sx, 0.);
4073 if (m_sx / m_sy < 6.) p =
exp(-2. * Pi * m_sx / m_sy);
4074 m_zmult = std::complex<double>(0., Pi / m_sy);
4077 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
4081 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4083 std::cout <<
" zmult = " << m_zmult <<
"\n";
4084 std::cout <<
" mode = " << m_mode <<
"\n";
4088 for (
unsigned int i = 0; i < m_nWires; ++i) {
4090 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
4091 for (
unsigned int j = 0; j < m_nWires; ++j) {
4094 temp = (m_w[i].x - cx) * (m_w[j].x - cx) * TwoPi / (m_sx * m_sy);
4098 Ph2Lim(m_w[i].r) - Ph2(2. * (m_w[i].x - cx), 0.) - temp;
4100 m_a[i][j] = Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
4101 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) -
4107 if (!Charge())
return false;
4112 for (
unsigned int i = 0; i < m_nWires; ++i) {
4114 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
4115 s += m_w[i].e * (m_w[i].x - cx);
4117 m_c1 = -s * TwoPi / (m_sx * m_sy);
4122bool ComponentAnalyticField::SetupC2Y() {
4136 if (m_sx <= 2. * m_sy) {
4138 if (m_sy / m_sx <= 6.) p =
exp(-2. * Pi * m_sy / m_sx);
4139 m_zmult = std::complex<double>(Pi / m_sx, 0.);
4142 if (m_sx / m_sy <= 25.) p =
exp(-HalfPi * m_sx / m_sy);
4143 m_zmult = std::complex<double>(0., HalfPi / m_sy);
4146 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
4150 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4152 std::cout <<
" zmult = " << m_zmult <<
"\n";
4153 std::cout <<
" mode = " << m_mode <<
"\n";
4157 for (
unsigned int i = 0; i < m_nWires; ++i) {
4159 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
4160 for (
unsigned int j = 0; j < m_nWires; ++j) {
4163 temp = (m_w[i].y - cy) * (m_w[j].y - cy) * TwoPi / (m_sx * m_sy);
4167 Ph2Lim(m_w[i].r) - Ph2(0., 2. * (m_w[j].y - cy)) - temp;
4169 m_a[i][j] = Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
4170 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) -
4176 if (!Charge())
return false;
4181 for (
unsigned int i = 0; i < m_nWires; ++i) {
4183 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
4184 s += m_w[i].e * (m_w[i].y - cy);
4186 m_c1 = -s * TwoPi / (m_sx * m_sy);
4191bool ComponentAnalyticField::SetupC30() {
4207 if (m_sy / m_sx <= 13.) p =
exp(-Pi * m_sy / m_sx);
4208 m_zmult = std::complex<double>(HalfPi / m_sx, 0.);
4211 if (m_sx / m_sy <= 13.) p =
exp(-Pi * m_sx / m_sy);
4212 m_zmult = std::complex<double>(0., HalfPi / m_sy);
4215 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
4219 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4221 std::cout <<
" zmult = " << m_zmult <<
"\n";
4222 std::cout <<
" mode = " << m_mode <<
"\n";
4226 for (
unsigned int i = 0; i < m_nWires; ++i) {
4227 double cx = m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
4228 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
4229 for (
unsigned int j = 0; j < m_nWires; ++j) {
4231 m_a[i][i] = Ph2Lim(m_w[i].r) - Ph2(0., 2. * (m_w[i].y - cy)) -
4232 Ph2(2. * (m_w[i].x - cx), 0.) +
4233 Ph2(2. * (m_w[i].x - cx), 2. * (m_w[i].y - cy));
4236 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
4237 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) -
4238 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) +
4239 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y + m_w[j].y - 2. * cy);
4244 if (!Charge())
return false;
4250bool ComponentAnalyticField::SetupD10() {
4259 for (
unsigned int i = 0; i < m_nWires; ++i) {
4261 m_a[i][i] = -log(m_w[i].r * m_cotube /
4262 (m_cotube2 - (m_w[i].x * m_w[i].x + m_w[i].y * m_w[i].y)));
4264 std::complex<double> zi(m_w[i].x, m_w[i].y);
4266 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
4268 std::complex<double> zj(m_w[j].x, m_w[j].y);
4269 m_a[i][j] = -log(abs(m_cotube * (zi - zj) / (m_cotube2 - conj(zi) * zj)));
4271 m_a[j][i] = m_a[i][j];
4278bool ComponentAnalyticField::SetupD20() {
4288 for (
unsigned int i = 0; i < m_nWires; ++i) {
4290 std::complex<double> zi(m_w[i].x, m_w[i].y);
4291 if (abs(zi) < m_w[i].r) {
4294 for (
unsigned int j = 0; j < m_nWires; ++j) {
4300 (m_w[i].x * m_w[i].x + m_w[i].y * m_w[i].y) / m_cotube));
4303 std::complex<double> zj(m_w[j].x, m_w[j].y);
4304 m_a[j][i] = -log(abs((1. / m_cotube) * (zi - zj) /
4305 (1. - conj(zi) * zj / m_cotube2)));
4311 for (
unsigned int j = 0; j < m_nWires; ++j) {
4315 -log(abs(m_w[i].r * m_mtube *
pow(zi, m_mtube - 1) /
4316 (
pow(m_cotube, m_mtube) *
4317 (1. -
pow((abs(zi) / m_cotube), 2 * m_mtube)))));
4320 std::complex<double> zj(m_w[j].x, m_w[j].y);
4321 m_a[j][i] = -log(abs((1 /
pow(m_cotube, m_mtube)) *
4322 (
pow(zj, m_mtube) -
pow(zi, m_mtube)) /
4323 (1. -
pow(zj * conj(zi) / m_cotube2, m_mtube))));
4332bool ComponentAnalyticField::SetupD30() {
4341 wmap.assign(m_nWires, std::complex<double>(0., 0.));
4343 std::complex<double> wd = std::complex<double>(0., 0.);
4346 m_kappa = tgamma((m_ntube + 1.) / m_ntube) *
4347 tgamma((m_ntube - 2.) / m_ntube) / tgamma((m_ntube - 1.) / m_ntube);
4349 for (
unsigned int i = 0; i < m_nWires; ++i) {
4351 ConformalMap(std::complex<double>(m_w[i].x, m_w[i].y) / m_cotube, wmap[i],
4355 abs((m_w[i].r / m_cotube) * wd / (1. -
pow(abs(wmap[i]), 2))));
4357 for (
unsigned int j = 0; j < i; ++j) {
4359 -log(abs((wmap[i] - wmap[j]) / (1. - conj(wmap[i]) * wmap[j])));
4361 m_a[j][i] = m_a[i][j];
4368bool ComponentAnalyticField::Charge() {
4377 std::vector<double> b(m_nWires, 0.);
4378 for (
unsigned int i = 0; i < m_nWires; ++i) {
4379 b[i] = m_w[i].v - (m_corvta * m_w[i].x + m_corvtb * m_w[i].y + m_corvtc);
4384 if (!(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3] || m_tube)) {
4387 m_a.resize(m_nWires + 1);
4388 m_a[m_nWires].clear();
4389 for (
unsigned int i = 0; i < m_nWires; ++i) {
4390 m_a[i].push_back(1.);
4391 m_a[m_nWires].push_back(1.);
4393 m_a[m_nWires].push_back(0.);
4396 std::cerr <<
m_className <<
"::Charge: Matrix inversion failed.\n";
4400 if (m_a[m_nWires][m_nWires] != 0.) {
4401 const double t = 1. / m_a[m_nWires][m_nWires];
4402 for (
unsigned int i = 0; i < m_nWires; ++i) {
4403 for (
unsigned int j = 0; j < m_nWires; ++j) {
4404 m_a[i][j] -= t * m_a[i][m_nWires] * m_a[m_nWires][j];
4409 <<
" True inverse of the capacitance matrix"
4410 <<
" could not be calculated.\n";
4418 std::cerr <<
m_className <<
"::Charge: Matrix inversion failed.\n";
4428 <<
" Failure to solve the capacitance equations.\n"
4429 <<
" No charges are available.\n";
4434 for (
unsigned int i = 0; i < m_nWires; ++i) m_w[i].e = b[i];
4439 std::cout <<
" Dump of the capacitance matrix after inversion:\n";
4440 for (
unsigned int i = 0; i < m_nWires; i += 10) {
4441 for (
unsigned int j = 0; j < m_nWires; j += 10) {
4442 std::cout <<
" (Block " << i / 10 <<
", " << j / 10 <<
")\n";
4443 for (
unsigned int ii = 0; ii < 10; ++ii) {
4444 if (i + ii >= m_nWires)
break;
4445 for (
unsigned int jj = 0; jj < 10; ++jj) {
4446 if (j + jj >= m_nWires)
break;
4447 std::cout << std::setw(6) << m_a[i + ii][j + jj] <<
" ";
4455 std::cout <<
" End of the inverted capacitance matrix.\n";
4459 if (m_chargeCheck) {
4461 std::cout <<
" Quality check of the charge calculation.\n";
4462 std::cout <<
" Wire E as obtained E reconstructed\n";
4463 for (
unsigned int i = 0; i < m_nWires; ++i) {
4465 for (
unsigned int j = 0; j < m_nWires; ++j) {
4468 (m_corvta * m_w[j].x + m_corvtb * m_w[j].y + m_corvtc));
4470 std::cout <<
" " << i <<
" " << m_w[i].e <<
" " << b[i]
4477double ComponentAnalyticField::Ph2(
const double xpos,
const double ypos)
const {
4492 std::complex<double> zeta = m_zmult * std::complex<double>(xpos, ypos);
4493 if (
fabs(imag(zeta)) < 10.) {
4494 std::complex<double> zsin =
sin(zeta);
4495 std::complex<double> zcof = 4. * zsin * zsin - 2.;
4496 std::complex<double> zu = -m_p1 - zcof * m_p2;
4497 std::complex<double> zunew = 1. - zcof * zu - m_p2;
4498 std::complex<double> zterm = (zunew + zu) * zsin;
4499 return -log(abs(zterm));
4502 return -
fabs(imag(zeta)) + CLog2;
4505void ComponentAnalyticField::ConformalMap(
const std::complex<double>& z,
4506 std::complex<double>& ww,
4507 std::complex<double>& wd)
const {
4520 constexpr std::array<std::array<double, 16>, 6> cc1 = {
4521 {{{0.1000000000e+01, -.1666666865e+00, 0.3174602985e-01, -.5731921643e-02,
4522 0.1040112227e-02, -.1886279933e-03, 0.3421107249e-04, -.6204730198e-05,
4523 0.1125329618e-05, -.2040969207e-06, 0.3701631357e-07, -.6713513301e-08,
4524 0.1217605794e-08, -.2208327132e-09, 0.4005162868e-10,
4526 {{0.1000000000e+01, -.1000000238e+00, 0.8333332837e-02, -.7051283028e-03,
4527 0.5967194738e-04, -.5049648280e-05, 0.4273189802e-06, -.3616123934e-07,
4528 0.3060091514e-08, -.2589557457e-09, 0.2191374859e-10, -.1854418528e-11,
4529 0.1569274224e-12, -.1327975205e-13, 0.1123779363e-14,
4531 {{0.1000000000e+01, -.6666666269e-01, 0.1212121220e-02, -.2626262140e-03,
4532 -.3322110570e-04, -.9413293810e-05, -.2570029210e-05, -.7695705904e-06,
4533 -.2422486887e-06, -.7945993730e-07, -.2691839640e-07, -.9361642128e-08,
4534 -.3327319087e-08, -.1204430555e-08, -.4428404310e-09,
4536 {{0.1000000000e+01, -.4761904851e-01, -.1221001148e-02, -.3753788769e-03,
4537 -.9415557724e-04, -.2862767724e-04, -.9587882232e-05, -.3441659828e-05,
4538 -.1299798896e-05, -.5103651119e-06, -.2066504408e-06, -.8578405186e-07,
4539 -.3635090096e-07, -.1567239494e-07, -.6857355572e-08,
4541 {{0.1000000000e+01, -.3571428731e-01, -.2040816238e-02, -.4936389159e-03,
4542 -.1446709794e-03, -.4963850370e-04, -.1877940667e-04, -.7600909157e-05,
4543 -.3232265954e-05, -.1427365532e-05, -.6493634714e-06, -.3026190711e-06,
4544 -.1438593245e-06, -.6953911225e-07, -.3409525462e-07,
4546 {{0.1000000000e+01, -.2777777612e-01, -.2246732125e-02, -.5571441725e-03,
4547 -.1790652314e-03, -.6708275760e-04, -.2766949183e-04, -.1219387286e-04,
4548 -.5640039490e-05, -.2706697160e-05, -.1337270078e-05, -.6763995657e-06,
4549 -.3488264610e-06, -.1828456675e-06, -.9718036154e-07,
4550 -.5227070332e-07}}}};
4552 constexpr std::array<std::array<double, 16>, 6> cc2 = {
4553 {{{0.3333333135e+00, -.5555555597e-01, 0.1014109328e-01, -.1837154618e-02,
4554 0.3332451452e-03, -.6043842586e-04, 0.1096152027e-04, -.1988050826e-05,
4555 0.3605655365e-06, -.6539443120e-07, 0.1186035448e-07, -.2151069323e-08,
4556 0.3901317047e-09, -.7075676156e-10, 0.1283289534e-10,
4558 {{0.1000000000e+01, -.5000000000e+00, 0.3000000119e+00, -.1750000119e+00,
4559 0.1016666889e+00, -.5916666612e-01, 0.3442307562e-01, -.2002724260e-01,
4560 0.1165192947e-01, -.6779119372e-02, 0.3944106400e-02, -.2294691978e-02,
4561 0.1335057430e-02, -.7767395582e-03, 0.4519091453e-03,
4563 {{0.1248050690e+01, -.7788147926e+00, 0.6355384588e+00, -.4899077415e+00,
4564 0.3713272810e+00, -.2838423252e+00, 0.2174729109e+00, -.1663445234e+00,
4565 0.1271933913e+00, -.9728997946e-01, 0.7442557812e-01, -.5692918226e-01,
4566 0.4354400188e-01, -.3330700099e-01, 0.2547712997e-01,
4568 {{0.1333333015e+01, -.8888888955e+00, 0.8395061493e+00, -.7242798209e+00,
4569 0.6016069055e+00, -.5107235312e+00, 0.4393203855e+00, -.3745460510e+00,
4570 0.3175755739e+00, -.2703750730e+00, 0.2308617830e+00, -.1966916919e+00,
4571 0.1672732830e+00, -.1424439549e+00, 0.1214511395e+00,
4573 {{0.1359752655e+01, -.9244638681e+00, 0.9593217969e+00, -.8771237731e+00,
4574 0.7490229011e+00, -.6677658558e+00, 0.6196745634e+00, -.5591596961e+00,
4575 0.4905325770e+00, -.4393517375e+00, 0.4029803872e+00, -.3631100059e+00,
4576 0.3199430704e+00, -.2866140604e+00, 0.2627358437e+00,
4578 {{0.1362840652e+01, -.9286670089e+00, 0.1035511017e+01, -.9800255299e+00,
4579 0.8315343261e+00, -.7592730522e+00, 0.7612683773e+00, -.7132136226e+00,
4580 0.6074471474e+00, -.5554352999e+00, 0.5699443221e+00, -.5357525349e+00,
4581 0.4329345822e+00, -.3916820884e+00, 0.4401986003e+00,
4582 -.4197303057e+00}}}};
4584 constexpr int nterm = 15;
4589 }
else if (std::abs(z) < 0.75) {
4591 std::complex<double> zterm =
pow(m_kappa * z, m_ntube);
4592 std::complex<double> wdsum = 0.;
4593 std::complex<double> wsum = cc1[m_ntube - 3][nterm];
4594 for (
int i = nterm; i--;) {
4595 wdsum = wsum + zterm * wdsum;
4596 wsum = cc1[m_ntube - 3][i] + zterm * wsum;
4599 ww = m_kappa *
z * wsum;
4600 wd = m_kappa * (wsum + double(m_ntube) * zterm * wdsum);
4604 double arot = -TwoPi *
4605 int(round(atan2(imag(z), real(z)) * m_ntube / TwoPi)) /
4607 const std::complex<double> zz =
4608 z * std::complex<double>(
cos(arot),
sin(arot));
4610 std::complex<double> zterm =
4611 pow(m_kappa * (1. - zz), m_ntube / (m_ntube - 2.));
4612 std::complex<double> wdsum = 0.;
4613 std::complex<double> wsum = cc2[m_ntube - 3][nterm];
4614 for (
int i = nterm; i--;) {
4615 wdsum = wsum + zterm * wdsum;
4616 wsum = cc2[m_ntube - 3][i] + zterm * wsum;
4619 ww = std::complex<double>(
cos(arot), -
sin(arot)) * (1. - zterm * wsum);
4620 wd = m_ntube * m_kappa *
pow(m_kappa * (1. - zz), 2. / (m_ntube - 2.)) *
4621 (wsum + zterm * wdsum) / (m_ntube - 2.);
4625void ComponentAnalyticField::E2Sum(
const double xpos,
const double ypos,
4626 double& ex,
double& ey)
const {
4638 constexpr std::complex<double> icons(0., 1.);
4640 std::complex<double> wsum = 0.;
4641 for (
const auto& wire : m_w) {
4643 m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
4644 if (imag(zeta) > 15.) {
4645 wsum -= wire.e * icons;
4646 }
else if (imag(zeta) < -15.) {
4647 wsum += wire.e * icons;
4649 const auto zterm = Th1(zeta, m_p1, m_p2);
4650 wsum += wire.e * (zterm.second / zterm.first);
4653 ex = -real(-m_zmult * wsum);
4654 ey = imag(-m_zmult * wsum);
4657void ComponentAnalyticField::FieldA00(
const double xpos,
const double ypos,
4658 double& ex,
double& ey,
double& volt,
4659 const bool opt)
const {
4678 double xxmirr = 0., yymirr = 0.;
4680 for (
const auto& wire : m_w) {
4681 const double xx = xpos - wire.x;
4682 const double yy = ypos - wire.y;
4683 double r2 = xx * xx + yy * yy;
4685 double exhelp = xx / r2;
4686 double eyhelp = yy / r2;
4689 xxmirr = wire.x + (xpos - 2. * m_coplax);
4690 const double r2plan = xxmirr * xxmirr + yy * yy;
4691 exhelp -= xxmirr / r2plan;
4692 eyhelp -= yy / r2plan;
4697 yymirr = wire.y + (ypos - 2. * m_coplay);
4698 const double r2plan = xx * xx + yymirr * yymirr;
4699 exhelp -= xx / r2plan;
4700 eyhelp -= yymirr / r2plan;
4704 if (m_ynplax && m_ynplay) {
4705 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
4706 exhelp += xxmirr / r2plan;
4707 eyhelp += yymirr / r2plan;
4711 if (opt) volt -= 0.5 * wire.e * log(r2);
4712 ex += wire.e * exhelp;
4713 ey += wire.e * eyhelp;
4717void ComponentAnalyticField::FieldB1X(
const double xpos,
const double ypos,
4718 double& ex,
double& ey,
double& volt,
4719 const bool opt)
const {
4728 constexpr std::complex<double> icons(0., 1.);
4730 std::complex<double> ecompl;
4738 const double tx = Pi / m_sx;
4740 for (
const auto& wire : m_w) {
4741 const double xx = tx * (xpos - wire.x);
4742 const double yy = tx * (ypos - wire.y);
4746 }
else if (yy < -20.) {
4749 const std::complex<double> zz(xx, yy);
4750 const auto expzz =
exp(2. * icons * zz);
4751 ecompl = icons * (expzz + 1.) / (expzz - 1.);
4755 if (
fabs(yy) > 20.) r2 = -
fabs(yy) + CLog2;
4756 if (
fabs(yy) <= 20.) r2 = -0.5 * log(
pow(sinh(yy), 2) +
pow(
sin(xx), 2));
4760 const double yymirr = tx * (ypos + wire.y - 2. * m_coplay);
4763 }
else if (yymirr < -20.) {
4766 const std::complex<double> zzmirr(xx, yymirr);
4767 const auto expzzmirr =
exp(2. * icons * zzmirr);
4768 ecompl += -icons * (expzzmirr + 1.) / (expzzmirr - 1.);
4770 if (opt &&
fabs(yymirr) > 20.) r2 +=
fabs(yymirr) - CLog2;
4771 if (opt &&
fabs(yymirr) <= 20.)
4772 r2 += 0.5 * log(
pow(sinh(yymirr), 2) +
pow(
sin(xx), 2));
4775 ex += wire.e * real(ecompl);
4776 ey -= wire.e * imag(ecompl);
4777 if (opt) volt += wire.e * r2;
4783void ComponentAnalyticField::FieldB1Y(
const double xpos,
const double ypos,
4784 double& ex,
double& ey,
double& volt,
4785 const bool opt)
const {
4794 std::complex<double> ecompl;
4802 const double ty = Pi / m_sy;
4804 for (
const auto& wire : m_w) {
4805 const double xx = ty * (xpos - wire.x);
4806 const double yy = ty * (ypos - wire.y);
4810 }
else if (xx < -20.) {
4813 const std::complex<double> zz(xx, yy);
4814 const auto expzz =
exp(2. * zz);
4815 ecompl = (expzz + 1.) / (expzz - 1.);
4818 if (
fabs(xx) > 20.) r2 = -
fabs(xx) + CLog2;
4819 if (
fabs(xx) <= 20.) r2 = -0.5 * log(
pow(sinh(xx), 2) +
pow(
sin(yy), 2));
4823 const double xxmirr = ty * (xpos + wire.x - 2. * m_coplax);
4826 }
else if (xxmirr < -20.) {
4829 const std::complex<double> zzmirr(xxmirr, yy);
4830 const auto expzzmirr =
exp(2. * zzmirr);
4831 ecompl -= (expzzmirr + 1.) / (expzzmirr - 1.);
4833 if (opt &&
fabs(xxmirr) > 20.) r2 +=
fabs(xxmirr) - CLog2;
4834 if (opt &&
fabs(xxmirr) <= 20.)
4835 r2 += 0.5 * log(
pow(sinh(xxmirr), 2) +
pow(
sin(yy), 2));
4838 ex += wire.e * real(ecompl);
4839 ey -= wire.e * imag(ecompl);
4840 if (opt) volt += wire.e * r2;
4846void ComponentAnalyticField::FieldB2X(
const double xpos,
const double ypos,
4847 double& ex,
double& ey,
double& volt,
4848 const bool opt)
const {
4862 const double tx = HalfPi / m_sx;
4864 for (
unsigned int i = 0; i < m_nWires; ++i) {
4865 const double xx = tx * (xpos - m_w[i].x);
4866 const double yy = tx * (ypos - m_w[i].y);
4867 const double xxneg = tx * (xpos - m_w[i].x - 2 * m_coplax);
4869 std::complex<double> ecompl(0., 0.);
4871 if (
fabs(yy) <= 20.) {
4872 const std::complex<double> zz(xx, yy);
4873 const std::complex<double> zzneg(xxneg, yy);
4874 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
4876 const double sinhy = sinh(yy);
4877 const double sinxx =
sin(xx);
4878 const double sinxxneg =
sin(xxneg);
4879 r2 = (sinhy * sinhy + sinxx * sinxx) /
4880 (sinhy * sinhy + sinxxneg * sinxxneg);
4885 const double yymirr = tx * (ypos + m_w[i].y - 2 * m_coplay);
4886 if (
fabs(yymirr) <= 20.) {
4887 const std::complex<double> zzmirr(xx, yymirr);
4888 const std::complex<double> zznmirr(xxneg, yymirr);
4889 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
4891 const double sinhy = sinh(yymirr);
4892 const double sinxx =
sin(xx);
4893 const double sinxxneg =
sin(xxneg);
4894 const double r2plan = (sinhy * sinhy + sinxx * sinxx) /
4895 (sinhy * sinhy + sinxxneg * sinxxneg);
4901 ex += m_w[i].e * real(ecompl);
4902 ey -= m_w[i].e * imag(ecompl);
4903 if (opt) volt -= 0.5 * m_w[i].e * log(r2);
4909void ComponentAnalyticField::FieldB2Y(
const double xpos,
const double ypos,
4910 double& ex,
double& ey,
double& volt,
4911 const bool opt)
const {
4921 const std::complex<double> icons(0., 1.);
4927 const double ty = HalfPi / m_sy;
4929 for (
unsigned int i = 0; i < m_nWires; ++i) {
4930 const double xx = ty * (xpos - m_w[i].x);
4931 const double yy = ty * (ypos - m_w[i].y);
4932 const double yyneg = ty * (ypos + m_w[i].y - 2 * m_coplay);
4934 std::complex<double> ecompl(0., 0.);
4936 if (
fabs(xx) <= 20.) {
4937 const std::complex<double> zz(xx, yy);
4938 const std::complex<double> zzneg(xx, yyneg);
4939 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
4941 const double sinhx = sinh(xx);
4942 const double sinyy =
sin(yy);
4943 const double sinyyneg =
sin(yyneg);
4944 r2 = (sinhx * sinhx + sinyy * sinyy) /
4945 (sinhx * sinhx + sinyyneg * sinyyneg);
4950 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
4951 if (
fabs(xxmirr) <= 20.) {
4952 const std::complex<double> zzmirr(xxmirr, yy);
4953 const std::complex<double> zznmirr(xxmirr, yyneg);
4955 icons * m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
4957 const double sinhx = sinh(xxmirr);
4958 const double sinyy =
sin(yy);
4959 const double sinyyneg =
sin(yyneg);
4960 const double r2plan = (sinhx * sinhx + sinyy * sinyy) /
4961 (sinhx * sinhx + sinyyneg * sinyyneg);
4967 ex += m_w[i].e * real(ecompl);
4968 ey -= m_w[i].e * imag(ecompl);
4969 if (opt) volt -= 0.5 * m_w[i].e * log(r2);
4975void ComponentAnalyticField::FieldC10(
const double xpos,
const double ypos,
4976 double& ex,
double& ey,
double& volt,
4977 const bool opt)
const {
4986 if (m_mode == 0) volt = m_v0 + m_c1 * xpos;
4987 if (m_mode == 1) volt = m_v0 + m_c1 * ypos;
4988 for (
const auto& wire : m_w) {
4989 volt += wire.e * Ph2(xpos - wire.x, ypos - wire.y);
4994 E2Sum(xpos, ypos, ex, ey);
4995 if (m_mode == 0) ex -= m_c1;
4996 if (m_mode == 1) ey -= m_c1;
4999void ComponentAnalyticField::FieldC2X(
const double xpos,
const double ypos,
5000 double& ex,
double& ey,
double& volt,
5001 const bool opt)
const {
5008 constexpr std::complex<double> icons(0., 1.);
5011 std::complex<double> wsum1 = 0.;
5012 std::complex<double> wsum2 = 0.;
5016 for (
const auto& wire : m_w) {
5018 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
5019 if (imag(zeta) > 15.) {
5020 wsum1 -= wire.e * icons;
5021 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5022 }
else if (imag(zeta) < -15.) {
5023 wsum1 += wire.e * icons;
5024 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5026 const auto zterm = Th1(zeta, m_p1, m_p2);
5027 wsum1 += wire.e * (zterm.second / zterm.first);
5028 if (opt) volt -= wire.e * log(abs(zterm.first));
5031 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
5034 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
5035 if (imag(zeta) > 15.) {
5036 wsum2 -= wire.e * icons;
5037 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5038 }
else if (imag(zeta) < -15.) {
5039 wsum2 += wire.e * icons;
5040 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5042 const auto zterm = Th1(zeta, m_p1, m_p2);
5043 wsum2 += wire.e * (zterm.second / zterm.first);
5044 if (opt) volt += wire.e * log(abs(zterm.first));
5047 if (opt && m_mode == 0) {
5048 volt -= TwoPi * wire.e * (xpos - cx) * (wire.x - cx) / (m_sx * m_sy);
5052 ex = real(m_zmult * (wsum1 + wsum2));
5053 ey = -imag(m_zmult * (wsum1 - wsum2));
5055 if (m_mode == 0) ex -= m_c1;
5058void ComponentAnalyticField::FieldC2Y(
const double xpos,
const double ypos,
5059 double& ex,
double& ey,
double& volt,
5060 const bool opt)
const {
5067 constexpr std::complex<double> icons(0., 1.);
5071 std::complex<double> wsum1 = 0.;
5072 std::complex<double> wsum2 = 0.;
5075 for (
const auto& wire : m_w) {
5077 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
5078 if (imag(zeta) > 15.) {
5079 wsum1 -= wire.e * icons;
5080 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5081 }
else if (imag(zeta) < -15.) {
5082 wsum1 += wire.e * icons;
5083 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5085 const auto zterm = Th1(zeta, m_p1, m_p2);
5086 wsum1 += wire.e * (zterm.second / zterm.first);
5087 if (opt) volt -= wire.e * log(abs(zterm.first));
5090 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
5093 m_zmult * std::complex<double>(xpos - wire.x, 2 * cy - ypos - wire.y);
5094 if (imag(zeta) > 15.) {
5095 wsum2 -= wire.e * icons;
5096 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5097 }
else if (imag(zeta) < -15.) {
5098 wsum2 += wire.e * icons;
5099 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5101 const auto zterm = Th1(zeta, m_p1, m_p2);
5102 wsum2 += wire.e * (zterm.second / zterm.first);
5103 if (opt) volt += wire.e * log(abs(zterm.first));
5106 if (opt && m_mode == 1) {
5107 volt -= TwoPi * wire.e * (ypos - cy) * (wire.y - cy) / (m_sx * m_sy);
5111 ex = real(m_zmult * (wsum1 - wsum2));
5112 ey = -imag(m_zmult * (wsum1 + wsum2));
5114 if (m_mode == 1) ey -= m_c1;
5117void ComponentAnalyticField::FieldC30(
const double xpos,
const double ypos,
5118 double& ex,
double& ey,
double& volt,
5119 const bool opt)
const {
5126 constexpr std::complex<double> icons(0., 1.);
5129 std::complex<double> wsum1 = 0.;
5130 std::complex<double> wsum2 = 0.;
5131 std::complex<double> wsum3 = 0.;
5132 std::complex<double> wsum4 = 0.;
5136 for (
const auto& wire : m_w) {
5138 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
5139 if (imag(zeta) > 15.) {
5140 wsum1 -= wire.e * icons;
5141 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5142 }
else if (imag(zeta) < -15.) {
5143 wsum1 += wire.e * icons;
5144 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5146 const auto zterm = Th1(zeta, m_p1, m_p2);
5147 wsum1 += wire.e * (zterm.second / zterm.first);
5148 if (opt) volt -= wire.e * log(abs(zterm.first));
5151 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
5154 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
5155 if (imag(zeta) > 15.) {
5156 wsum2 -= wire.e * icons;
5157 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5158 }
else if (imag(zeta) < -15.) {
5159 wsum2 += wire.e * icons;
5160 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5162 const auto zterm = Th1(zeta, m_p1, m_p2);
5163 wsum2 += wire.e * (zterm.second / zterm.first);
5164 if (opt) volt += wire.e * log(abs(zterm.first));
5167 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
5170 m_zmult * std::complex<double>(xpos - wire.x, 2. * cy - ypos - wire.y);
5171 if (imag(zeta) > 15.) {
5172 wsum3 -= wire.e * icons;
5173 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5174 }
else if (imag(zeta) < -15.) {
5175 wsum3 += wire.e * icons;
5176 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5178 const auto zterm = Th1(zeta, m_p1, m_p2);
5179 wsum3 += wire.e * (zterm.second / zterm.first);
5180 if (opt) volt += wire.e * log(abs(zterm.first));
5183 zeta = m_zmult * std::complex<double>(2. * cx - xpos - wire.x,
5184 2. * cy - ypos - wire.y);
5185 if (imag(zeta) > 15.) {
5186 wsum4 -= wire.e * icons;
5187 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5188 }
else if (imag(zeta) < -15.) {
5189 wsum4 += wire.e * icons;
5190 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5192 const auto zterm = Th1(zeta, m_p1, m_p2);
5193 wsum4 += wire.e * (zterm.second / zterm.first);
5194 if (opt) volt -= wire.e * log(abs(zterm.first));
5198 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
5199 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
5202void ComponentAnalyticField::FieldD10(
const double xpos,
const double ypos,
5203 double& ex,
double& ey,
double& volt,
5204 const bool opt)
const {
5220 const std::complex<double> zpos = std::complex<double>(xpos, ypos);
5222 for (
const auto& wire : m_w) {
5224 const std::complex<double> zi(wire.x, wire.y);
5228 log(abs(m_cotube * (zpos - zi) / (m_cotube2 - zpos * conj(zi))));
5231 const std::complex<double> wi =
5232 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
5233 ex += wire.e * real(wi);
5234 ey += wire.e * imag(wi);
5238void ComponentAnalyticField::FieldD20(
const double xpos,
const double ypos,
5239 double& ex,
double& ey,
double& volt,
5240 const bool opt)
const {
5256 const std::complex<double> zpos = std::complex<double>(xpos, ypos);
5258 for (
const auto& wire : m_w) {
5260 const std::complex<double> zi(wire.x, wire.y);
5262 if (abs(zi) > wire.r) {
5266 wire.e * log(abs((1. /
pow(m_cotube, m_mtube)) *
5267 (
pow(zpos, m_mtube) -
pow(zi, m_mtube)) /
5268 (1. -
pow(zpos * conj(zi) / m_cotube2, m_mtube))));
5271 const std::complex<double> wi =
5272 double(m_mtube) *
pow(conj(zpos), m_mtube - 1) *
5273 (1. / conj(
pow(zpos, m_mtube) -
pow(zi, m_mtube)) +
5275 (
pow(m_cotube, 2 * m_mtube) -
pow(conj(zpos) * zi, m_mtube)));
5276 ex += wire.e * real(wi);
5277 ey += wire.e * imag(wi);
5281 volt -= wire.e * log(abs((1. / m_cotube) * (zpos - zi) /
5282 (1. - zpos * conj(zi) / m_cotube2)));
5284 const std::complex<double> wi =
5285 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
5287 ex += wire.e * real(wi);
5288 ey += wire.e * imag(wi);
5293void ComponentAnalyticField::FieldD30(
const double xpos,
const double ypos,
5294 double& ex,
double& ey,
double& volt,
5295 const bool opt)
const {
5310 std::complex<double> whelp;
5313 std::complex<double> wpos, wdpos;
5314 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
5316 for (
int i = m_nWires; i--;) {
5320 m_w[i].e * log(abs((wpos - wmap[i]) / (1. - wpos * conj(wmap[i]))));
5322 whelp = wdpos * (1. -
pow(abs(wmap[i]), 2)) /
5323 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
5325 ex += m_w[i].e * real(whelp);
5326 ey -= m_w[i].e * imag(whelp);
5332bool ComponentAnalyticField::InTube(
const double x0,
const double y0,
5333 const double a,
const int n)
const {
5342 if (x0 == 0. && y0 == 0.)
return true;
5346 if (x0 * x0 + y0 * y0 > a * a)
return false;
5350 if (n < 0 || n == 1 || n == 2) {
5352 std::cerr <<
" Invalid number of edges (n = " << n <<
")\n";
5358 double phi = atan2(y0, x0);
5359 if (phi < 0.)
phi += TwoPi;
5360 phi -= TwoPi * int(0.5 * n * phi / Pi) / n;
5362 if ((x0 * x0 + y0 * y0) *
pow(
cos(Pi / n - phi), 2) >
5363 a * a *
pow(
cos(Pi / n), 2))
5369void ComponentAnalyticField::Field3dA00(
const double xpos,
const double ypos,
5370 const double zpos,
double& ex,
5371 double& ey,
double& ez,
double& volt) {
5384 ex = ey = ez = volt = 0.;
5387 for (
const auto& charge : m_ch3d) {
5389 const double dx = xpos - charge.x;
5390 const double dy = ypos - charge.y;
5391 const double dz = zpos - charge.z;
5392 const double r =
sqrt(dx * dx + dy * dy + dz * dz);
5393 if (
fabs(r) < Small)
continue;
5394 const double r3 =
pow(r, 3);
5395 double exhelp = -dx / r3;
5396 double eyhelp = -dy / r3;
5397 double ezhelp = -dz / r3;
5398 double vhelp = 1. / r;
5400 double dxm = 0., dym = 0.;
5402 dxm = charge.x + xpos - 2 * m_coplax;
5403 const double rplan =
sqrt(dxm * dxm + dy * dy);
5404 if (
fabs(rplan) < Small)
continue;
5405 const double rplan3 =
pow(rplan, 3);
5406 exhelp += dxm / rplan3;
5407 eyhelp += dy / rplan3;
5408 ezhelp += dz / rplan3;
5409 vhelp -= 1. / rplan;
5413 dym = charge.y + ypos - 2. * m_coplay;
5414 const double rplan =
sqrt(dx * dx + dym * dym);
5415 if (
fabs(rplan) < Small)
continue;
5416 const double rplan3 =
pow(rplan, 3);
5417 exhelp += dx / rplan3;
5418 eyhelp += dym / rplan3;
5419 ezhelp += dz / rplan3;
5420 vhelp -= 1. / rplan;
5423 if (m_ynplax && m_ynplay) {
5424 const double rplan =
sqrt(dxm * dxm + dym * dym);
5425 if (
fabs(rplan) < Small)
continue;
5426 const double rplan3 =
pow(rplan, 3);
5427 exhelp -= dxm / rplan3;
5428 eyhelp -= dym / rplan3;
5429 ezhelp -= dz / rplan3;
5430 vhelp += 1. / rplan;
5433 ex -= charge.e * exhelp;
5434 ey -= charge.e * eyhelp;
5435 ez -= charge.e * ezhelp;
5436 volt += charge.e * vhelp;
5440void ComponentAnalyticField::Field3dB2X(
const double xpos,
const double ypos,
5441 const double zpos,
double& ex,
5442 double& ey,
double& ez,
double& volt) {
5452 const double rcut = 1.;
5454 double rr1, rr2, rm1, rm2, err, ezz;
5455 double exsum = 0., eysum = 0., ezsum = 0., vsum = 0.;
5456 double k0r, k1r, k0rm, k1rm;
5459 ex = ey = ez = volt = 0.;
5462 for (
const auto& charge : m_ch3d) {
5464 if (xpos == charge.x && ypos == charge.y && zpos == charge.z)
continue;
5465 const double dx = xpos - charge.x;
5466 const double dy = ypos - charge.y;
5467 const double dz = zpos - charge.z;
5468 const double dxm = xpos + charge.x - 2 * m_coplax;
5470 if (dy * dy + dz * dz >
pow(rcut * 2 * m_sx, 2)) {
5472 exsum = eysum = ezsum = vsum = 0.;
5474 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5476 const double rr = Pi * j *
sqrt(dy * dy + dz * dz) / m_sx;
5477 const double zzp = Pi * j * dx / m_sx;
5478 const double zzn = Pi * j * dxm / m_sx;
5488 const double czzp =
cos(zzp);
5489 const double czzn =
cos(zzn);
5490 vsum += (1. / m_sx) * k0r * (czzp - czzn);
5491 err = (TwoPi * j / (m_sx * m_sx)) * k1r * (czzp - czzn);
5492 ezz = (TwoPi * j / (m_sx * m_sx)) * k0r * (
sin(zzp) -
sin(zzn));
5494 eysum += err * dy /
sqrt(dy * dy + dz * dz);
5495 ezsum += err * dz /
sqrt(dy * dy + dz * dz);
5501 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5503 rr1 =
sqrt(
pow(dx + j * 2 * m_sx, 2) + dy * dy + dz * dz);
5504 rr2 =
sqrt(
pow(dx - j * 2 * m_sx, 2) + dy * dy + dz * dz);
5505 rm1 =
sqrt(
pow(dxm - j * 2 * m_sx, 2) + dy * dy + dz * dz);
5506 rm2 =
sqrt(
pow(dxm + j * 2 * m_sx, 2) + dy * dy + dz * dz);
5507 const double rr13 =
pow(rr1, 3);
5508 const double rm13 =
pow(rm1, 3);
5511 vsum = 1. / rr1 - 1. / rm1;
5512 exsum = dx / rr13 - dxm / rm13;
5513 eysum = dy * (1. / rr13 - 1. / rm13);
5514 ezsum = dz * (1. / rr13 - 1. / rm13);
5517 const double rr23 =
pow(rr2, 3);
5518 const double rm23 =
pow(rm2, 3);
5520 vsum += 1. / rr1 + 1. / rr2 - 1. / rm1 - 1. / rm2;
5521 exsum += (dx + j * 2 * m_sx) / rr13 + (dx - j * 2 * m_sx) / rr23 -
5522 (dxm - j * 2 * m_sx) / rm13 - (dxm + j * 2 * m_sx) / rm23;
5523 eysum += dy * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5524 ezsum += dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5529 const double dym = ypos + charge.y - 2. * m_coplay;
5530 if (dym * dym + dz * dz >
pow(rcut * 2 * m_sx, 2)) {
5533 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5535 const double rrm = Pi * j *
sqrt(dym * dym + dz * dz) / m_sx;
5536 const double zzp = Pi * j * dx / m_sx;
5537 const double zzn = Pi * j * dxm / m_sx;
5547 const double czzp =
cos(zzp);
5548 const double czzn =
cos(zzn);
5549 vsum += (1. / m_sx) * k0rm * (czzp - czzn);
5550 err = (TwoPi / (m_sx * m_sx)) * k1rm * (czzp - czzn);
5551 ezz = (TwoPi / (m_sx * m_sx)) * k0rm * (
sin(zzp) -
sin(zzn));
5553 eysum += err * dym /
sqrt(dym * dym + dz * dz);
5554 ezsum += err * dz /
sqrt(dym * dym + dz * dz);
5559 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5561 rr1 =
sqrt(
pow(dx + j * 2 * m_sx, 2) + dym * dym + dz * dz);
5562 rr2 =
sqrt(
pow(dx - j * 2 * m_sx, 2) + dym * dym + dz * dz);
5563 rm1 =
sqrt(
pow(dxm - j * 2 * m_sx, 2) + dym * dym + dz * dz);
5564 rm2 =
sqrt(
pow(dxm + j * 2 * m_sx, 2) + dym * dym + dz * dz);
5565 const double rr13 =
pow(rr1, 3);
5566 const double rm13 =
pow(rm1, 3);
5569 vsum += -1. / rr1 + 1. / rm1;
5570 exsum += -dx / rr13 + dxm / rm13;
5571 eysum += -dym * (1. / rr13 - 1. / rm13);
5572 ezsum += -dz * (1. / rr13 - 1. / rm13);
5575 const double rr23 =
pow(rr2, 3);
5576 const double rm23 =
pow(rm2, 3);
5578 vsum += -1. / rr1 - 1. / rr2 + 1. / rm1 + 1. / rm2;
5579 exsum += -(dx + j * 2 * m_sx) / rr13 - (dx - j * 2 * m_sx) / rr23 +
5580 (dxm - j * 2 * m_sx) / rm13 + (dxm + j * 2 * m_sx) / rm23;
5581 eysum += -dym * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5582 ezsum += -dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5586 ex += charge.e * exsum;
5587 ey += charge.e * eysum;
5588 ez += charge.e * ezsum;
5589 volt += charge.e * vsum;
5593void ComponentAnalyticField::Field3dB2Y(
const double xpos,
const double ypos,
5594 const double zpos,
double& ex,
5595 double& ey,
double& ez,
double& volt) {
5605 const double rcut = 1.;
5607 double rr1, rr2, rm1, rm2, err, ezz;
5608 double exsum = 0., eysum = 0., ezsum = 0., vsum = 0.;
5609 double k0r, k1r, k0rm, k1rm;
5612 ex = ey = ez = volt = 0.;
5615 for (
const auto& charge : m_ch3d) {
5617 if (xpos == charge.x && ypos == charge.y && zpos == charge.z)
continue;
5618 const double dx = xpos - charge.x;
5619 const double dy = ypos - charge.y;
5620 const double dz = zpos - charge.z;
5621 const double dym = ypos + charge.y - 2 * m_coplay;
5623 if (dx * dx + dz * dz >
pow(rcut * 2 * m_sy, 2)) {
5625 exsum = eysum = ezsum = vsum = 0.;
5627 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5629 const double rr = Pi * j *
sqrt(dx * dx + dz * dz) / m_sy;
5630 const double zzp = Pi * j * dy / m_sy;
5631 const double zzn = Pi * j * dym / m_sy;
5641 const double czzp =
cos(zzp);
5642 const double czzn =
cos(zzn);
5643 vsum += (1. / m_sy) * k0r * (czzp - czzn);
5644 err = (TwoPi * j / (m_sy * m_sy)) * k1r * (czzp - czzn);
5645 ezz = (TwoPi * j / (m_sy * m_sy)) * k0r * (
sin(zzp) -
sin(zzn));
5646 exsum += err * dx /
sqrt(dx * dx + dz * dz);
5647 ezsum += err * dz /
sqrt(dx * dx + dz * dz);
5654 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5656 rr1 =
sqrt(dx * dx + dz * dz +
pow(dy + j * 2 * m_sy, 2));
5657 rr2 =
sqrt(dx * dx + dz * dz +
pow(dy - j * 2 * m_sy, 2));
5658 rm1 =
sqrt(dx * dx + dz * dz +
pow(dym - j * 2 * m_sy, 2));
5659 rm2 =
sqrt(dx * dx + dz * dz +
pow(dym + j * 2 * m_sy, 2));
5660 const double rr13 =
pow(rr1, 3);
5661 const double rm13 =
pow(rm1, 3);
5664 vsum = 1. / rr1 - 1. / rm1;
5665 exsum = dx * (1. / rr13 - 1. / rm13);
5666 ezsum = dz * (1. / rr13 - 1. / rm13);
5667 eysum = dy / rr13 - dym / rm13;
5671 const double rr23 =
pow(rr2, 3);
5672 const double rm23 =
pow(rm2, 3);
5673 vsum += 1. / rr1 + 1. / rr2 - 1. / rm1 - 1. / rm2;
5674 exsum += dx * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5675 ezsum += dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5676 eysum += (dy + j * 2 * m_sy) / rr13 + (dy - j * 2 * m_sy) / rr23 -
5677 (dym - j * 2 * m_sy) / rm13 - (dym + j * 2 * m_sy) / rm23;
5682 const double dxm = xpos + charge.x - 2. * m_coplax;
5683 if (dxm * dxm + dz * dz >
pow(rcut * 2 * m_sy, 2)) {
5686 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5688 const double rrm = Pi * j *
sqrt(dxm * dxm + dz * dz) / m_sy;
5689 const double zzp = Pi * j * dy / m_sy;
5690 const double zzn = Pi * j * dym / m_sy;
5700 const double czzp =
cos(zzp);
5701 const double czzn =
cos(zzn);
5702 vsum += (1. / m_sy) * k0rm * (czzp - czzn);
5703 err = (TwoPi / (m_sy * m_sy)) * k1rm * (czzp - czzn);
5704 ezz = (TwoPi / (m_sy * m_sy)) * k0rm * (
sin(zzp) -
sin(zzn));
5705 exsum += err * dxm /
sqrt(dxm * dxm + dz * dz);
5706 ezsum += err * dz /
sqrt(dxm * dxm + dz * dz);
5712 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5714 rr1 =
sqrt(
pow(dy + j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5715 rr2 =
sqrt(
pow(dy - j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5716 rm1 =
sqrt(
pow(dym - j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5717 rm2 =
sqrt(
pow(dym + j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5718 const double rr13 =
pow(rr1, 3);
5719 const double rm13 =
pow(rm1, 3);
5722 vsum += -1. / rr1 + 1. / rm1;
5723 exsum += -dxm * (1. / rr13 - 1. / rm13);
5724 ezsum += -dz * (1. / rr13 - 1. / rm13);
5725 eysum += -dy / rr13 + dym / rm13;
5728 const double rr23 =
pow(rr2, 3);
5729 const double rm23 =
pow(rm2, 3);
5731 vsum += -1. / rr1 - 1. / rr2 + 1. / rm1 + 1. / rm2;
5732 exsum += -dxm * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5733 ezsum += -dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5734 eysum += -(dy + j * 2 * m_sy) / rr13 - (dy - j * 2 * m_sy) / rr23 +
5735 (dym - j * 2 * m_sy) / rm13 + (dym + j * 2 * m_sy) / rm23;
5739 ex += charge.e * exsum;
5740 ey += charge.e * eysum;
5741 ez += charge.e * ezsum;
5742 volt += charge.e * vsum;
5746void ComponentAnalyticField::Field3dD10(
const double xxpos,
const double yypos,
5747 const double zzpos,
double& eex,
5748 double& eey,
double& eez,
5759 const double rcut = 1.;
5761 double x3d, y3d, z3d;
5762 double exsum = 0., eysum = 0., ezsum = 0., vsum = 0.;
5763 double rr1, rr2, rm1, rm2, err, ezz;
5767 eex = eey = eez = volt = 0.;
5768 double ex = 0., ey = 0., ez = 0.;
5773 std::cerr <<
" Inappropriate potential function.\n";
5778 const double ssx = log(m_cotube / m_w[0].r);
5779 const double cpl = log(m_w[0].r);
5782 const double xpos = 0.5 * log(xxpos * xxpos + yypos * yypos);
5783 const double ypos = atan2(yypos, xxpos);
5784 const double zpos = zzpos;
5787 for (
const auto& charge : m_ch3d) {
5788 for (
int ii = -1; ii <= 1; ++ii) {
5790 x3d = 0.5 * log(charge.x * charge.x + charge.y * charge.y);
5791 y3d = atan2(charge.y, charge.x + ii * TwoPi);
5793 const double dx = xpos - x3d;
5794 const double dy = ypos - y3d;
5795 const double dz = zpos - z3d;
5796 const double dxm = xpos + x3d - 2 * cpl;
5798 if (xpos == x3d && ypos == y3d && zpos == z3d)
continue;
5800 if (dy * dy + dz * dz >
pow(rcut * 2 * ssx, 2)) {
5802 exsum = eysum = ezsum = vsum = 0.;
5804 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5806 const double rr = Pi * j *
sqrt(dy * dy + dz * dz) / ssx;
5807 const double zzp = Pi * j * dx / ssx;
5808 const double zzn = Pi * j * dxm / ssx;
5818 const double czzp =
cos(zzp);
5819 const double czzn =
cos(zzn);
5820 vsum += (1. / ssx) * k0r * (czzp - czzn);
5821 err = (j * TwoPi / (ssx * ssx)) * k1r * (czzp - czzn);
5822 ezz = (j * TwoPi / (ssx * ssx)) * k0r * (
sin(zzp) -
sin(zzn));
5824 eysum += err * dy /
sqrt(dy * dy + dz * dz);
5825 ezsum += err * dz /
sqrt(dy * dy + dz * dz);
5831 for (
unsigned int j = 0; j < m_nTermPoly; ++j) {
5833 rr1 =
sqrt(
pow(dx + j * 2 * ssx, 2) + dy * dy + dz * dz);
5834 rr2 =
sqrt(
pow(dx - j * 2 * ssx, 2) + dy * dy + dz * dz);
5835 rm1 =
sqrt(
pow(dxm - j * 2 * ssx, 2) + dy * dy + dz * dz);
5836 rm2 =
sqrt(
pow(dxm + j * 2 * ssx, 2) + dy * dy + dz * dz);
5837 const double rr13 =
pow(rr1, 3);
5838 const double rm13 =
pow(rm1, 3);
5841 vsum = 1. / rr1 - 1. / rm1;
5842 exsum = dxm / rr13 - dxm / rm13;
5843 eysum = dy * (1. / rr13 - 1. / rm13);
5844 ezsum = dz * (1. / rr13 - 1. / rm13);
5847 const double rr23 =
pow(rr2, 3);
5848 const double rm23 =
pow(rm2, 3);
5850 vsum += 1. / rr1 + 1. / rr2 - 1. / rm1 - 1. / rm2;
5851 exsum += (dx + j * 2 * ssx) / rr13 + (dx - j * 2 * ssx) / rr23 -
5852 (dxm - j * 2 * ssx) / rm13 - (dxm + j * 2 * ssx) / rm23;
5853 eysum += dy * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5854 ezsum += dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5857 ex += charge.e * exsum;
5858 ey += charge.e * eysum;
5859 ez += charge.e * ezsum;
5865 eex =
exp(-xpos) * (ex *
cos(ypos) - ey *
sin(ypos));
5866 eey =
exp(-ypos) * (ex *
sin(ypos) + ey *
cos(ypos));
5870bool ComponentAnalyticField::PrepareSignals() {
5876 if (m_readout.empty()) {
5877 std::cerr <<
m_className <<
"::PrepareSignals:\n";
5878 std::cerr <<
" There are no readout groups defined.\n";
5879 std::cerr <<
" Calculation of weighting fields makes no sense.\n";
5883 if (!m_cellset && !Prepare()) {
5884 std::cerr <<
m_className <<
"::PrepareSignals: Cell not set up.\n";
5888 std::lock_guard<std::mutex> guard(m_mutex);
5892 if (m_nFourier == 0) {
5893 m_cellTypeFourier = m_cellType;
5894 }
else if (m_cellType ==
A00 || m_cellType ==
B1X || m_cellType ==
B1Y ||
5895 m_cellType ==
C10) {
5896 m_cellTypeFourier =
A00;
5897 }
else if (m_cellType ==
B2X || m_cellType ==
C2X) {
5898 m_cellTypeFourier =
B2X;
5899 }
else if (m_cellType ==
B2Y || m_cellType ==
C2Y) {
5900 m_cellTypeFourier =
B2Y;
5901 }
else if (m_cellType ==
C30) {
5902 m_cellTypeFourier =
C30;
5903 }
else if (m_cellType ==
D10) {
5904 m_cellTypeFourier =
D10;
5905 }
else if (m_cellType ==
D30) {
5906 m_cellTypeFourier =
D30;
5910 <<
" No potentials available to handle cell type "
5916 m_fperx = m_fpery =
false;
5917 if (m_nFourier == 0) {
5920 if (m_cellType ==
B1X || m_cellType ==
C10 || m_cellType ==
C2Y) {
5923 if (m_cellType ==
B1Y || m_cellType ==
C10 || m_cellType ==
C2X) {
5926 m_mfexp = int(0.1 + log(1. * m_nFourier) / log(2.));
5928 m_fperx = m_fpery =
false;
5932 m_mxmin = m_mymin = m_mxmax = m_mymax = 0;
5934 m_mxmin = std::min(0, 1 - m_nFourier / 2);
5935 m_mxmax = m_nFourier / 2;
5938 m_mymin = std::min(0, 1 - m_nFourier / 2);
5939 m_mymax = m_nFourier / 2;
5945 <<
" Cell type: " <<
GetCellType(m_cellType) <<
"\n"
5946 <<
" Fourier cell type: " <<
GetCellType(m_cellTypeFourier)
5948 std::cout <<
" x convolutions: " << m_fperx <<
"\n"
5949 <<
" y convolutions: " << m_fpery <<
"\n";
5950 std::cout <<
" No of Fourier terms: " << m_nFourier <<
" (= 2**"
5951 << m_mfexp <<
")\n";
5955 if (!SetupWireSignals()) {
5956 std::cerr <<
m_className <<
"::PrepareSignals:\n";
5957 std::cerr <<
" Preparing wire signal capacitance matrices failed.\n";
5961 if (!SetupPlaneSignals()) {
5962 std::cerr <<
m_className <<
"::PrepareSignals:\n";
5963 std::cerr <<
" Preparing plane charges failed.\n";
5973 const unsigned int nReadout = m_readout.size();
5974 for (
unsigned int i = 0; i < nReadout; ++i) {
5975 for (
auto& wire : m_w) {
5976 if (wire.type == m_readout[i]) wire.ind = i;
5978 for (
unsigned int j = 0; j < 5; ++j) {
5979 if (m_planes[j].type == m_readout[i]) m_planes[j].ind = i;
5980 for (
auto& strip : m_planes[j].strips1) {
5981 if (strip.type == m_readout[i]) strip.ind = i;
5983 for (
auto& strip : m_planes[j].strips2) {
5984 if (strip.type == m_readout[i]) strip.ind = i;
5986 for (
auto& pixel : m_planes[j].pixels) {
5987 if (pixel.type == m_readout[i]) pixel.ind = i;
5997bool ComponentAnalyticField::SetupWireSignals() {
6010 m_sigmat.assign(m_nWires, std::vector<std::complex<double> >(m_nWires));
6012 std::vector<std::vector<std::complex<double> > > fftmat;
6014 if (m_fperx || m_fpery) {
6015 fftmat.resize(m_nFourier);
6016 for (
int i = 0; i < m_nFourier; ++i) {
6017 fftmat[i].resize(m_nWires);
6021 if (m_fperx || m_fpery) {
6032 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6033 for (
int my = m_mymin; my <= m_mymax; ++my) {
6035 if (m_cellTypeFourier ==
A00) {
6037 }
else if (m_cellTypeFourier ==
B2X) {
6039 }
else if (m_cellTypeFourier ==
B2Y) {
6041 }
else if (m_cellTypeFourier ==
C2X) {
6043 }
else if (m_cellTypeFourier ==
C2Y) {
6045 }
else if (m_cellTypeFourier ==
C30) {
6047 }
else if (m_cellTypeFourier ==
D10) {
6049 }
else if (m_cellTypeFourier ==
D30) {
6052 std::cerr <<
m_className <<
"::SetupWireSignals:\n";
6053 std::cerr <<
" Unknown signal cell type " << m_cellTypeFourier
6058 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6059 std::cout <<
" Signal matrix MX = " << mx <<
", MY = " << my
6060 <<
" has been calculated.\n";
6062 if (m_fperx || m_fpery) {
6070 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6071 std::cout <<
" Dump of signal matrix (" << mx <<
", " << my
6072 <<
") before inversion:\n";
6073 for (
unsigned int i = 0; i < m_nWires; i += 10) {
6074 for (
unsigned int j = 0; j < m_nWires; j += 10) {
6075 std::cout <<
" (Re-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6076 for (
unsigned int ii = 0; ii < 10; ++ii) {
6077 if (i + ii >= m_nWires)
break;
6078 for (
unsigned int jj = 0; jj < 10; ++jj) {
6079 if (j + jj >= m_nWires)
break;
6080 std::cout << real(m_sigmat[i + ii][j + jj]) <<
" ";
6085 std::cout <<
" (Im-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6086 for (
unsigned int ii = 0; ii < 10; ++ii) {
6087 if (i + ii >= m_nWires)
break;
6088 for (
unsigned int jj = 0; jj < 10; ++jj) {
6089 if (j + jj >= m_nWires)
break;
6090 std::cout << imag(m_sigmat[i + ii][j + jj]) <<
" ";
6097 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6098 std::cout <<
" End of the uninverted capacitance matrix dump.\n";
6105 if (m_fperx != m_fpery) {
6106 for (
unsigned int i = 0; i < m_nWires; ++i) {
6107 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6110 for (
unsigned int j = 0; j < m_nWires; ++j) {
6111 fftmat[m + m_nFourier / 2][j] = m_sigmat[i][j];
6114 for (
unsigned int j = 0; j < m_nWires; ++j) {
6117 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6120 for (
unsigned int j = 0; j < m_nWires; ++j) {
6121 m_sigmat[i][j] = fftmat[m + m_nFourier / 2][j];
6129 if (m_fperx || m_fpery) {
6130 for (
unsigned int i = 0; i < m_nWires; ++i) {
6131 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6132 for (
int my = m_mymin; my <= m_mymax; ++my) {
6135 for (
unsigned int j = 0; j < m_nWires; ++j) {
6136 fftmat[my + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6139 for (
unsigned int j = 0; j < m_nWires; ++j) {
6142 for (
int my = m_mymin; my <= m_mymax; ++my) {
6145 for (
unsigned int j = 0; j < m_nWires; ++j) {
6146 m_sigmat[i][j] = fftmat[my + m_nFourier / 2 - 1][j];
6152 for (
int my = m_mymin; my <= m_mymax; ++my) {
6153 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6156 for (
unsigned int j = 0; j < m_nWires; ++j) {
6157 fftmat[mx + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6160 for (
unsigned int j = 0; j < m_nWires; ++j) {
6163 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6166 for (
unsigned int j = 0; j < m_nWires; ++j) {
6167 m_sigmat[i][j] = fftmat[mx + m_nFourier / 2 - 1][j];
6177 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6178 for (
int my = m_mymin; my <= m_mymax; ++my) {
6180 if (m_fperx || m_fpery) {
6185 if (m_nWires >= 1) {
6187 std::cerr <<
m_className <<
"::PrepareWireSignals:\n";
6188 std::cerr <<
" Inversion of signal matrix (" << mx <<
", " << my
6190 std::cerr <<
" No reliable results.\n";
6191 std::cerr <<
" Preparation of weighting fields is abandoned.\n";
6196 if (m_fperx || m_fpery) {
6205 if (m_fperx != m_fpery) {
6206 for (
unsigned int i = 0; i < m_nWires; ++i) {
6207 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6210 for (
unsigned int j = 0; j < m_nWires; ++j) {
6211 fftmat[m + m_nFourier / 2][j] = m_sigmat[i][j];
6214 for (
unsigned int j = 0; j < m_nWires; ++j) {
6217 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6220 for (
unsigned int j = 0; j < m_nWires; ++j) {
6221 m_sigmat[i][j] = fftmat[m + m_nFourier / 2][j] / double(m_nFourier);
6229 if (m_fperx && m_fpery) {
6230 for (
unsigned int i = 0; i < m_nWires; ++i) {
6231 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6232 for (
int my = m_mymin; my <= m_mymax; ++my) {
6235 for (
unsigned int j = 0; j < m_nWires; ++j) {
6236 fftmat[my + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6239 for (
unsigned int j = 0; j < m_nWires; ++j) {
6242 for (
int my = m_mymin; my <= m_mymax; ++my) {
6245 for (
unsigned int j = 0; j < m_nWires; ++j) {
6247 fftmat[my + m_nFourier / 2 - 1][j] / double(m_nFourier);
6253 for (
int my = m_mymin; my <= m_mymax; ++my) {
6254 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6257 for (
unsigned int j = 0; j < m_nWires; ++j) {
6258 fftmat[mx + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6261 for (
unsigned int j = 0; j < m_nWires; ++j) {
6264 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6267 for (
unsigned int j = 0; j < m_nWires; ++j) {
6269 fftmat[mx + m_nFourier / 2 - 1][j] / double(m_nFourier);
6280 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6281 for (
int my = m_mymin; my <= m_mymax; ++my) {
6282 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6283 std::cout <<
" Dump of signal matrix (" << mx <<
", " << my
6284 <<
") after inversion:\n";
6285 for (
unsigned int i = 0; i < m_nWires; i += 10) {
6286 for (
unsigned int j = 0; j < m_nWires; j += 10) {
6287 std::cout <<
" (Re-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6288 for (
unsigned int ii = 0; ii < 10; ++ii) {
6289 if (i + ii >= m_nWires)
break;
6290 for (
unsigned int jj = 0; jj < 10; ++jj) {
6291 if (j + jj >= m_nWires)
break;
6292 std::cout << real(m_sigmat[i + ii][j + jj]) <<
" ";
6297 std::cout <<
" (Im-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6298 for (
int ii = 0; ii < 10; ++ii) {
6299 if (i + ii >= m_nWires)
break;
6300 for (
int jj = 0; jj < 10; ++jj) {
6301 if (j + jj >= m_nWires)
break;
6302 std::cout << imag(m_sigmat[i + ii][j + jj]) <<
" ";
6309 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6310 std::cout <<
" End of the inverted capacitance matrix dump.\n";
6317bool ComponentAnalyticField::SetupPlaneSignals() {
6324 const int nPlanes = 5;
6325 m_qplane.assign(nPlanes, std::vector<double>(m_nWires, 0.));
6330 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6331 for (
int my = m_mymin; my <= m_mymax; ++my) {
6340 m_qplane.assign(nPlanes, std::vector<double>(m_nWires, 0.));
6344 for (
unsigned int i = 0; i < m_nWires; ++i) {
6346 vw = -(m_coplan[1] - m_w[i].x) / (m_coplan[1] - m_coplan[0]);
6347 }
else if (m_perx) {
6348 vw = -(m_coplan[0] + m_sx - m_w[i].x) / m_sx;
6353 for (
unsigned int j = 0; j < m_nWires; ++j) {
6354 m_qplane[0][j] += real(m_sigmat[i][j]) * vw;
6361 for (
unsigned int i = 0; i < m_nWires; ++i) {
6363 vw = -(m_coplan[0] - m_w[i].x) / (m_coplan[0] - m_coplan[1]);
6364 }
else if (m_perx) {
6365 vw = -(m_w[i].x - m_coplan[1] + m_sx) / m_sx;
6370 for (
unsigned int j = 0; j < m_nWires; ++j) {
6371 m_qplane[1][j] += real(m_sigmat[i][j]) * vw;
6378 for (
unsigned int i = 0; i < m_nWires; ++i) {
6380 vw = -(m_coplan[3] - m_w[i].y) / (m_coplan[3] - m_coplan[2]);
6381 }
else if (m_pery) {
6382 vw = -(m_coplan[2] + m_sy - m_w[i].y) / m_sy;
6387 for (
unsigned int j = 0; j < m_nWires; ++j) {
6388 m_qplane[2][i] += real(m_sigmat[i][j]) * vw;
6395 for (
unsigned int i = 0; i < m_nWires; ++i) {
6397 vw = -(m_coplan[2] - m_w[i].y) / (m_coplan[2] - m_coplan[3]);
6398 }
else if (m_pery) {
6399 vw = -(m_w[i].y - m_coplan[3] + m_sy) / m_sy;
6404 for (
unsigned int j = 0; j < m_nWires; ++j) {
6405 m_qplane[3][i] += real(m_sigmat[i][j]) * vw;
6411 for (
unsigned int i = 0; i < m_nWires; ++i) {
6412 for (
unsigned int j = 0; j < m_nWires; ++j) {
6413 m_qplane[4][i] -= real(m_sigmat[i][j]);
6428 if (m_ynplan[0] && m_ynplan[1]) {
6429 m_planes[0].ewxcor = 1. / (m_coplan[1] - m_coplan[0]);
6430 m_planes[1].ewxcor = 1. / (m_coplan[0] - m_coplan[1]);
6431 }
else if (m_ynplan[0] && m_perx) {
6432 m_planes[0].ewxcor = 1. / m_sx;
6433 m_planes[1].ewxcor = 0.;
6434 }
else if (m_ynplan[1] && m_perx) {
6435 m_planes[0].ewxcor = 0.;
6436 m_planes[1].ewxcor = -1. / m_sx;
6438 m_planes[0].ewxcor = m_planes[1].ewxcor = 0.;
6440 m_planes[2].ewxcor = m_planes[3].ewxcor = m_planes[4].ewxcor = 0.;
6442 m_planes[0].ewycor = m_planes[1].ewycor = 0.;
6443 if (m_ynplan[2] && m_ynplan[3]) {
6444 m_planes[2].ewycor = 1. / (m_coplan[3] - m_coplan[2]);
6445 m_planes[3].ewycor = 1. / (m_coplan[2] - m_coplan[3]);
6446 }
else if (m_ynplan[2] && m_pery) {
6447 m_planes[2].ewycor = 1. / m_sy;
6448 m_planes[3].ewycor = 0.;
6449 }
else if (m_ynplan[3] && m_pery) {
6450 m_planes[2].ewycor = 0.;
6451 m_planes[3].ewycor = -1. / m_sy;
6453 m_planes[2].ewycor = m_planes[3].ewycor = 0.;
6456 m_planes[4].ewycor = 0.;
6460 std::cout <<
m_className <<
"::SetupPlaneSignals:\n";
6461 std::cout <<
" Charges for currents induced in the planes:\n";
6462 std::cout <<
" Wire x-Plane 1 x-Plane 2"
6463 <<
" y-Plane 1 y-Plane 2"
6465 for (
unsigned int i = 0; i < m_nWires; ++i) {
6466 std::cout <<
" " << i <<
" " << m_qplane[0][i] <<
" "
6467 << m_qplane[1][i] <<
" " << m_qplane[2][i] <<
" "
6468 << m_qplane[3][i] <<
" " << m_qplane[4][i] <<
"\n";
6470 std::cout <<
m_className <<
"::SetupPlaneSignals:\n";
6471 std::cout <<
" Bias fields:\n";
6472 std::cout <<
" Plane x-Bias [1/cm] y-Bias [1/cm]\n";
6473 for (
int i = 0; i < 4; ++i) {
6474 std::cout <<
" " << i <<
" " << m_planes[i].ewxcor <<
" "
6475 << m_planes[i].ewycor <<
"\n";
6482bool ComponentAnalyticField::IprA00(
const int mx,
const int my) {
6488 const double dx = mx * m_sx;
6489 const double dy = my * m_sy;
6492 for (
unsigned int i = 0; i < m_nWires; ++i) {
6494 if (dx != 0. || dy != 0.) {
6495 aa = dx * dx + dy * dy;
6497 aa = m_w[i].r * m_w[i].r;
6500 if (m_ynplax) aa /= 2. *
pow(m_w[i].x - m_coplax, 2) + dy * dy;
6501 if (m_ynplay) aa /= 2. *
pow(m_w[i].y - m_coplay, 2) + dx * dx;
6503 if (m_ynplax && m_ynplay)
6504 aa *= 4. * (
pow(m_w[i].x - m_coplax, 2) +
pow(m_w[i].y - m_coplay, 2));
6506 m_sigmat[i][i] = -0.5 * log(aa);
6507 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6508 aa =
pow(m_w[i].x + dx - m_w[j].x, 2) +
pow(m_w[i].y + dy - m_w[j].y, 2);
6511 aa /=
pow(2. * m_coplax - m_w[i].x - dx - m_w[j].x, 2) +
6512 pow(m_w[i].y + dy - m_w[j].y, 2);
6514 aa /=
pow(m_w[i].x + dx - m_w[j].x, 2) +
6515 pow(2. * m_coplay - m_w[i].y - dy - m_w[j].y, 2);
6517 if (m_ynplax && m_ynplay) {
6518 aa *=
pow(2. * m_coplax - m_w[i].x - dx - m_w[j].x, 2) +
6519 pow(2. * m_coplay - m_w[i].y - dy - m_w[j].y, 2);
6522 m_sigmat[i][j] = -0.5 * log(aa);
6523 m_sigmat[j][i] = m_sigmat[i][j];
6529bool ComponentAnalyticField::IprB2X(
const int my) {
6536 m_b2sin.resize(m_nWires);
6538 const double dy = my * m_sy;
6543 for (
unsigned int i = 0; i < m_nWires; ++i) {
6544 double xx = (Pi / m_sx) * (m_w[i].x - m_coplan[0]);
6546 aa =
pow(sinh(Pi * dy / m_sx) /
sin(xx), 2);
6548 aa =
pow((0.5 * m_w[i].r * Pi / m_sx) /
sin(xx), 2);
6552 const double yymirr = (Pi / m_sx) * (m_w[i].y - m_coplay);
6553 if (
fabs(yymirr) <= 20.) {
6554 const double sinhy = sinh(yymirr);
6555 const double sinxx =
sin(xx);
6556 aa *= (sinhy * sinhy + sinxx * sinxx) / (sinhy * sinhy);
6560 m_sigmat[i][i] = -0.5 * log(aa);
6562 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6563 const double yy = HalfPi * (m_w[i].y + dy - m_w[j].y) / m_sx;
6564 xx = HalfPi * (m_w[i].x - m_w[j].x) / m_sx;
6565 xxneg = HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplan[0]) / m_sx;
6566 if (
fabs(yy) <= 20.) {
6567 const double sinhy = sinh(yy);
6568 const double sinxx =
sin(xx);
6569 const double sinxxneg =
sin(xxneg);
6570 aa = (sinhy * sinhy + sinxx * sinxx) /
6571 (sinhy * sinhy + sinxxneg * sinxxneg);
6577 const double yymirr =
6578 HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplay) / m_sx;
6579 if (
fabs(yymirr) <= 20.) {
6580 const double sinhy = sinh(yymirr);
6581 const double sinxx =
sin(xx);
6582 const double sinxxneg =
sin(xxneg);
6583 aa *= (sinhy * sinhy + sinxxneg * sinxxneg) /
6584 (sinhy * sinhy + sinxx * sinxx);
6588 m_sigmat[i][j] = -0.5 * log(aa);
6589 m_sigmat[j][i] = m_sigmat[i][j];
6592 m_b2sin[i] =
sin(Pi * (m_coplan[0] - m_w[i].x) / m_sx);
6598bool ComponentAnalyticField::IprB2Y(
const int mx) {
6605 m_b2sin.resize(m_nWires);
6607 const double dx = mx * m_sx;
6609 double xx, yy, xxmirr, yyneg;
6612 for (
unsigned int i = 0; i < m_nWires; ++i) {
6613 yy = (Pi / m_sy) * (m_w[i].y - m_coplan[2]);
6615 aa =
pow(sinh(Pi * dx / m_sy) /
sin(yy), 2);
6617 aa =
pow((0.5 * m_w[i].r * Pi / m_sy) /
sin(yy), 2);
6621 xxmirr = (Pi / m_sy) * (m_w[i].x - m_coplax);
6622 if (
fabs(xxmirr) <= 20.) {
6623 aa *= (
pow(sinh(xxmirr), 2) +
pow(
sin(yy), 2)) /
pow(sinh(xxmirr), 2);
6627 m_sigmat[i][i] = -0.5 * log(aa);
6629 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6630 xx = HalfPi * (m_w[i].x + dx - m_w[j].x) / m_sy;
6631 yy = HalfPi * (m_w[i].y - m_w[j].y) / m_sy;
6632 yyneg = HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplan[2]) / m_sy;
6633 if (
fabs(xx) <= 20.) {
6634 aa = (
pow(sinh(xx), 2) +
pow(
sin(yy), 2)) /
6635 (
pow(sinh(xx), 2) +
pow(
sin(yyneg), 2));
6641 xxmirr = HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplax) / m_sy;
6642 if (
fabs(xxmirr) <= 20.) {
6643 aa *= (
pow(sinh(xxmirr), 2) +
pow(
sin(yyneg), 2)) /
6644 (
pow(sinh(xxmirr), 2) +
pow(
sin(yy), 2));
6648 m_sigmat[i][j] = -0.5 * log(aa);
6649 m_sigmat[j][i] = m_sigmat[i][j];
6652 m_b2sin[i] =
sin(Pi * (m_coplan[2] - m_w[i].y) / m_sy);
6657bool ComponentAnalyticField::IprC2X() {
6668 for (
unsigned int i = 0; i < m_nWires; ++i) {
6669 double cx = m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
6670 for (
unsigned int j = 0; j < m_nWires; ++j) {
6673 temp = (m_w[i].x - cx) * (m_w[j].x - cx) * TwoPi / (m_sx * m_sy);
6677 Ph2Lim(m_w[i].r) - Ph2(2. * (m_w[j].x - cx), 0.) - temp;
6680 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
6681 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) - temp;
6688bool ComponentAnalyticField::IprC2Y() {
6699 for (
unsigned int i = 0; i < m_nWires; ++i) {
6701 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
6702 for (
unsigned int j = 0; j < m_nWires; ++j) {
6705 temp = (m_w[i].y - cy) * (m_w[j].y - cy) * TwoPi / (m_sx * m_sy);
6709 Ph2Lim(m_w[i].r) - Ph2(0., 2. * (m_w[j].y - cy)) - temp;
6712 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
6713 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) - temp;
6720bool ComponentAnalyticField::IprC30() {
6730 for (
unsigned int i = 0; i < m_nWires; ++i) {
6732 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
6734 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
6735 for (
unsigned int j = 0; j < m_nWires; ++j) {
6737 m_sigmat[i][i] = Ph2Lim(m_w[i].r) -
6738 Ph2(0., 2. * (m_w[i].y - cy)) -
6739 Ph2(2. * (m_w[i].x - cx), 0.) +
6740 Ph2(2. * (m_w[i].x - cx), 2. * (m_w[i].y - cy));
6743 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
6744 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) -
6745 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) +
6746 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y + m_w[j].y - 2. * cy);
6753bool ComponentAnalyticField::IprD10() {
6761 for (
unsigned int i = 0; i < m_nWires; ++i) {
6763 m_sigmat[i][i] = -log(
6765 (m_cotube - (m_w[i].x * m_w[i].x + m_w[i].y * m_w[i].y) / m_cotube));
6767 std::complex<double> zi(m_w[i].x, m_w[i].y);
6769 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6771 std::complex<double> zj(m_w[j].x, m_w[j].y);
6772 m_sigmat[i][j] = -log(
6773 abs((1. / m_cotube) * (zi - zj) / (1. - conj(zi) * zj / m_cotube2)));
6775 m_sigmat[j][i] = m_sigmat[i][j];
6781bool ComponentAnalyticField::IprD30() {
6788 wmap.resize(m_nWires);
6790 std::complex<double> wd;
6793 for (
int i = 0; i < int(m_nWires); ++i) {
6795 ConformalMap(std::complex<double>(m_w[i].x, m_w[i].y) / m_cotube, wmap[i],
6798 m_sigmat[i][i] = -log(
6799 abs((m_w[i].r / m_cotube) * wd / (1. -
pow(abs(wmap[i]), 2))));
6801 for (
int j = 0; j < i - 1; ++j) {
6803 -log(abs((wmap[i] - wmap[j]) / (1. - conj(wmap[i]) * wmap[j])));
6805 m_sigmat[j][i] = m_sigmat[i][j];
6811bool ComponentAnalyticField::Wfield(
const double xin,
const double yin,
6812 const double zpos,
double& exsum,
6813 double& eysum,
double& ezsum,
6814 const std::string& label)
const {
6821 exsum = eysum = ezsum = 0.;
6822 double ex = 0., ey = 0., ez = 0.;
6824 double xpos = xin, ypos = yin;
6825 if (m_polar) Cartesian2Internal(xin, yin, xpos, ypos);
6827 if (m_readout.empty())
return false;
6829 std::cerr <<
m_className <<
"::Wfield: No weighting fields available.\n";
6835 if (!InTube(xpos, ypos, m_cotube, m_ntube))
return false;
6838 if ((m_ynplan[0] && xpos < m_coplan[0]) ||
6839 (m_ynplan[1] && xpos > m_coplan[1])) {
6844 if ((m_ynplan[2] && ypos < m_coplan[2]) ||
6845 (m_ynplan[3] && ypos > m_coplan[3])) {
6851 if (label.empty())
return false;
6852 const auto it = std::find(m_readout.cbegin(), m_readout.cend(), label);
6853 if (it == m_readout.end())
return false;
6854 const auto isw = it - m_readout.begin();
6857 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6858 for (
int my = m_mymin; my <= m_mymax; ++my) {
6869 for (
size_t iw = 0; iw < m_nWires; ++iw) {
6871 if (m_w[iw].ind != isw)
continue;
6873 if (m_cellTypeFourier ==
A00) {
6874 WfieldWireA00(xpos, ypos, ex, ey, mx, my, iw);
6875 }
else if (m_cellTypeFourier ==
B2X) {
6876 WfieldWireB2X(xpos, ypos, ex, ey, my, iw);
6877 }
else if (m_cellTypeFourier ==
B2Y) {
6878 WfieldWireB2Y(xpos, ypos, ex, ey, mx, iw);
6879 }
else if (m_cellTypeFourier ==
C2X) {
6880 WfieldWireC2X(xpos, ypos, ex, ey, iw);
6881 }
else if (m_cellTypeFourier ==
C2Y) {
6882 WfieldWireC2Y(xpos, ypos, ex, ey, iw);
6883 }
else if (m_cellTypeFourier ==
C30) {
6884 WfieldWireC30(xpos, ypos, ex, ey, iw);
6885 }
else if (m_cellTypeFourier ==
D10) {
6886 WfieldWireD10(xpos, ypos, ex, ey, iw);
6887 }
else if (m_cellTypeFourier ==
D30) {
6888 WfieldWireD30(xpos, ypos, ex, ey, iw);
6891 std::cerr <<
" Unknown signal field type " << m_cellTypeFourier
6892 <<
" received. Program error!\n";
6893 std::cerr <<
" Encountered for wire " << iw
6894 <<
", readout group = " << m_w[iw].ind <<
"\n";
6895 exsum = eysum = ezsum = 0.;
6912 for (
int ip = 0; ip < 5; ++ip) {
6914 if (m_planes[ip].ind != isw)
continue;
6916 if (m_cellTypeFourier ==
A00) {
6917 WfieldPlaneA00(xpos, ypos, ex, ey, mx, my, ip);
6918 }
else if (m_cellTypeFourier ==
B2X) {
6919 WfieldPlaneB2X(xpos, ypos, ex, ey, my, ip);
6920 }
else if (m_cellTypeFourier ==
B2Y) {
6921 WfieldPlaneB2Y(xpos, ypos, ex, ey, mx, ip);
6922 }
else if (m_cellTypeFourier ==
C2X) {
6923 WfieldPlaneC2X(xpos, ypos, ex, ey, ip);
6924 }
else if (m_cellTypeFourier ==
C2Y) {
6925 WfieldPlaneC2Y(xpos, ypos, ex, ey, ip);
6926 }
else if (m_cellTypeFourier ==
C30) {
6927 WfieldPlaneC30(xpos, ypos, ex, ey, ip);
6928 }
else if (m_cellTypeFourier ==
D10) {
6929 WfieldPlaneD10(xpos, ypos, ex, ey, ip);
6930 }
else if (m_cellTypeFourier ==
D30) {
6931 WfieldPlaneD30(xpos, ypos, ex, ey, ip);
6934 std::cerr <<
" Unkown field type " << m_cellTypeFourier
6935 <<
" received. Program error!\n";
6936 std::cerr <<
" Encountered for plane " << ip
6937 <<
", readout group = " << m_planes[ip].ind <<
"\n";
6938 exsum = eysum = ezsum = 0.;
6949 for (
int ip = 0; ip < 5; ++ip) {
6950 if (m_planes[ip].ind != isw)
continue;
6951 exsum += m_planes[ip].ewxcor;
6952 eysum += m_planes[ip].ewycor;
6956 for (
unsigned int ip = 0; ip < 5; ++ip) {
6957 for (
const auto& strip : m_planes[ip].strips1) {
6958 if (strip.ind != isw)
continue;
6959 WfieldStripXy(xpos, ypos, zpos, ex, ey, ez, ip, strip);
6964 for (
const auto& strip : m_planes[ip].strips2) {
6965 if (strip.ind != isw)
continue;
6966 WfieldStripZ(xpos, ypos, ex, ey, ip, strip);
6970 for (
const auto& pixel : m_planes[ip].pixels) {
6971 if (pixel.ind != isw)
continue;
6972 WfieldPixel(xpos, ypos, zpos, ex, ey, ez, ip, pixel);
6979 const double r =
exp(xpos);
6980 const double er = exsum / r;
6981 const double ep = eysum / r;
6982 const double theta = atan2(yin, xin);
6983 const double ct =
cos(theta);
6984 const double st =
sin(theta);
6985 exsum = +ct * er -
st * ep;
6986 eysum = +
st * er + ct * ep;
6991double ComponentAnalyticField::Wpot(
const double xin,
const double yin,
6993 const std::string& label)
const {
6996 double xpos = xin, ypos = yin;
6997 if (m_polar) Cartesian2Internal(xin, yin, xpos, ypos);
6999 if (m_readout.empty())
return 0.;
7001 std::cerr <<
m_className <<
"::Wpot: No weighting potentials available.\n";
7007 if (!InTube(xpos, ypos, m_cotube, m_ntube))
return 0.;
7010 if ((m_ynplan[0] && xpos < m_coplan[0]) ||
7011 (m_ynplan[1] && xpos > m_coplan[1])) {
7016 if ((m_ynplan[2] && ypos < m_coplan[2]) ||
7017 (m_ynplan[3] && ypos > m_coplan[3])) {
7022 if (label.empty())
return 0.;
7023 const auto it = std::find(m_readout.cbegin(), m_readout.cend(), label);
7024 if (it == m_readout.end())
return 0.;
7025 const auto isw = it - m_readout.begin();
7028 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
7029 for (
int my = m_mymin; my <= m_mymax; ++my) {
7031 for (
int iw = m_nWires; iw--;) {
7033 if (m_w[iw].ind != isw)
continue;
7034 if (m_cellTypeFourier ==
A00) {
7035 vsum += WpotWireA00(xpos, ypos, mx, my, iw);
7036 }
else if (m_cellTypeFourier ==
B2X) {
7037 vsum += WpotWireB2X(xpos, ypos, my, iw);
7038 }
else if (m_cellTypeFourier ==
B2Y) {
7039 vsum += WpotWireB2Y(xpos, ypos, mx, iw);
7040 }
else if (m_cellTypeFourier ==
C2X) {
7041 vsum += WpotWireC2X(xpos, ypos, iw);
7042 }
else if (m_cellTypeFourier ==
C2Y) {
7043 vsum += WpotWireC2Y(xpos, ypos, iw);
7044 }
else if (m_cellTypeFourier ==
C30) {
7045 vsum += WpotWireC30(xpos, ypos, iw);
7046 }
else if (m_cellTypeFourier ==
D10) {
7047 vsum += WpotWireD10(xpos, ypos, iw);
7048 }
else if (m_cellTypeFourier ==
D30) {
7049 vsum += WpotWireD30(xpos, ypos, iw);
7052 std::cerr <<
" Unknown signal field type " << m_cellTypeFourier
7053 <<
" received. Program error!\n";
7054 std::cerr <<
" Encountered for wire " << iw
7055 <<
", readout group = " << m_w[iw].ind <<
"\n";
7060 for (
int ip = 0; ip < 5; ++ip) {
7062 if (m_planes[ip].ind != isw)
continue;
7063 if (m_cellTypeFourier ==
A00) {
7064 vsum += WpotPlaneA00(xpos, ypos, mx, my, ip);
7065 }
else if (m_cellTypeFourier ==
B2X) {
7066 vsum += WpotPlaneB2X(xpos, ypos, my, ip);
7067 }
else if (m_cellTypeFourier ==
B2Y) {
7068 vsum += WpotPlaneB2Y(xpos, ypos, mx, ip);
7069 }
else if (m_cellTypeFourier ==
C2X) {
7070 vsum += WpotPlaneC2X(xpos, ypos, ip);
7071 }
else if (m_cellTypeFourier ==
C2Y) {
7072 vsum += WpotPlaneC2Y(xpos, ypos, ip);
7073 }
else if (m_cellTypeFourier ==
C30) {
7074 vsum += WpotPlaneC30(xpos, ypos, ip);
7075 }
else if (m_cellTypeFourier ==
D10) {
7076 vsum += WpotPlaneD10(xpos, ypos, ip);
7077 }
else if (m_cellTypeFourier ==
D30) {
7078 vsum += WpotPlaneD30(xpos, ypos, ip);
7081 std::cerr <<
" Unkown field type " << m_cellTypeFourier
7082 <<
" received. Program error!\n";
7083 std::cerr <<
" Encountered for plane " << ip
7084 <<
", readout group = " << m_planes[ip].ind <<
"\n";
7092 for (
int ip = 0; ip < 5; ++ip) {
7093 if (m_planes[ip].ind != isw)
continue;
7094 if (ip == 0 || ip == 1) {
7097 xx -= m_sx * int(round(xpos / m_sx));
7098 if (m_ynplan[0] && xx <= m_coplan[0]) xx += m_sx;
7099 if (m_ynplan[1] && xx >= m_coplan[1]) xx -= m_sx;
7101 vsum += 1. - m_planes[ip].ewxcor * (xx - m_coplan[ip]);
7102 }
else if (ip == 2 || ip == 3) {
7105 yy -= m_sy * int(round(ypos / m_sy));
7106 if (m_ynplan[2] && yy <= m_coplan[2]) yy += m_sy;
7107 if (m_ynplan[3] && yy >= m_coplan[3]) yy -= m_sy;
7109 vsum += 1. - m_planes[ip].ewycor * (yy - m_coplan[ip]);
7114 for (
unsigned int ip = 0; ip < 5; ++ip) {
7115 for (
const auto& strip : m_planes[ip].strips1) {
7116 if (strip.ind != isw)
continue;
7117 vsum += WpotStripXy(xpos, ypos, zpos, ip, strip);
7119 for (
const auto& strip : m_planes[ip].strips2) {
7120 if (strip.ind != isw)
continue;
7121 vsum += WpotStripZ(xpos, ypos, ip, strip);
7123 for (
const auto& pixel : m_planes[ip].pixels) {
7124 if (pixel.ind != isw)
continue;
7125 vsum += WpotPixel(xpos, ypos, zpos, ip, pixel);
7131void ComponentAnalyticField::WfieldWireA00(
const double xpos,
const double ypos,
7132 double& ex,
double& ey,
7133 const int mx,
const int my,
7134 const int isw)
const {
7148 for (
unsigned int i = 0; i < m_nWires; ++i) {
7150 const double xx = xpos - m_w[i].x - mx * m_sx;
7151 const double yy = ypos - m_w[i].y - my * m_sy;
7153 const double r2 = xx * xx + yy * yy;
7154 if (r2 <= 0.)
continue;
7155 const double s2 = 1. / r2;
7156 double exhelp = xx * s2;
7157 double eyhelp = yy * s2;
7159 const double xxmirr = m_ynplax ? xpos + m_w[i].x - 2. * m_coplax : 0.;
7161 const double r2plan = xxmirr * xxmirr + yy * yy;
7162 if (r2plan <= 0.)
continue;
7163 const double s2plan = 1. / r2plan;
7164 exhelp -= xxmirr * s2plan;
7165 eyhelp -= yy * s2plan;
7168 const double yymirr = m_ynplay ? ypos + m_w[i].y - 2. * m_coplay : 0.;
7170 const double r2plan = xx * xx + yymirr * yymirr;
7171 if (r2plan <= 0.)
continue;
7172 const double s2plan = 1. / r2plan;
7173 exhelp -= xx * s2plan;
7174 eyhelp -= yymirr * s2plan;
7177 if (m_ynplax && m_ynplay) {
7178 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
7179 if (r2plan <= 0.)
continue;
7180 const double s2plan = 1. / r2plan;
7181 exhelp += xxmirr * s2plan;
7182 eyhelp += yymirr * s2plan;
7185 const double qw = real(m_sigmat[isw][i]);
7191double ComponentAnalyticField::WpotWireA00(
const double xpos,
const double ypos,
7192 const int mx,
const int my,
7193 const int isw)
const {
7197 for (
unsigned int i = 0; i < m_nWires; ++i) {
7199 const double xx = xpos - m_w[i].x - mx * m_sx;
7200 const double yy = ypos - m_w[i].y - my * m_sy;
7202 double r2 = xx * xx + yy * yy;
7203 if (r2 <= 0.)
continue;
7205 const double xxmirr = m_ynplax ? xpos + m_w[i].x - 2. * m_coplax : 0.;
7207 const double r2plan = xxmirr * xxmirr + yy * yy;
7208 if (r2plan <= 0.)
continue;
7212 const double yymirr = m_ynplay ? ypos + m_w[i].y - 2. * m_coplay : 0.;
7214 const double r2plan = xx * xx + yymirr * yymirr;
7215 if (r2plan <= 0.)
continue;
7219 if (m_ynplax && m_ynplay) {
7220 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
7221 if (r2plan <= 0.)
continue;
7225 volt -= real(m_sigmat[isw][i]) * log(r2);
7230void ComponentAnalyticField::WfieldWireB2X(
const double xpos,
const double ypos,
7231 double& ex,
double& ey,
7232 const int my,
const int isw)
const {
7243 const double tx = HalfPi / m_sx;
7245 for (
unsigned int i = 0; i < m_nWires; ++i) {
7246 const double xx = tx * (xpos - m_w[i].x);
7247 const double yy = tx * (ypos - m_w[i].y - my * m_sy);
7248 const double xxneg = tx * (xpos + m_w[i].x - 2 * m_coplan[0]);
7250 std::complex<double> ecompl(0., 0.);
7251 if (
fabs(yy) <= 20.) {
7252 const std::complex<double> zz(xx, yy);
7253 const std::complex<double> zzneg(xxneg, yy);
7254 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
7258 const double yymirr = tx * (ypos + m_w[i].y - 2. * m_coplay);
7259 if (
fabs(yymirr) <= 20.) {
7260 const std::complex<double> zzmirr(xx, yymirr);
7261 const std::complex<double> zznmirr(xxneg, yymirr);
7262 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
7266 const double qw = real(m_sigmat[isw][i]);
7267 ex += qw * real(ecompl);
7268 ey -= qw * imag(ecompl);
7274double ComponentAnalyticField::WpotWireB2X(
const double xpos,
const double ypos,
7275 const int my,
const int isw)
const {
7277 const double tx = HalfPi / m_sx;
7279 for (
unsigned int i = 0; i < m_nWires; ++i) {
7280 const double xx = tx * (xpos - m_w[i].x);
7281 const double yy = tx * (ypos - m_w[i].y - my * m_sy);
7282 const double xxneg = tx * (xpos + m_w[i].x - 2 * m_coplan[0]);
7285 if (
fabs(yy) <= 20.) {
7286 const double sinhy = sinh(yy);
7287 const double sinxx =
sin(xx);
7288 const double sinxxneg =
sin(xxneg);
7289 r2 = (sinhy * sinhy + sinxx * sinxx) /
7290 (sinhy * sinhy + sinxxneg * sinxxneg);
7294 const double yymirr = tx * (ypos + m_w[i].y - 2. * m_coplay);
7295 if (
fabs(yymirr) <= 20.) {
7296 const double sinhy = sinh(yymirr);
7297 const double sinxx =
sin(xx);
7298 const double sinxxneg =
sin(xxneg);
7299 const double r2plan = (sinhy * sinhy + sinxx * sinxx) /
7300 (sinhy * sinhy + sinxxneg * sinxxneg);
7305 volt -= real(m_sigmat[isw][i]) * log(r2);
7310void ComponentAnalyticField::WfieldWireB2Y(
const double xpos,
const double ypos,
7311 double& ex,
double& ey,
7312 const int mx,
const int isw)
const {
7322 constexpr std::complex<double> icons(0., 1.);
7324 const double ty = HalfPi / m_sy;
7326 for (
unsigned int i = 0; i < m_nWires; ++i) {
7327 const double xx = ty * (xpos - m_w[i].x - mx * m_sx);
7328 const double yy = ty * (ypos - m_w[i].y);
7329 const double yyneg = ty * (ypos + m_w[i].y - 2. * m_coplan[2]);
7331 std::complex<double> ecompl(0., 0.);
7332 if (
fabs(xx) <= 20.) {
7333 const std::complex<double> zz(xx, yy);
7334 const std::complex<double> zzneg(xx, yyneg);
7335 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
7339 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
7340 if (
fabs(xxmirr) <= 20.) {
7341 const std::complex<double> zzmirr(xxmirr, yy);
7342 const std::complex<double> zznmirr(xxmirr, yyneg);
7344 icons * m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
7348 const double qw = real(m_sigmat[isw][i]);
7349 ex += qw * real(ecompl);
7350 ey -= qw * imag(ecompl);
7356double ComponentAnalyticField::WpotWireB2Y(
const double xpos,
const double ypos,
7357 const int mx,
const int isw)
const {
7359 const double ty = HalfPi / m_sy;
7361 for (
unsigned int i = 0; i < m_nWires; ++i) {
7362 const double xx = ty * (xpos - m_w[i].x - mx * m_sx);
7363 const double yy = ty * (ypos - m_w[i].y);
7364 const double yyneg = ty * (ypos + m_w[i].y - 2. * m_coplan[2]);
7367 if (
fabs(xx) <= 20.) {
7368 const double sinhx = sinh(xx);
7369 const double sinyy =
sin(yy);
7370 const double sinyyneg =
sin(yyneg);
7371 r2 = (sinhx * sinhx + sinyy * sinyy) /
7372 (sinhx * sinhx + sinyyneg * sinyyneg);
7376 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
7377 if (
fabs(xxmirr) <= 20.) {
7378 const double sinhx = sinh(xxmirr);
7379 const double sinyy =
sin(yy);
7380 const double sinyyneg =
sin(yyneg);
7381 const double r2plan = (sinhx * sinhx + sinyy * sinyy) /
7382 (sinhx * sinhx + sinyyneg * sinyyneg);
7386 volt -= real(m_sigmat[isw][i]) * log(r2);
7391void ComponentAnalyticField::WfieldWireC2X(
const double xpos,
const double ypos,
7392 double& ex,
double& ey,
7393 const int isw)
const {
7401 constexpr std::complex<double> icons(0., 1.);
7403 std::complex<double> wsum1 = 0.;
7404 std::complex<double> wsum2 = 0.;
7407 for (
unsigned int i = 0; i < m_nWires; ++i) {
7408 const double qw = real(m_sigmat[isw][i]);
7409 const double xx = xpos - m_w[i].x;
7410 const double yy = ypos - m_w[i].y;
7412 auto zeta = m_zmult * std::complex<double>(xx, yy);
7413 if (imag(zeta) > 15.) {
7414 wsum1 -= qw * icons;
7415 }
else if (imag(zeta) < -15.) {
7416 wsum1 += qw * icons;
7418 const auto zterm = Th1(zeta, m_p1, m_p2);
7419 wsum1 += qw * (zterm.second / zterm.first);
7423 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
7425 s += qw * (m_w[i].x - cx);
7427 zeta = m_zmult * std::complex<double>(2. * cx - xpos - m_w[i].x, yy);
7428 if (imag(zeta) > +15.) {
7429 wsum2 -= qw * icons;
7430 }
else if (imag(zeta) < -15.) {
7431 wsum2 += qw * icons;
7433 const auto zterm = Th1(zeta, m_p1, m_p2);
7434 wsum2 += qw * (zterm.second / zterm.first);
7438 ex = real(m_zmult * (wsum1 + wsum2));
7439 ey = -imag(m_zmult * (wsum1 - wsum2));
7441 if (m_mode == 0) ex += s * TwoPi / (m_sx * m_sy);
7444double ComponentAnalyticField::WpotWireC2X(
const double xpos,
const double ypos,
7445 const int isw)
const {
7448 for (
unsigned int i = 0; i < m_nWires; ++i) {
7449 const double xx = xpos - m_w[i].x;
7450 const double yy = ypos - m_w[i].y;
7451 const double qw = real(m_sigmat[isw][i]);
7453 auto zeta = m_zmult * std::complex<double>(xx, yy);
7454 if (
fabs(imag(zeta)) > 15.) {
7455 volt -= qw * (
fabs(imag(zeta)) - CLog2);
7457 const auto zterm = Th1(zeta, m_p1, m_p2);
7458 volt -= qw * log(abs(zterm.first));
7462 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
7464 zeta = m_zmult * std::complex<double>(2. * cx - xpos - m_w[i].x, yy);
7465 if (
fabs(imag(zeta)) > 15.) {
7466 volt += qw * (
fabs(imag(zeta)) - CLog2);
7468 const auto zterm = Th1(zeta, m_p1, m_p2);
7469 volt += qw * log(abs(zterm.first));
7473 volt -= TwoPi * qw * (xpos - cx) * (m_w[i].x - cx) / (m_sx * m_sy);
7479void ComponentAnalyticField::WfieldWireC2Y(
const double xpos,
const double ypos,
7480 double& ex,
double& ey,
7481 const int isw)
const {
7489 constexpr std::complex<double> icons(0., 1.);
7491 std::complex<double> wsum1 = 0.;
7492 std::complex<double> wsum2 = 0.;
7495 for (
unsigned int i = 0; i < m_nWires; ++i) {
7496 const double qw = real(m_sigmat[isw][i]);
7497 const double xx = xpos - m_w[i].x;
7498 const double yy = ypos - m_w[i].y;
7500 auto zeta = m_zmult * std::complex<double>(xx, yy);
7501 if (imag(zeta) > +15.) {
7502 wsum1 -= qw * icons;
7503 }
else if (imag(zeta) < -15.) {
7504 wsum1 += qw * icons;
7506 const auto zterm = Th1(zeta, m_p1, m_p2);
7507 wsum1 += qw * (zterm.second / zterm.first);
7510 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
7512 s += qw * (m_w[i].y - cy);
7514 zeta = m_zmult * std::complex<double>(xx, 2. * cy - ypos - m_w[i].y);
7515 if (imag(zeta) > +15.) {
7516 wsum2 -= qw * icons;
7517 }
else if (imag(zeta) < -15.) {
7518 wsum2 += qw * icons;
7520 const auto zterm = Th1(zeta, m_p1, m_p2);
7521 wsum2 += qw * (zterm.second / zterm.first);
7525 ex = real(m_zmult * (wsum1 - wsum2));
7526 ey = -imag(m_zmult * (wsum1 + wsum2));
7528 if (m_mode == 1) ey += s * TwoPi / (m_sx * m_sy);
7531double ComponentAnalyticField::WpotWireC2Y(
const double xpos,
const double ypos,
7532 const int isw)
const {
7536 for (
unsigned int i = 0; i < m_nWires; ++i) {
7537 const double qw = real(m_sigmat[isw][i]);
7538 const double xx = xpos - m_w[i].x;
7539 const double yy = ypos - m_w[i].y;
7541 auto zeta = m_zmult * std::complex<double>(xx, yy);
7542 if (
fabs(imag(zeta)) > 15.) {
7543 volt -= qw * (
fabs(imag(zeta)) - CLog2);
7545 const auto zterm = Th1(zeta, m_p1, m_p2);
7546 volt -= qw * log(abs(zterm.first));
7549 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
7551 zeta = m_zmult * std::complex<double>(xx, 2. * cy - ypos - m_w[i].y);
7552 if (
fabs(imag(zeta)) > 15.) {
7553 volt += qw * (
fabs(imag(zeta)) - CLog2);
7555 const auto zterm = Th1(zeta, m_p1, m_p2);
7556 volt += qw * log(abs(zterm.first));
7560 volt -= TwoPi * qw * (ypos - cy) * (m_w[i].y - cy) / (m_sx * m_sy);
7566void ComponentAnalyticField::WfieldWireC30(
const double xpos,
const double ypos,
7567 double& ex,
double& ey,
7568 const int isw)
const {
7576 constexpr std::complex<double> icons(0., 1.);
7578 std::complex<double> wsum1 = 0.;
7579 std::complex<double> wsum2 = 0.;
7580 std::complex<double> wsum3 = 0.;
7581 std::complex<double> wsum4 = 0.;
7583 for (
unsigned int i = 0; i < m_nWires; ++i) {
7584 const double qw = real(m_sigmat[isw][i]);
7585 const double xx = xpos - m_w[i].x;
7586 const double yy = ypos - m_w[i].y;
7588 auto zeta = m_zmult * std::complex<double>(xx, yy);
7589 if (imag(zeta) > +15.) {
7590 wsum1 -= qw * icons;
7591 }
else if (imag(zeta) < -15.) {
7592 wsum1 += qw * icons;
7594 const auto zterm = Th1(zeta, m_p1, m_p2);
7595 wsum1 += qw * (zterm.second / zterm.first);
7598 const double xxmirr = MirrorCoordinate(xpos, m_coplax, m_w[i].x, m_sx);
7599 zeta = m_zmult * std::complex<double>(xxmirr, yy);
7600 if (imag(zeta) > +15.) {
7601 wsum2 -= qw * icons;
7602 }
else if (imag(zeta) < -15.) {
7603 wsum2 += qw * icons;
7605 const auto zterm = Th1(zeta, m_p1, m_p2);
7606 wsum2 += qw * (zterm.second / zterm.first);
7609 const double yymirr = MirrorCoordinate(ypos, m_coplay, m_w[i].y, m_sy);
7610 zeta = m_zmult * std::complex<double>(xx, yymirr);
7611 if (imag(zeta) > +15.) {
7612 wsum3 -= qw * icons;
7613 }
else if (imag(zeta) < -15.) {
7614 wsum3 += qw * icons;
7616 const auto zterm = Th1(zeta, m_p1, m_p2);
7617 wsum3 += qw * (zterm.second / zterm.first);
7620 zeta = m_zmult * std::complex<double>(xxmirr, yymirr);
7621 if (imag(zeta) > +15.) {
7622 wsum4 -= qw * icons;
7623 }
else if (imag(zeta) < -15.) {
7624 wsum4 += qw * icons;
7626 const auto zterm = Th1(zeta, m_p1, m_p2);
7627 wsum4 += qw * (zterm.second / zterm.first);
7631 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
7632 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
7635double ComponentAnalyticField::WpotWireC30(
const double xpos,
const double ypos,
7636 const int isw)
const {
7639 for (
unsigned int i = 0; i < m_nWires; ++i) {
7640 const double qw = real(m_sigmat[isw][i]);
7641 const double xx = xpos - m_w[i].x;
7642 const double yy = ypos - m_w[i].y;
7644 auto zeta = m_zmult * std::complex<double>(xx, yy);
7645 if (
fabs(imag(zeta)) > 15.) {
7646 volt -= qw * (
fabs(imag(zeta)) - CLog2);
7648 const auto zterm = Th1(zeta, m_p1, m_p2);
7649 volt -= qw * log(abs(zterm.first));
7652 const double xxmirr = MirrorCoordinate(xpos, m_coplax, m_w[i].x, m_sx);
7653 zeta = m_zmult * std::complex<double>(xxmirr, yy);
7654 if (
fabs(imag(zeta)) > 15.) {
7655 volt += qw * (
fabs(imag(zeta)) - CLog2);
7657 const auto zterm = Th1(zeta, m_p1, m_p2);
7658 volt += qw * log(abs(zterm.first));
7661 const double yymirr = MirrorCoordinate(ypos, m_coplay, m_w[i].y, m_sy);
7662 zeta = m_zmult * std::complex<double>(xx, yymirr);
7663 if (
fabs(imag(zeta)) > 15.) {
7664 volt += qw * (
fabs(imag(zeta)) - CLog2);
7666 const auto zterm = Th1(zeta, m_p1, m_p2);
7667 volt += qw * log(abs(zterm.first));
7670 zeta = m_zmult * std::complex<double>(xxmirr, yymirr);
7671 if (
fabs(imag(zeta)) > 15.) {
7672 volt -= qw * (
fabs(imag(zeta)) - CLog2);
7674 const auto zterm = Th1(zeta, m_p1, m_p2);
7675 volt -= qw * log(abs(zterm.first));
7681void ComponentAnalyticField::WfieldWireD10(
const double xpos,
const double ypos,
7682 double& ex,
double& ey,
7683 const int isw)
const {
7696 const std::complex<double> zpos(xpos, ypos);
7698 for (
unsigned int i = 0; i < m_nWires; ++i) {
7700 const std::complex<double> zi(m_w[i].x, m_w[i].y);
7702 const auto wi = 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
7703 const double qw = real(m_sigmat[isw][i]);
7704 ex += qw * real(wi);
7705 ey += qw * imag(wi);
7709double ComponentAnalyticField::WpotWireD10(
const double xpos,
const double ypos,
7710 const int isw)
const {
7713 const std::complex<double> zpos(xpos, ypos);
7715 for (
unsigned int i = 0; i < m_nWires; ++i) {
7717 const std::complex<double> zi(m_w[i].x, m_w[i].y);
7718 volt -= real(m_sigmat[isw][i]) *
7719 log(abs(m_cotube * (zpos - zi) / (m_cotube2 - zpos * conj(zi))));
7724void ComponentAnalyticField::WfieldWireD30(
const double xpos,
const double ypos,
7725 double& ex,
double& ey,
7726 const int isw)
const {
7738 std::complex<double> wpos, wdpos;
7739 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
7741 for (
unsigned int i = 0; i < m_nWires; ++i) {
7743 const auto whelp = wdpos * (1. -
pow(abs(wmap[i]), 2)) /
7744 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
7745 const double qw = real(m_sigmat[isw][i]);
7746 ex += qw * real(whelp);
7747 ey -= qw * imag(whelp);
7753double ComponentAnalyticField::WpotWireD30(
const double xpos,
const double ypos,
7754 const int isw)
const {
7757 std::complex<double> wpos, wdpos;
7758 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
7760 for (
unsigned int i = 0; i < m_nWires; ++i) {
7762 volt -= real(m_sigmat[isw][i]) *
7763 log(abs((wpos - wmap[i]) / (1. - wpos * conj(wmap[i]))));
7768void ComponentAnalyticField::WfieldPlaneA00(
7769 const double xpos,
const double ypos,
double& ex,
double& ey,
7770 const int mx,
const int my,
const int ip)
const {
7782 for (
unsigned int i = 0; i < m_nWires; ++i) {
7784 const double xx = xpos - m_w[i].x - mx * m_sx;
7785 const double yy = ypos - m_w[i].y - my * m_sy;
7787 const double r2 = xx * xx + yy * yy;
7788 if (r2 <= 0.)
continue;
7789 const double s2 = 1. / r2;
7790 double exhelp = xx * s2;
7791 double eyhelp = yy * s2;
7793 const double xxmirr = m_ynplax ? xpos + m_w[i].x - 2 * m_coplax : 0.;
7795 const double r2plan = xxmirr * xxmirr + yy * yy;
7796 if (r2plan <= 0.)
continue;
7797 const double s2plan = 1. / r2plan;
7798 exhelp -= xxmirr * s2plan;
7799 eyhelp -= yy * s2plan;
7802 const double yymirr = m_ynplay ? ypos + m_w[i].y - 2 * m_coplay : 0.;
7804 const double r2plan = xx * xx + yymirr * yymirr;
7805 if (r2plan <= 0.)
continue;
7806 const double s2plan = 1. / r2plan;
7807 exhelp -= xx * s2plan;
7808 eyhelp -= yymirr * s2plan;
7811 if (m_ynplax && m_ynplay) {
7812 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
7813 if (r2plan <= 0.)
continue;
7814 const double s2plan = 1. / r2plan;
7815 exhelp += xxmirr * s2plan;
7816 eyhelp += yymirr * s2plan;
7818 ex += m_qplane[ip][i] * exhelp;
7819 ey += m_qplane[ip][i] * eyhelp;
7823double ComponentAnalyticField::WpotPlaneA00(
7824 const double xpos,
const double ypos,
7825 const int mx,
const int my,
const int ip)
const {
7829 for (
unsigned int i = 0; i < m_nWires; ++i) {
7831 const double xx = xpos - m_w[i].x - mx * m_sx;
7832 const double yy = ypos - m_w[i].y - my * m_sy;
7834 double r2 = xx * xx + yy * yy;
7835 if (r2 <= 0.)
continue;
7837 const double xxmirr = m_ynplax ? xpos + m_w[i].x - 2 * m_coplax : 0.;
7839 const double r2plan = xxmirr * xxmirr + yy * yy;
7840 if (r2plan <= 0.)
continue;
7844 const double yymirr = m_ynplay ? ypos + m_w[i].y - 2 * m_coplay : 0.;
7846 const double r2plan = xx * xx + yymirr * yymirr;
7847 if (r2plan <= 0.)
continue;
7851 if (m_ynplax && m_ynplay) {
7852 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
7853 if (r2plan <= 0.)
continue;
7857 volt -= m_qplane[ip][i] * log(r2);
7862void ComponentAnalyticField::WfieldPlaneB2X(
const double xpos,
7864 double& ex,
double& ey,
7866 const int ip)
const {
7877 const double tx = HalfPi / m_sx;
7879 for (
unsigned int i = 0; i < m_nWires; ++i) {
7880 const double xx = tx * (xpos - m_w[i].x);
7881 const double yy = tx * (ypos - m_w[i].y - my * m_sy);
7882 const double xxneg = tx * (xpos + m_w[i].x - 2 * m_coplan[0]);
7884 std::complex<double> ecompl(0., 0.);
7885 if (
fabs(yy) <= 20.) {
7886 const std::complex<double> zz(xx, yy);
7887 const std::complex<double> zzneg(xxneg, yy);
7888 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
7892 const double yymirr = tx * (ypos + m_w[i].y - 2 * m_coplay);
7893 if (
fabs(yymirr) <= 20.) {
7894 const std::complex<double> zzmirr(yy, yymirr);
7895 const std::complex<double> zznmirr(xxneg, yymirr);
7896 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
7900 ex += m_qplane[ip][i] * real(ecompl);
7901 ey -= m_qplane[ip][i] * imag(ecompl);
7907double ComponentAnalyticField::WpotPlaneB2X(
const double xpos,
7909 const int my,
const int ip)
const {
7912 const double tx = HalfPi / m_sx;
7914 for (
unsigned int i = 0; i < m_nWires; ++i) {
7915 const double xx = tx * (xpos - m_w[i].x);
7916 const double yy = tx * (ypos - m_w[i].y - my * m_sy);
7917 const double xxneg = tx * (xpos + m_w[i].x - 2 * m_coplan[0]);
7920 if (
fabs(yy) <= 20.) {
7921 const double sinhy = sinh(yy);
7922 const double sinxx =
sin(xx);
7923 const double sinxxneg =
sin(xxneg);
7924 r2 = (sinhy * sinhy + sinxx * sinxx) /
7925 (sinhy * sinhy + sinxxneg * sinxxneg);
7929 const double yymirr = tx * (ypos + m_w[i].y - 2 * m_coplay);
7930 if (
fabs(yymirr) <= 20.) {
7931 const double sinhy = sinh(yymirr);
7932 const double sinxx =
sin(xx);
7933 const double sinxxneg =
sin(xxneg);
7934 const double r2plan = (sinhy * sinhy + sinxx * sinxx) /
7935 (sinhy * sinhy + sinxxneg * sinxxneg);
7939 volt -= m_qplane[ip][i] * log(r2);
7944void ComponentAnalyticField::WfieldPlaneB2Y(
const double xpos,
7946 double& ex,
double& ey,
7948 const int ip)
const {
7958 constexpr std::complex<double> icons(0., 1.);
7960 const double ty = HalfPi / m_sy;
7962 for (
unsigned int i = 0; i < m_nWires; ++i) {
7963 const double xx = ty * (xpos - m_w[i].x - mx * m_sx);
7964 const double yy = ty * (ypos - m_w[i].y);
7965 const double yyneg = ty * (ypos + m_w[i].y - 2 * m_coplan[2]);
7967 std::complex<double> ecompl(0., 0.);
7968 if (
fabs(xx) <= 20.) {
7969 const std::complex<double> zz(xx, yy);
7970 const std::complex<double> zzneg(xx, yyneg);
7971 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
7975 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
7976 if (
fabs(xxmirr) <= 20.) {
7977 const std::complex<double> zzmirr(xxmirr, yy);
7978 const std::complex<double> zznmirr(xxmirr, yyneg);
7979 ecompl -= m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
7982 ex += m_qplane[ip][i] * real(ecompl);
7983 ey -= m_qplane[ip][i] * imag(ecompl);
7989double ComponentAnalyticField::WpotPlaneB2Y(
const double xpos,
7991 const int mx,
const int ip)
const {
7993 const double ty = HalfPi / m_sy;
7995 for (
unsigned int i = 0; i < m_nWires; ++i) {
7996 const double xx = ty * (xpos - m_w[i].x - mx * m_sx);
7997 const double yy = ty * (ypos - m_w[i].y);
7998 const double yyneg = ty * (ypos + m_w[i].y - 2 * m_coplan[2]);
8001 if (
fabs(xx) <= 20.) {
8002 const double sinhx = sinh(xx);
8003 const double sinyy =
sin(yy);
8004 const double sinyyneg =
sin(yyneg);
8005 r2 = (sinhx * sinhx + sinyy * sinyy) /
8006 (sinhx * sinhx + sinyyneg * sinyyneg);
8010 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
8011 if (
fabs(xxmirr) <= 20.) {
8012 const double sinhx = sinh(xxmirr);
8013 const double sinyy =
sin(yy);
8014 const double sinyyneg =
sin(yyneg);
8015 const double r2plan = (sinhx * sinhx + sinyy * sinyy) /
8016 (sinhx * sinhx + sinyyneg * sinyyneg);
8020 volt -= m_qplane[ip][i] * log(r2);
8025void ComponentAnalyticField::WfieldPlaneC2X(
const double xpos,
8027 double& ex,
double& ey,
8028 const int ip)
const {
8036 constexpr std::complex<double> icons(0., 1.);
8038 std::complex<double> wsum1 = 0.;
8039 std::complex<double> wsum2 = 0.;
8042 for (
unsigned int i = 0; i < m_nWires; ++i) {
8043 const double xx = xpos - m_w[i].x;
8044 const double yy = ypos - m_w[i].y;
8046 auto zeta = m_zmult * std::complex<double>(xx, yy);
8047 if (imag(zeta) > +15.) {
8048 wsum1 -= m_qplane[ip][i] * icons;
8049 }
else if (imag(zeta) < -15.) {
8050 wsum1 += m_qplane[ip][i] * icons;
8052 const auto zterm = Th1(zeta, m_p1, m_p2);
8053 wsum1 += m_qplane[ip][i] * (zterm.second / zterm.first);
8057 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
8059 s += m_qplane[ip][i] * (m_w[i].x - cx);
8061 zeta = m_zmult * std::complex<double>(2. * cx - xpos - m_w[i].x, yy);
8062 if (imag(zeta) > 15.) {
8063 wsum2 -= m_qplane[ip][i] * icons;
8064 }
else if (imag(zeta) < -15.) {
8065 wsum2 += m_qplane[ip][i] * icons;
8067 const auto zterm = Th1(zeta, m_p1, m_p2);
8068 wsum2 += m_qplane[ip][i] * (zterm.second / zterm.first);
8072 ex = real(m_zmult * (wsum1 + wsum2));
8073 ey = -imag(m_zmult * (wsum1 - wsum2));
8075 if (m_mode == 0) ex += s * TwoPi / (m_sx * m_sy);
8078double ComponentAnalyticField::WpotPlaneC2X(
const double xpos,
8080 const int ip)
const {
8082 const double c0 = m_mode == 0 ? TwoPi / (m_sx * m_sy) : 0.;
8084 for (
unsigned int i = 0; i < m_nWires; ++i) {
8085 const double xx = xpos - m_w[i].x;
8086 const double yy = ypos - m_w[i].y;
8088 auto zeta = m_zmult * std::complex<double>(xx, yy);
8089 if (
fabs(imag(zeta)) > 15.) {
8090 volt -= m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8092 const auto zterm = Th1(zeta, m_p1, m_p2);
8093 volt -= m_qplane[ip][i] * log(abs(zterm.first));
8097 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
8099 zeta = m_zmult * std::complex<double>(2. * cx - xpos - m_w[i].x, yy);
8100 if (
fabs(imag(zeta)) > 15.) {
8101 volt += m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8103 const auto zterm = Th1(zeta, m_p1, m_p2);
8104 volt += m_qplane[ip][i] * log(abs(zterm.first));
8107 volt -= c0 * m_qplane[ip][i] * (xpos - cx) * (m_w[i].x - cx);
8113void ComponentAnalyticField::WfieldPlaneC2Y(
const double xpos,
8115 double& ex,
double& ey,
8116 const int ip)
const {
8124 constexpr std::complex<double> icons(0., 1.);
8126 std::complex<double> wsum1 = 0.;
8127 std::complex<double> wsum2 = 0.;
8130 for (
unsigned int i = 0; i < m_nWires; ++i) {
8131 const double xx = xpos - m_w[i].x;
8132 const double yy = ypos - m_w[i].y;
8134 auto zeta = m_zmult * std::complex<double>(xx, yy);
8135 if (imag(zeta) > +15.) {
8136 wsum1 -= m_qplane[ip][i] * icons;
8137 }
else if (imag(zeta) < -15.) {
8138 wsum1 += m_qplane[ip][i] * icons;
8140 const auto zterm = Th1(zeta, m_p1, m_p2);
8141 wsum1 += m_qplane[ip][i] * (zterm.second / zterm.first);
8144 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
8146 s += m_qplane[ip][i] * (m_w[i].y - cy);
8148 zeta = m_zmult * std::complex<double>(xx, 2. * cy - ypos - m_w[i].y);
8149 if (imag(zeta) > 15.) {
8150 wsum2 -= m_qplane[ip][i] * icons;
8151 }
else if (imag(zeta) < -15.) {
8152 wsum2 += m_qplane[ip][i] * icons;
8154 const auto zterm = Th1(zeta, m_p1, m_p2);
8155 wsum2 += m_qplane[ip][i] * (zterm.second / zterm.first);
8159 ex = real(m_zmult * (wsum1 - wsum2));
8160 ey = -imag(m_zmult * (wsum1 + wsum2));
8162 if (m_mode == 1) ey += s * TwoPi / (m_sx * m_sy);
8165double ComponentAnalyticField::WpotPlaneC2Y(
const double xpos,
8167 const int ip)
const {
8169 const double c1 = m_mode == 1 ? TwoPi / (m_sx * m_sy) : 0.;
8171 for (
unsigned int i = 0; i < m_nWires; ++i) {
8172 const double xx = xpos - m_w[i].x;
8173 const double yy = ypos - m_w[i].y;
8175 auto zeta = m_zmult * std::complex<double>(xx, yy);
8176 if (
fabs(imag(zeta)) > 15.) {
8177 volt -= m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8179 const auto zterm = Th1(zeta, m_p1, m_p2);
8180 volt -= m_qplane[ip][i] * log(abs(zterm.first));
8183 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
8185 zeta = m_zmult * std::complex<double>(xx, 2. * cy - ypos - m_w[i].y);
8186 if (
fabs(imag(zeta)) > 15.) {
8187 volt += m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8189 const auto zterm = Th1(zeta, m_p1, m_p2);
8190 volt += m_qplane[ip][i] * log(abs(zterm.first));
8194 volt -= c1 * m_qplane[ip][i] * (ypos - cy) * (m_w[i].y - cy);
8200void ComponentAnalyticField::WfieldPlaneC30(
const double xpos,
8202 double& ex,
double& ey,
8203 const int ip)
const {
8211 constexpr std::complex<double> icons(0., 1.);
8213 std::complex<double> wsum1 = 0.;
8214 std::complex<double> wsum2 = 0.;
8215 std::complex<double> wsum3 = 0.;
8216 std::complex<double> wsum4 = 0.;
8218 for (
unsigned int i = 0; i < m_nWires; ++i) {
8219 const double xx = xpos - m_w[i].x;
8220 const double yy = ypos - m_w[i].y;
8222 auto zeta = m_zmult * std::complex<double>(xx, yy);
8223 if (imag(zeta) > +15.) {
8224 wsum1 -= m_qplane[ip][i] * icons;
8225 }
else if (imag(zeta) < -15.) {
8226 wsum1 += m_qplane[ip][i] * icons;
8228 const auto zterm = Th1(zeta, m_p1, m_p2);
8229 wsum1 += m_qplane[ip][i] * zterm.second / zterm.first;
8232 const double xxmirr = MirrorCoordinate(xpos, m_coplax, m_w[i].x, m_sx);
8233 zeta = m_zmult * std::complex<double>(xxmirr, yy);
8234 if (imag(zeta) > 15.) {
8235 wsum2 -= m_qplane[ip][i] * icons;
8236 }
else if (imag(zeta) < -15.) {
8237 wsum2 += m_qplane[ip][i] * icons;
8239 const auto zterm = Th1(zeta, m_p1, m_p2);
8240 wsum2 += m_qplane[ip][i] * zterm.second / zterm.first;
8243 const double yymirr = MirrorCoordinate(ypos, m_coplay, m_w[i].y, m_sy);
8244 zeta = m_zmult * std::complex<double>(xx, yymirr);
8245 if (imag(zeta) > 15.) {
8246 wsum3 -= m_qplane[ip][i] * icons;
8247 }
else if (imag(zeta) < -15.) {
8248 wsum3 += m_qplane[ip][i] * icons;
8250 const auto zterm = Th1(zeta, m_p1, m_p2);
8251 wsum3 += m_qplane[ip][i] * zterm.second / zterm.first;
8254 zeta = m_zmult * std::complex<double>(xxmirr, yymirr);
8255 if (imag(zeta) > 15.) {
8256 wsum4 -= m_qplane[ip][i] * icons;
8257 }
else if (imag(zeta) < -15.) {
8258 wsum4 += m_qplane[ip][i] * icons;
8260 const auto zterm = Th1(zeta, m_p1, m_p2);
8261 wsum4 += m_qplane[ip][i] * zterm.second / zterm.first;
8264 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
8265 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
8268double ComponentAnalyticField::WpotPlaneC30(
const double xpos,
8270 const int ip)
const {
8273 for (
unsigned int i = 0; i < m_nWires; ++i) {
8274 const double xx = xpos - m_w[i].x;
8275 const double yy = ypos - m_w[i].y;
8277 auto zeta = m_zmult * std::complex<double>(xx, yy);
8278 if (
fabs(imag(zeta)) > 15.) {
8279 volt -= m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8281 const auto zterm = Th1(zeta, m_p1, m_p2);
8282 volt -= m_qplane[ip][i] * log(abs(zterm.first));
8285 const double xxmirr = MirrorCoordinate(xpos, m_coplax, m_w[i].x, m_sx);
8286 zeta = m_zmult * std::complex<double>(xxmirr, yy);
8287 if (
fabs(imag(zeta)) > 15.) {
8288 volt += m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8290 const auto zterm = Th1(zeta, m_p1, m_p2);
8291 volt += m_qplane[ip][i] * log(abs(zterm.first));
8294 const double yymirr = MirrorCoordinate(ypos, m_coplay, m_w[i].y, m_sy);
8295 zeta = m_zmult * std::complex<double>(xx, yymirr);
8296 if (
fabs(imag(zeta)) > 15.) {
8297 volt += m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8299 const auto zterm = Th1(zeta, m_p1, m_p2);
8300 volt += m_qplane[ip][i] * log(abs(zterm.first));
8303 zeta = m_zmult * std::complex<double>(xxmirr, yymirr);
8304 if (
fabs(imag(zeta)) > 15.) {
8305 volt -= m_qplane[ip][i] * (
fabs(imag(zeta)) - CLog2);
8307 const auto zterm = Th1(zeta, m_p1, m_p2);
8308 volt -= m_qplane[ip][i] * log(abs(zterm.first));
8314void ComponentAnalyticField::WfieldPlaneD10(
const double xpos,
8316 double& ex,
double& ey,
8317 const int ip)
const {
8329 const std::complex<double> zpos(xpos, ypos);
8331 for (
unsigned int i = 0; i < m_nWires; ++i) {
8333 const std::complex<double> zi(m_w[i].x, m_w[i].y);
8335 const auto wi = 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
8336 ex += m_qplane[ip][i] * real(wi);
8337 ey += m_qplane[ip][i] * imag(wi);
8341double ComponentAnalyticField::WpotPlaneD10(
const double xpos,
8343 const int ip)
const {
8346 const std::complex<double> zpos(xpos, ypos);
8348 for (
unsigned int i = 0; i < m_nWires; ++i) {
8350 const std::complex<double> zi(m_w[i].x, m_w[i].y);
8351 volt -= m_qplane[ip][i] *
8352 log(abs(m_cotube * (zpos - zi) / (m_cotube2 - zpos * conj(zi))));
8357void ComponentAnalyticField::WfieldPlaneD30(
const double xpos,
8359 double& ex,
double& ey,
8360 const int ip)
const {
8371 std::complex<double> wpos, wdpos;
8372 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
8374 for (
unsigned int i = 0; i < m_nWires; ++i) {
8376 const auto whelp = wdpos * (1. -
pow(abs(wmap[i]), 2)) /
8377 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
8378 ex += m_qplane[ip][i] * real(whelp);
8379 ey -= m_qplane[ip][i] * imag(whelp);
8385double ComponentAnalyticField::WpotPlaneD30(
const double xpos,
8387 const int ip)
const {
8390 std::complex<double> wpos, wdpos;
8391 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
8393 for (
unsigned int i = 0; i < m_nWires; ++i) {
8394 volt -= m_qplane[ip][i] *
8395 log(abs((wpos - wmap[i]) / (1. - wpos * conj(wmap[i]))));
8400void ComponentAnalyticField::WfieldStripZ(
8401 const double xpos,
const double ypos,
double& ex,
double& ey,
8402 const int ip,
const Strip& strip)
const {
8412 double xw = 0., yw = 0.;
8415 xw = -ypos + 0.5 * (strip.smin + strip.smax);
8416 yw = xpos - m_coplan[ip];
8419 xw = ypos - 0.5 * (strip.smin + strip.smax);
8420 yw = m_coplan[ip] - xpos;
8423 xw = xpos - 0.5 * (strip.smin + strip.smax);
8424 yw = ypos - m_coplan[ip];
8427 xw = -xpos + 0.5 * (strip.smin + strip.smax);
8428 yw = m_coplan[ip] - ypos;
8435 if (yw <= 0. || yw > strip.gap)
return;
8438 const double invg = 1. / strip.gap;
8439 const double s =
sin(Pi * yw * invg);
8440 const double c =
cos(Pi * yw * invg);
8442 const double w = 0.5 *
fabs(strip.smax - strip.smin);
8443 const double e1 =
exp(Pi * (w - xw) * invg);
8444 const double e2 =
exp(-Pi * (w + xw) * invg);
8446 if (c == e1 || c == e2)
return;
8448 const double s2 = s * s;
8449 const double d1 = c - e1;
8450 const double d2 = c - e2;
8451 const double t1 = 1. / (s2 + d1 * d1);
8452 const double t2 = 1. / (s2 + d2 * d2);
8453 const double fx = s * (e1 * t1 - e2 * t2) * invg;
8454 const double fy = ((1. - c * e2) * t2 - (1. - c * e1) * t1) * invg;
8477double ComponentAnalyticField::WpotStripZ(
8478 const double xpos,
const double ypos,
8479 const int ip,
const Strip& strip)
const {
8482 double xw = 0., yw = 0.;
8485 xw = -ypos + 0.5 * (strip.smin + strip.smax);
8486 yw = xpos - m_coplan[ip];
8489 xw = ypos - 0.5 * (strip.smin + strip.smax);
8490 yw = m_coplan[ip] - xpos;
8493 xw = xpos - 0.5 * (strip.smin + strip.smax);
8494 yw = ypos - m_coplan[ip];
8497 xw = -xpos + 0.5 * (strip.smin + strip.smax);
8498 yw = m_coplan[ip] - ypos;
8505 if (yw <= 0. || yw > strip.gap)
return 0.;
8508 const double a = Pi / strip.gap;
8509 const double c =
cos(a * yw);
8511 const double w = 0.5 *
fabs(strip.smax - strip.smin);
8512 const double e1 =
exp(a * (w - xw));
8513 const double e2 =
exp(-a * (w + xw));
8515 if (c == e1 || c == e2)
return 0.;
8516 const double invs = 1. /
sin(a * yw);
8517 constexpr double invPi = 1. / Pi;
8518 return (atan((c - e2) * invs) - atan((c - e1) * invs)) * invPi;
8521void ComponentAnalyticField::WfieldStripXy(
const double xpos,
const double ypos,
8522 const double zpos,
double& ex,
8523 double& ey,
double& ez,
8525 const Strip& strip)
const {
8535 double xw = 0., yw = 0.;
8538 xw = -zpos + 0.5 * (strip.smin + strip.smax);
8539 yw = xpos - m_coplan[ip];
8542 xw = zpos - 0.5 * (strip.smin + strip.smax);
8543 yw = m_coplan[ip] - xpos;
8546 xw = zpos - 0.5 * (strip.smin + strip.smax);
8547 yw = ypos - m_coplan[ip];
8550 xw = -zpos + 0.5 * (strip.smin + strip.smax);
8551 yw = m_coplan[ip] - ypos;
8558 if (yw <= 0. || yw > strip.gap)
return;
8561 const double invg = 1. / strip.gap;
8562 const double s =
sin(Pi * yw * invg);
8563 const double c =
cos(Pi * yw * invg);
8565 const double w = 0.5 *
fabs(strip.smax - strip.smin);
8566 const double e1 =
exp(Pi * (w - xw) * invg);
8567 const double e2 =
exp(-Pi * (w + xw) * invg);
8569 if (c == e1 || c == e2)
return;
8571 const double s2 = s * s;
8572 const double d1 = c - e1;
8573 const double d2 = c - e2;
8574 const double t1 = 1. / (s2 + d1 * d1);
8575 const double t2 = 1. / (s2 + d2 * d2);
8576 const double fx = s * (e1 * t1 - e2 * t2) * invg;
8577 const double fy = ((1. - c * e2) * t2 - (1. - c * e1) * t1) * invg;
8604double ComponentAnalyticField::WpotStripXy(
const double xpos,
const double ypos,
8606 const int ip,
const Strip& strip)
const {
8608 double xw = 0., yw = 0.;
8611 xw = -zpos + 0.5 * (strip.smin + strip.smax);
8612 yw = xpos - m_coplan[ip];
8615 xw = zpos - 0.5 * (strip.smin + strip.smax);
8616 yw = m_coplan[ip] - xpos;
8619 xw = zpos - 0.5 * (strip.smin + strip.smax);
8620 yw = ypos - m_coplan[ip];
8623 xw = -zpos + 0.5 * (strip.smin + strip.smax);
8624 yw = m_coplan[ip] - ypos;
8631 if (yw <= 0. || yw > strip.gap)
return 0.;
8634 const double a = Pi / strip.gap;
8635 const double c =
cos(a * yw);
8637 const double w = 0.5 *
fabs(strip.smax - strip.smin);
8638 const double e1 =
exp(a * (w - xw));
8639 const double e2 =
exp(-a * (w + xw));
8641 if (c == e1 || c == e2)
return 0.;
8642 const double invs = 1. /
sin(a * yw);
8643 constexpr double invPi = 1. / Pi;
8644 return (atan((c - e2) * invs) - atan((c - e1) * invs)) * invPi;
8647void ComponentAnalyticField::WfieldPixel(
const double xpos,
const double ypos,
8649 double& ex,
double& ey,
double& ez,
8651 const Pixel& pixel)
const {
8665 double x = 0.,
y = 0.,
z = 0.;
8668 const double ps = 0.5 * (pixel.smin + pixel.smax);
8669 const double pz = 0.5 * (pixel.zmin + pixel.zmax);
8670 const double wx = pixel.smax - pixel.smin;
8671 const double wy = pixel.zmax - pixel.zmin;
8676 z = xpos - m_coplan[ip];
8681 z = -xpos + m_coplan[ip];
8686 z = ypos - m_coplan[ip];
8691 z = -ypos + m_coplan[ip];
8697 const bool rot =
fabs(pixel.sphi) > 1.e-9;
8699 const double xx =
x;
8700 const double yy =
y;
8701 x = pixel.cphi * xx + pixel.sphi * yy;
8702 y = -pixel.sphi * xx + pixel.cphi * yy;
8711 const double x1 =
x - 0.5 *
wx;
8712 const double x2 =
x + 0.5 *
wx;
8713 const double y1 =
y - 0.5 *
wy;
8714 const double y2 =
y + 0.5 *
wy;
8715 const double x1s = x1 * x1;
8716 const double x2s = x2 * x2;
8717 const double y1s = y1 * y1;
8718 const double y2s = y2 * y2;
8721 const double maxError = 1.e-5;
8722 const double d = pixel.gap;
8723 const double d3 = d * d * d;
8724 const unsigned int nz = std::ceil(
sqrt(wx * wy / (8 * Pi * d3 * maxError)));
8725 const unsigned int nx = std::ceil(
sqrt(wy * z / (4 * Pi * d3 * maxError)));
8726 const unsigned int ny = std::ceil(
sqrt(wx * z / (4 * Pi * d3 * maxError)));
8727 const unsigned int nn = std::max(ny, std::max(nx, nz));
8728 for (
unsigned int i = 1; i <= nn; ++i) {
8729 const double u1 = 2 * i * d -
z;
8730 const double u2 = 2 * i * d +
z;
8731 const double u1s = u1 * u1;
8732 const double u2s = u2 * u2;
8733 const double u1x1y1 =
sqrt(x1s + y1s + u1s);
8734 const double u1x1y2 =
sqrt(x1s + y2s + u1s);
8735 const double u1x2y1 =
sqrt(x2s + y1s + u1s);
8736 const double u1x2y2 =
sqrt(x2s + y2s + u1s);
8737 const double u2x1y1 =
sqrt(x1s + y1s + u2s);
8738 const double u2x1y2 =
sqrt(x1s + y2s + u2s);
8739 const double u2x2y1 =
sqrt(x2s + y1s + u2s);
8740 const double u2x2y2 =
sqrt(x2s + y2s + u2s);
8744 ex -= u1 * y1 / ((u1s + x2s) * u1x2y1) -
8745 u1 * y1 / ((u1s + x1s) * u1x1y1) +
8746 u1 * y2 / ((u1s + x1s) * u1x1y2) - u1 * y2 / ((u1s + x2s) * u1x2y2);
8749 ex += u2 * y1 / ((u2s + x2s) * u2x2y1) -
8750 u2 * y1 / ((u2s + x1s) * u2x1y1) +
8751 u2 * y2 / ((u2s + x1s) * u2x1y2) - u2 * y2 / ((u2s + x2s) * u2x2y2);
8755 ey -= u1 * x1 / ((u1s + y2s) * u1x1y2) -
8756 u1 * x1 / ((u1s + y1s) * u1x1y1) +
8757 u1 * x2 / ((u1s + y1s) * u1x2y1) - u1 * x2 / ((u1s + y2s) * u1x2y2);
8760 ey += u2 * x1 / ((u2s + y2s) * u2x1y2) -
8761 u2 * x1 / ((u2s + y1s) * u2x1y1) +
8762 u2 * x2 / ((u2s + y1s) * u2x2y1) - u2 * x2 / ((u2s + y2s) * u2x2y2);
8766 ez += x1 * y1 * (x1s + y1s + 2 * u1s) /
8767 ((x1s + u1s) * (y1s + u1s) * u1x1y1) +
8768 x2 * y2 * (x2s + y2s + 2 * u1s) /
8769 ((x2s + u1s) * (y2s + u1s) * u1x2y2) -
8770 x1 * y2 * (x1s + y2s + 2 * u1s) /
8771 ((x1s + u1s) * (y2s + u1s) * u1x1y2) -
8772 x2 * y1 * (x2s + y1s + 2 * u1s) /
8773 ((x2s + u1s) * (y1s + u1s) * u1x2y1);
8776 ez += x1 * y1 * (x1s + y1s + 2 * u2s) /
8777 ((x1s + u2s) * (y1s + u2s) * u2x1y1) +
8778 x2 * y2 * (x2s + y2s + 2 * u2s) /
8779 ((x2s + u2s) * (y2s + u2s) * u2x2y2) -
8780 x1 * y2 * (x1s + y2s + 2 * u2s) /
8781 ((x1s + u2s) * (y2s + u2s) * u2x1y2) -
8782 x2 * y1 * (x2s + y1s + 2 * u2s) /
8783 ((x2s + u2s) * (y1s + u2s) * u2x2y1);
8787 const double zs =
z *
z;
8788 const double x1y1 =
sqrt(x1s + y1s + zs);
8789 const double x1y2 =
sqrt(x1s + y2s + zs);
8790 const double x2y1 =
sqrt(x2s + y1s + zs);
8791 const double x2y2 =
sqrt(x2s + y2s + zs);
8793 ex +=
z * y1 / ((zs + x2s) * x2y1) -
z * y1 / ((zs + x1s) * x1y1) +
8794 z * y2 / ((zs + x1s) * x1y2) -
z * y2 / ((zs + x2s) * x2y2);
8797 ey +=
z * x1 / ((zs + y2s) * x1y2) -
z * x1 / ((zs + y1s) * x1y1) +
8798 z * x2 / ((zs + y1s) * x2y1) -
z * x2 / ((zs + y2s) * x2y2);
8801 ez += x1 * y1 * (x1s + y1s + 2 * zs) / ((x1s + zs) * (y1s + zs) * x1y1) +
8802 x2 * y2 * (x2s + y2s + 2 * zs) / ((x2s + zs) * (y2s + zs) * x2y2) -
8803 x1 * y2 * (x1s + y2s + 2 * zs) / ((x1s + zs) * (y2s + zs) * x1y2) -
8804 x2 * y1 * (x2s + y1s + 2 * zs) / ((x2s + zs) * (y1s + zs) * x2y1);
8806 constexpr double invTwoPi = 1. / TwoPi;
8812 const double fx = rot ? pixel.cphi * ex - pixel.sphi * ey : ex;
8813 const double fy = rot ? pixel.sphi * ex + pixel.cphi * ey : ey;
8814 const double fz = ez;
8839double ComponentAnalyticField::WpotPixel(
const double xpos,
const double ypos,
8841 const int ip,
const Pixel& pixel)
const {
8843 double x = 0.,
y = 0.,
z = 0.;
8846 const double ps = 0.5 * (pixel.smin + pixel.smax);
8847 const double pz = 0.5 * (pixel.zmin + pixel.zmax);
8848 const double wx = pixel.smax - pixel.smin;
8849 const double wy = pixel.zmax - pixel.zmin;
8854 z = xpos - m_coplan[ip];
8859 z = -xpos + m_coplan[ip];
8864 z = ypos - m_coplan[ip];
8869 z = -ypos + m_coplan[ip];
8875 if (
fabs(pixel.sphi) > 1.e-9) {
8876 const double xx =
x;
8877 const double yy =
y;
8878 x = pixel.cphi * xx + pixel.sphi * yy;
8879 y = -pixel.sphi * xx + pixel.cphi * yy;
8883 const double x1 =
x - 0.5 *
wx;
8884 const double x2 =
x + 0.5 *
wx;
8885 const double y1 =
y - 0.5 *
wy;
8886 const double y2 =
y + 0.5 *
wy;
8887 const double x1s = x1 * x1;
8888 const double x2s = x2 * x2;
8889 const double y1s = y1 * y1;
8890 const double y2s = y2 * y2;
8893 const double maxError = 1.e-5;
8894 const double d = pixel.gap;
8895 const double d3 = d * d * d;
8896 const unsigned int nn = std::ceil(
sqrt(wx * wy * z / (8 * Pi * d3 * maxError)));
8898 for (
unsigned int i = 1; i <= nn; ++i) {
8899 const double u1 = 2 * i * d -
z;
8900 const double u2 = 2 * i * d +
z;
8901 const double u1s = u1 * u1;
8902 const double u2s = u2 * u2;
8903 const double u1x1y1 =
sqrt(x1s + y1s + u1s);
8904 const double u1x1y2 =
sqrt(x1s + y2s + u1s);
8905 const double u1x2y1 =
sqrt(x2s + y1s + u1s);
8906 const double u1x2y2 =
sqrt(x2s + y2s + u1s);
8907 const double u2x1y1 =
sqrt(x1s + y1s + u2s);
8908 const double u2x1y2 =
sqrt(x1s + y2s + u2s);
8909 const double u2x2y1 =
sqrt(x2s + y1s + u2s);
8910 const double u2x2y2 =
sqrt(x2s + y2s + u2s);
8912 volt -= atan(x1 * y1 / (u1 * u1x1y1)) + atan(x2 * y2 / (u1 * u1x2y2)) -
8913 atan(x1 * y2 / (u1 * u1x1y2)) - atan(x2 * y1 / (u1 * u1x2y1));
8914 volt += atan(x1 * y1 / (u2 * u2x1y1)) + atan(x2 * y2 / (u2 * u2x2y2)) -
8915 atan(x1 * y2 / (u2 * u2x1y2)) - atan(x2 * y1 / (u2 * u2x2y1));
8918 const double zs =
z *
z;
8919 const double x1y1 =
sqrt(x1s + y1s + zs);
8920 const double x1y2 =
sqrt(x1s + y2s + zs);
8921 const double x2y1 =
sqrt(x2s + y1s + zs);
8922 const double x2y2 =
sqrt(x2s + y2s + zs);
8924 volt += atan(x1 * y1 / (z * x1y1)) + atan(x2 * y2 / (z * x2y2)) -
8925 atan(x1 * y2 / (z * x1y2)) - atan(x2 * y1 / (z * x2y1));
8926 constexpr double invTwoPi = 1. / TwoPi;
8927 return volt * invTwoPi;
8930void ComponentAnalyticField::FieldAtWireA00(
8931 const double xpos,
const double ypos,
double& ex,
double& ey,
8932 const std::vector<bool>& cnalso)
const {
8943 for (
unsigned int i = 0; i < m_nWires; ++i) {
8944 const auto& wire = m_w[i];
8948 const double xx = xpos - wire.x;
8949 const double yy = ypos - wire.y;
8951 const double r2 = xx * xx + yy * yy;
8958 xxmirr = wire.x + xpos - 2 * m_coplax;
8959 const double r2plan = xxmirr * xxmirr + yy * yy;
8960 exhelp -= xxmirr / r2plan;
8961 eyhelp -= yy / r2plan;
8966 yymirr = wire.y + ypos - 2 * m_coplay;
8967 const double r2plan = xx * xx + yymirr * yymirr;
8968 exhelp -= xx / r2plan;
8969 eyhelp -= yymirr / r2plan;
8972 if (m_ynplax && m_ynplay) {
8973 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
8974 exhelp += xxmirr / r2plan;
8975 eyhelp += yymirr / r2plan;
8977 ex += wire.e * exhelp;
8978 ey += wire.e * eyhelp;
8982void ComponentAnalyticField::FieldAtWireB1X(
8983 const double xpos,
const double ypos,
double& ex,
double& ey,
8984 const std::vector<bool>& cnalso)
const {
8990 constexpr std::complex<double> icons(0., 1.);
8991 std::complex<double> ecompl;
8993 const double tx = Pi / m_sx;
8996 for (
unsigned int i = 0; i < m_nWires; ++i) {
8997 const auto& wire = m_w[i];
8998 const double xx = tx * (xpos - wire.x);
8999 const double yy = tx * (ypos - wire.y);
9002 }
else if (yy > 20.) {
9004 }
else if (yy < -20.) {
9007 const std::complex<double> zz(xx, yy);
9008 const auto expzz =
exp(2. * icons * zz);
9009 ecompl = icons * (expzz + 1.) / (expzz - 1.);
9011 const double yymirr = tx * (ypos + wire.y - 2. * m_coplay);
9014 }
else if (yymirr < -20.) {
9017 const std::complex<double> zzmirr(xx, yymirr);
9018 const auto expzzmirr =
exp(2. * icons * zzmirr);
9019 ecompl += -icons * (expzzmirr + 1.) / (expzzmirr - 1.);
9022 ex += wire.e * real(ecompl);
9023 ey -= wire.e * imag(ecompl);
9027 for (
unsigned int i = 0; i < m_nWires; ++i) {
9028 if (!cnalso[i])
continue;
9029 const auto& wire = m_w[i];
9030 const double xx = tx * (xpos - wire.x);
9031 const double yy = tx * (ypos - wire.y);
9034 }
else if (yy < -20.) {
9037 const std::complex<double> zz(xx, yy);
9038 const auto expzz =
exp(2. * icons * zz);
9039 ecompl = icons * (expzz + 1.) / (expzz - 1.);
9041 ex += wire.e * real(ecompl);
9042 ey -= wire.e * imag(ecompl);
9049void ComponentAnalyticField::FieldAtWireB1Y(
9050 const double xpos,
const double ypos,
double& ex,
double& ey,
9051 const std::vector<bool>& cnalso)
const {
9057 std::complex<double> ecompl;
9059 const double ty = Pi / m_sy;
9062 for (
unsigned int i = 0; i < m_nWires; ++i) {
9063 const auto& wire = m_w[i];
9064 const double xx = ty * (xpos - wire.x);
9065 const double yy = ty * (ypos - wire.y);
9068 }
else if (xx > 20.) {
9070 }
else if (xx < -20.) {
9073 const std::complex<double> zz(xx, yy);
9074 const auto expzz =
exp(2. * zz);
9075 ecompl = (expzz + 1.) / (expzz - 1.);
9077 const double xxmirr = ty * (xpos + wire.x - 2. * m_coplax);
9080 }
else if (xxmirr < -20.) {
9083 const std::complex<double> zzmirr(xxmirr, yy);
9084 const auto expzzmirr =
exp(2. * zzmirr);
9085 ecompl -= (expzzmirr + 1.) / (expzzmirr - 1.);
9087 ex += wire.e * real(ecompl);
9088 ey -= wire.e * imag(ecompl);
9092 for (
unsigned int i = 0; i < m_nWires; ++i) {
9093 if (!cnalso[i])
continue;
9094 const auto& wire = m_w[i];
9095 const double xx = ty * (xpos - wire.x);
9096 const double yy = ty * (ypos - wire.y);
9099 }
else if (xx < -20.) {
9102 const std::complex<double> zz(xx, yy);
9103 const auto expzz =
exp(2. * zz);
9104 ecompl = (expzz + 1.) / (expzz - 1.);
9106 ex += wire.e * real(ecompl);
9107 ey -= wire.e * imag(ecompl);
9114void ComponentAnalyticField::FieldAtWireB2X(
9115 const double xpos,
const double ypos,
double& ex,
double& ey,
9116 const std::vector<bool>& cnalso)
const {
9121 constexpr std::complex<double> icons(0., 1.);
9123 const double tx = HalfPi / m_sx;
9125 for (
unsigned int i = 0; i < m_nWires; ++i) {
9126 const double xx = tx * (xpos - m_w[i].x);
9127 const double yy = tx * (ypos - m_w[i].y);
9128 const double xxneg = tx * (xpos - m_w[i].x - 2 * m_coplax);
9130 std::complex<double> ecompl(0., 0.);
9131 if (cnalso[i] &&
fabs(yy) <= 20.) {
9132 const std::complex<double> zz(xx, yy);
9133 const std::complex<double> zzneg(xxneg, yy);
9134 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
9135 }
else if (
fabs(yy) <= 20.) {
9136 const std::complex<double> zzneg(xxneg, yy);
9137 const auto expzzneg =
exp(2. * icons * zzneg);
9138 ecompl = -icons * (expzzneg + 1.) / (expzzneg - 1.);
9142 const double yymirr = tx * (ypos + m_w[i].y - 2 * m_coplay);
9143 if (
fabs(yymirr) <= 20.) {
9144 const std::complex<double> zzmirr(xx, yymirr);
9145 const std::complex<double> zznmirr(xxneg, yymirr);
9146 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
9149 ex += m_w[i].e * real(ecompl);
9150 ey -= m_w[i].e * imag(ecompl);
9156void ComponentAnalyticField::FieldAtWireB2Y(
9157 const double xpos,
const double ypos,
double& ex,
double& ey,
9158 const std::vector<bool>& cnalso)
const {
9163 constexpr std::complex<double> icons(0., 1.);
9165 const double ty = HalfPi / m_sy;
9167 for (
unsigned int i = 0; i < m_nWires; ++i) {
9168 const double xx = ty * (xpos - m_w[i].x);
9169 const double yy = ty * (ypos - m_w[i].y);
9170 const double yyneg = ty * (ypos + m_w[i].y - 2 * m_coplay);
9172 std::complex<double> ecompl(0., 0.);
9173 if (cnalso[i] &&
fabs(xx) <= 20.) {
9174 const std::complex<double> zz(xx, yy);
9175 const std::complex<double> zzneg(xx, yyneg);
9176 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
9177 }
else if (
fabs(xx) <= 20.) {
9178 const std::complex<double> zzneg(xx, yyneg);
9179 const auto expzzneg =
exp(2. * zzneg);
9180 ecompl = -(expzzneg + 1.) / (expzzneg - 1.);
9184 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
9185 if (
fabs(xxmirr) <= 20.) {
9186 const std::complex<double> zzmirr(xxmirr, yy);
9187 const std::complex<double> zznmirr(xxmirr, yyneg);
9189 icons * m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
9192 ex += m_w[i].e * real(ecompl);
9193 ey -= m_w[i].e * imag(ecompl);
9199void ComponentAnalyticField::FieldAtWireC10(
9200 const double xpos,
const double ypos,
double& ex,
double& ey,
9201 const std::vector<bool>& cnalso)
const {
9206 constexpr std::complex<double> icons(0., 1.);
9207 std::complex<double> wsum(0., 0.);
9209 for (
unsigned int j = 0; j < m_nWires; ++j) {
9210 if (!cnalso[j])
continue;
9211 const auto& wire = m_w[j];
9212 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
9213 if (imag(zeta) > 15.) {
9214 wsum -= wire.e * icons;
9215 }
else if (imag(zeta) < -15.) {
9216 wsum += wire.e * icons;
9218 const auto zterm = Th1(zeta, m_p1, m_p2);
9219 wsum += wire.e * (zterm.second / zterm.first);
9222 ex = -real(-m_zmult * wsum);
9223 ey = imag(-m_zmult * wsum);
9224 if (m_mode == 0) ex -= m_c1;
9225 if (m_mode == 1) ey -= m_c1;
9228void ComponentAnalyticField::FieldAtWireC2X(
9229 const double xpos,
const double ypos,
double& ex,
double& ey,
9230 const std::vector<bool>& cnalso)
const {
9235 constexpr std::complex<double> icons(0., 1.);
9237 std::complex<double> wsum1 = 0.;
9238 std::complex<double> wsum2 = 0.;
9239 for (
unsigned int i = 0; i < m_nWires; ++i) {
9240 const auto& wire = m_w[i];
9242 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
9243 if (imag(zeta) > 15.) {
9244 wsum1 -= wire.e * icons;
9245 }
else if (imag(zeta) < -15.) {
9246 wsum1 += wire.e * icons;
9248 const auto zterm = Th1(zeta, m_p1, m_p2);
9249 wsum1 += wire.e * (zterm.second / zterm.first);
9253 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
9256 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
9257 if (imag(zeta) > 15.) {
9258 wsum2 -= wire.e * icons;
9259 }
else if (imag(zeta) < -15.) {
9260 wsum2 += wire.e * icons;
9262 const auto zterm = Th1(zeta, m_p1, m_p2);
9263 wsum2 += wire.e * (zterm.second / zterm.first);
9267 ex = real(m_zmult * (wsum1 + wsum2));
9268 ey = -imag(m_zmult * (wsum1 - wsum2));
9270 if (m_mode == 0) ex -= m_c1;
9273void ComponentAnalyticField::FieldAtWireC2Y(
9274 const double xpos,
const double ypos,
double& ex,
double& ey,
9275 const std::vector<bool>& cnalso)
const {
9280 const std::complex<double> icons(0., 1.);
9282 std::complex<double> wsum1 = 0.;
9283 std::complex<double> wsum2 = 0.;
9284 for (
unsigned int i = 0; i < m_nWires; ++i) {
9285 const auto& wire = m_w[i];
9288 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
9289 if (imag(zeta) > 15.) {
9290 wsum1 -= wire.e * icons;
9291 }
else if (imag(zeta) < -15.) {
9292 wsum1 += wire.e * icons;
9294 const auto zterm = Th1(zeta, m_p1, m_p2);
9295 wsum1 += wire.e * (zterm.second / zterm.first);
9299 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
9302 m_zmult * std::complex<double>(xpos - wire.x, 2 * cy - ypos - wire.y);
9303 if (imag(zeta) > 15.) {
9304 wsum2 -= wire.e * icons;
9305 }
else if (imag(zeta) < -15.) {
9306 wsum2 += wire.e * icons;
9308 const auto zterm = Th1(zeta, m_p1, m_p2);
9309 wsum2 += wire.e * (zterm.second / zterm.first);
9313 ex = real(m_zmult * (wsum1 - wsum2));
9314 ey = -imag(m_zmult * (wsum1 + wsum2));
9316 if (m_mode == 1) ey -= m_c1;
9319void ComponentAnalyticField::FieldAtWireC30(
9320 const double xpos,
const double ypos,
double& ex,
double& ey,
9321 const std::vector<bool>& cnalso)
const {
9326 constexpr std::complex<double> icons(0., 1.);
9328 std::complex<double> wsum1 = 0.;
9329 std::complex<double> wsum2 = 0.;
9330 std::complex<double> wsum3 = 0.;
9331 std::complex<double> wsum4 = 0.;
9332 for (
unsigned int i = 0; i < m_nWires; ++i) {
9333 const auto& wire = m_w[i];
9335 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
9336 if (imag(zeta) > 15.) {
9337 wsum1 -= wire.e * icons;
9338 }
else if (imag(zeta) < -15.) {
9339 wsum1 += wire.e * icons;
9341 const auto zterm = Th1(zeta, m_p1, m_p2);
9342 wsum1 += wire.e * (zterm.second / zterm.first);
9346 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
9349 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
9350 if (imag(zeta) > 15.) {
9351 wsum2 -= wire.e * icons;
9352 }
else if (imag(zeta) < -15.) {
9353 wsum2 += wire.e * icons;
9355 const auto zterm = Th1(zeta, m_p1, m_p2);
9356 wsum2 += wire.e * (zterm.second / zterm.first);
9359 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
9362 m_zmult * std::complex<double>(xpos - wire.x, 2. * cy - ypos - wire.y);
9363 if (imag(zeta) > 15.) {
9364 wsum3 -= wire.e * icons;
9365 }
else if (imag(zeta) < -15.) {
9366 wsum3 += wire.e * icons;
9368 const auto zterm = Th1(zeta, m_p1, m_p2);
9369 wsum3 += wire.e * (zterm.second / zterm.first);
9372 zeta = m_zmult * std::complex<double>(2. * cx - xpos - wire.x,
9373 2. * cy - ypos - wire.y);
9374 if (imag(zeta) > 15.) {
9375 wsum4 -= wire.e * icons;
9376 }
else if (imag(zeta) < -15.) {
9377 wsum4 += wire.e * icons;
9379 const auto zterm = Th1(zeta, m_p1, m_p2);
9380 wsum4 += wire.e * (zterm.second / zterm.first);
9384 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
9385 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
9388void ComponentAnalyticField::FieldAtWireD10(
9389 const double xpos,
const double ypos,
double& ex,
double& ey,
9390 const std::vector<bool>& cnalso)
const {
9397 const std::complex<double> zpos(xpos, ypos);
9399 for (
unsigned int i = 0; i < m_nWires; ++i) {
9400 const auto& wire = m_w[i];
9402 const std::complex<double> zi(wire.x, wire.y);
9405 const std::complex<double> wi =
9406 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
9407 ex += wire.e * real(wi);
9408 ey += wire.e * imag(wi);
9410 const std::complex<double> wi = zi / (m_cotube2 - conj(zpos) * zi);
9411 ex += wire.e * real(wi);
9412 ey += wire.e * imag(wi);
9417void ComponentAnalyticField::FieldAtWireD20(
9418 const double xpos,
const double ypos,
double& ex,
double& ey,
9419 const std::vector<bool>& cnalso)
const {
9426 const std::complex<double> zpos(xpos, ypos);
9427 for (
unsigned int i = 0; i < m_nWires; ++i) {
9428 const auto& wire = m_w[i];
9430 const std::complex<double> zi(wire.x, wire.y);
9433 if (std::abs(zi) > wire.r) {
9434 const std::complex<double> wi =
9435 double(m_mtube) *
pow(conj(zpos), m_mtube - 1) *
9436 (1. / conj(
pow(zpos, m_mtube) -
pow(zi, m_mtube)) +
9438 (
pow(m_cotube, 2 * m_mtube) -
pow(conj(zpos) * zi, m_mtube)));
9439 ex += wire.e * real(wi);
9440 ey += wire.e * imag(wi);
9442 const std::complex<double> wi =
9443 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
9444 ex += wire.e * real(wi);
9445 ey += wire.e * imag(wi);
9448 if (abs(zi) > wire.r) {
9449 const std::complex<double> wi =
9450 double(m_mtube) *
pow(conj(zpos), m_mtube - 1) *
9452 (
pow(m_cotube, 2 * m_mtube) -
pow(conj(zpos) * zi, m_mtube)));
9453 ex += wire.e * real(wi);
9454 ey += wire.e * imag(wi);
9456 const std::complex<double> wi = zi / (m_cotube2 - conj(zpos) * zi);
9457 ex += wire.e * real(wi);
9458 ey += wire.e * imag(wi);
9464void ComponentAnalyticField::FieldAtWireD30(
9465 const double xpos,
const double ypos,
double& ex,
double& ey,
9466 const std::vector<bool>& cnalso)
const {
9473 std::complex<double> wpos, wdpos;
9474 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
9476 for (
unsigned int i = 0; i < m_nWires; ++i) {
9479 const std::complex<double> whelp =
9480 wdpos * (1. -
pow(abs(wmap[i]), 2)) /
9481 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
9482 ex += m_w[i].e * real(whelp);
9483 ey -= m_w[i].e * imag(whelp);
9486 const std::complex<double> whelp =
9487 wdpos * conj(wmap[i]) / (1. - conj(wmap[i]) * wpos);
9488 ex += m_w[i].e * real(whelp);
9489 ey -= m_w[i].e * imag(whelp);
9496bool ComponentAnalyticField::SagDetailed(
9497 const Wire& wire,
const std::vector<double>& xMap,
9498 const std::vector<double>& yMap,
9499 const std::vector<std::vector<double> >& fxMap,
9500 const std::vector<std::vector<double> >& fyMap, std::vector<double>& csag,
9501 std::vector<double>& xsag, std::vector<double>& ysag)
const {
9512 const unsigned int np = m_nSteps * (m_nShots + 1);
9514 const double h = wire.u / np;
9516 std::array<double, 2> xst = {0., 0.};
9517 std::array<double, 2> dxst = {0., 0.};
9521 for (
unsigned int i = 0; i <= np; ++i) {
9522 const double z = i * h;
9523 std::array<double, 2> force = {0., 0.};
9524 if (!GetForceRatio(wire, z, xst, dxst, force, xMap, yMap, fxMap, fyMap)) {
9526 <<
" Wire at nominal position outside scanning area.\n";
9532 const double u2 = wire.u * wire.u;
9534 const double s = u2 / (8. * (1. + np));
9535 double sagx0 = -fxmean * s;
9536 double sagy0 = -fymean * s;
9538 std::cout <<
m_className <<
"::SagDetailed: Parabolic sag.\n";
9539 std::printf(
" dx = %12.5e, dy = %12.5e [cm]\n", sagx0, sagy0);
9542 std::vector<double> xx(4 * m_nShots + 2);
9544 xx[0] = 4 * sagx0 / wire.u;
9545 xx[1] = 4 * sagy0 / wire.u;
9547 for (
unsigned int i = 1; i <= m_nShots; ++i) {
9549 const double z = -0.5 * wire.u + i * m_nSteps * h;
9550 const unsigned int k = 4 * i - 2;
9552 const double f = 1. - 4 *
z *
z / u2;
9554 xx[k + 1] = sagy0 * f;
9556 const double fp = -8 *
z / u2;
9557 xx[k + 2] = sagx0 * fp;
9558 xx[k + 3] = sagy0 * fp;
9561 if (!FindZeroes(wire, h, xx, xMap, yMap, fxMap, fyMap)) {
9563 <<
" Failed to solve the differential equation for the sag.\n";
9567 csag.assign(np + 1, 0.);
9568 xsag.assign(np + 1, 0.);
9569 ysag.assign(np + 1, 0.);
9570 csag[0] = -0.5 * wire.u;
9571 double coor = -0.5 * wire.u;
9572 for (
unsigned int i = 0; i <= m_nShots; ++i) {
9580 xst[0] = xx[4 * i - 2];
9581 xst[1] = xx[4 * i - 1];
9582 dxst[0] = xx[4 * i];
9583 dxst[1] = xx[4 * i + 1];
9586 for (
unsigned int j = 1; j <= m_nSteps; ++j) {
9587 StepRKN(wire, h, coor, xst, dxst, xMap, yMap, fxMap, fyMap);
9588 csag[i * m_nSteps + j] = coor;
9589 xsag[i * m_nSteps + j] = xst[0];
9590 ysag[i * m_nSteps + j] = xst[1];
9597bool ComponentAnalyticField::GetForceRatio(
9598 const Wire& wire,
const double ,
const std::array<double, 2>& bend,
9599 const std::array<double, 2>& , std::array<double, 2>& f,
9600 const std::vector<double>& xMap,
const std::vector<double>& yMap,
9601 const std::vector<std::vector<double> >& fxMap,
9602 const std::vector<std::vector<double> >& fyMap)
const {
9614 const double xw = wire.x + bend[0];
9615 const double yw = wire.y + bend[1];
9616 if (m_useElectrostaticForce) {
9618 if (xMap.empty() || yMap.empty() || fxMap.empty() || fyMap.empty()) {
9622 if (!m_extrapolateForces) {
9623 if ((xMap.front() - xw) * (xw - xMap.back()) < 0 ||
9624 (yMap.front() - yw) * (yw - yMap.back()) < 0) {
9629 constexpr int order = 2;
9631 const unsigned int nX = xMap.size();
9632 const unsigned int nY = yMap.size();
9633 std::vector<double> xaux(nX, 0.);
9634 std::vector<double> yaux(nX, 0.);
9635 for (
unsigned int i = 0; i < nX; ++i) {
9644 if (m_useGravitationalForce) {
9646 const double m = 1.e-3 * wire.density * Pi * wire.r * wire.r;
9647 f[0] -= m_down[0] * m * GravitationalAcceleration;
9648 f[1] -= m_down[1] * m * GravitationalAcceleration;
9651 const double s = 1000. / (GravitationalAcceleration * wire.tension);
9660bool ComponentAnalyticField::StepRKN(
9661 const Wire& wire,
const double h,
double& x, std::array<double, 2>& y,
9662 std::array<double, 2>& yp,
const std::vector<double>& xMap,
9663 const std::vector<double>& yMap,
9664 const std::vector<std::vector<double> >& fxMap,
9665 const std::vector<std::vector<double> >& fyMap)
const {
9666 constexpr double r2 = 1. / 2.;
9667 constexpr double r6 = 1. / 6.;
9668 constexpr double r8 = 1. / 8.;
9669 if (h == 0)
return true;
9670 const double h2 = r2 * h;
9671 const double h6 = r6 * h;
9672 const double hh2 = h * h2;
9673 const double hh6 = h * h6;
9674 const double hh8 = r8 * h * h;
9676 constexpr unsigned int n = 2;
9677 std::array<std::array<double, n>, 6> w;
9678 if (!GetForceRatio(wire, x, y, yp, w[0], xMap, yMap, fxMap, fyMap)) {
9681 for (
unsigned int j = 0; j < n; ++j) {
9682 w[3][j] =
y[j] + h2 * yp[j];
9683 w[4][j] = w[3][j] + hh8 * w[0][j];
9684 w[5][j] = yp[j] + h2 * w[0][j];
9686 const double xh2 =
x + h2;
9687 if (!GetForceRatio(wire, xh2, w[4], w[5], w[1], xMap, yMap, fxMap, fyMap)) {
9690 for (
unsigned int j = 0; j < n; ++j) {
9691 w[5][j] = yp[j] + h2 * w[1][j];
9692 w[0][j] = w[0][j] + w[1][j];
9693 w[1][j] = w[0][j] + w[1][j];
9695 if (!GetForceRatio(wire, xh2, w[4], w[5], w[2], xMap, yMap, fxMap, fyMap)) {
9698 for (
unsigned int j = 0; j < n; ++j) {
9699 w[3][j] = w[3][j] + h2 * yp[j];
9700 w[4][j] = w[3][j] + hh2 * w[2][j];
9701 w[5][j] = yp[j] + h * w[2][j];
9702 w[0][j] = w[0][j] + w[2][j];
9703 w[1][j] = w[1][j] + 2 * w[2][j];
9705 const double xh =
x + h;
9706 if (!GetForceRatio(wire, xh, w[4], w[5], w[2], xMap, yMap, fxMap, fyMap)) {
9709 for (
unsigned int j = 0; j < n; ++j) {
9710 y[j] = w[3][j] + hh6 * w[0][j];
9711 yp[j] += h6 * (w[1][j] + w[2][j]);
9717bool ComponentAnalyticField::FindZeroes(
9718 const Wire& wire,
const double h, std::vector<double>& x,
9719 const std::vector<double>& xMap,
const std::vector<double>& yMap,
9720 const std::vector<std::vector<double> >& fxMap,
9721 const std::vector<std::vector<double> >& fyMap)
const {
9731 std::cerr <<
m_className <<
"::FindZeroes: Empty vector.\n";
9734 const unsigned int n =
x.size();
9736 std::vector<double> fold(n, 0.);
9737 if (!Trace(wire, h, x, fold, xMap, yMap, fxMap, fyMap)) {
9738 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9739 <<
"Initial position outside scanning area.\n";
9743 std::inner_product(fold.begin(), fold.end(), fold.begin(), 0.);
9745 constexpr unsigned int nbsmax = 10;
9746 constexpr unsigned int nitmax = 20;
9747 constexpr double eps = 1.e-4;
9748 constexpr double epsx = 1.e-4;
9749 constexpr double epsf = 1.e-4;
9751 std::cout <<
m_className <<
"::FindZeroes: Start of zero search.\n"
9752 <<
" Number of parameters: " << n <<
"\n"
9753 <<
" Maximum bisections: " << nbsmax <<
"\n"
9754 <<
" Maximum iterations: " << nitmax <<
"\n"
9755 <<
" Epsilon differentiation: " << eps <<
"\n"
9756 <<
" Required location change: " << epsx <<
"\n"
9757 <<
" Required function norm: " << epsf <<
"\n"
9758 <<
" Initial function norm: " <<
sqrt(fnorml) <<
"\n"
9759 <<
" Parameter Value Function\n";
9760 for (
unsigned int i = 0; i < n; ++i) {
9761 std::printf(
" %9d %12.5e %12.5e\n", i, x[i], fold[i]);
9765 std::vector<std::vector<double> > b(n, std::vector<double>(n, 0.));
9766 std::vector<std::vector<double> > bb(n, std::vector<double>(n, 0.));
9768 bool updateMatrix =
true;
9770 unsigned int nCalls = 0;
9771 bool converged =
false;
9772 for (
unsigned int iter = 0; iter < nitmax; ++iter) {
9775 std::vector<double> f1(n, 0.);
9776 std::vector<double> f2(n, 0.);
9777 for (
unsigned int i = 0; i < n; ++i) {
9778 const double epsdif = eps * (1. + std::abs(x[i]));
9779 x[i] += 0.5 * epsdif;
9780 if (!Trace(wire, h, x, f1, xMap, yMap, fxMap, fyMap)) {
9781 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9782 <<
"Differential matrix requires a point "
9783 <<
"outside scanning area.\n";
9787 if (!Trace(wire, h, x, f2, xMap, yMap, fxMap, fyMap)) {
9788 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9789 <<
"Differential matrix requires a point "
9790 <<
"outside scanning area.\n";
9793 x[i] += 0.5 * epsdif;
9794 for (
unsigned int j = 0; j < n; ++j) {
9795 b[j][i] = (f1[j] - f2[j]) / epsdif;
9799 updateMatrix =
false;
9802 std::cout <<
" Start of iteration " << iter <<
"\n";
9803 for (
unsigned int i = 0; i < m_nShots; ++i) {
9804 const unsigned int k = 4 * i + 2;
9805 std::printf(
" x = %12.5e, y = %12.5e\n", x[k], x[k + 1]);
9809 std::vector<double> dx = fold;
9812 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n"
9813 <<
" Solving the update equation failed.\n";
9817 for (
unsigned int i = 0; i < m_nShots; ++i) {
9818 const unsigned int k = 4 * i + 2;
9819 std::printf(
" dx = %12.5e, dy = %12.5e\n", dx[k], dx[k + 1]);
9824 double fnorm = 2 * fnorml;
9825 std::vector<double> xnew(n, 0.);
9826 std::vector<double> fnew(n, 0.);
9827 for (
unsigned int kbs = 0; kbs < nbsmax; ++kbs) {
9828 for (
unsigned int i = 0; i < n; ++i) {
9829 xnew[i] =
x[i] - scale * dx[i];
9831 if (!Trace(wire, h, xnew, fnew, xMap, yMap, fxMap, fyMap)) {
9833 <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9834 <<
"Step update leads to a point outside the scanning area.\n";
9838 fnorm = std::inner_product(fnew.begin(), fnew.end(), fnew.begin(), 0.);
9839 if (fnorm <= fnorml) {
9840 if (
m_debug) std::cout <<
" Scaling factor: " << scale <<
"\n";
9845 if (fnorm > fnorml) {
9846 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9847 <<
"Bisection search for scaling factor did not converge.\n";
9851 std::vector<double> df(n, 0.);
9852 for (
unsigned int i = 0; i < n; ++i) {
9853 dx[i] = xnew[i] -
x[i];
9855 df[i] = fnew[i] - fold[i];
9858 double xnorm = std::inner_product(
x.begin(),
x.end(),
x.begin(), 0.);
9859 double dxnorm = std::inner_product(dx.begin(), dx.end(), dx.begin(), 0.);
9860 double dfnorm = std::inner_product(df.begin(), df.end(), df.begin(), 0.);
9863 std::cout <<
" After this iteration...\n";
9864 std::printf(
" Norm and change of position: %12.5e %12.5e\n",
9866 std::printf(
" Norm and change of function: %12.5e %12.5e\n",
9870 if (
sqrt(dxnorm) < epsx *
sqrt(xnorm)) {
9872 std::cout <<
" Positional convergence criterion is satisfied.\n";
9876 }
else if (
sqrt(fnorm) < epsf) {
9878 std::cout <<
" Function value convergence criterion is satisfied.\n";
9885 if (scale > 0.4 && iter != 5 * (iter / 5)) {
9887 if (
m_debug) std::cout <<
" Performing a Broyden rank-1 update.\n";
9889 std::vector<double> corr(n, 0.);
9890 for (
unsigned int i = 0; i < n; ++i) {
9892 for (
unsigned int j = 0; j < n; ++j) {
9893 corr[i] -= b[i][j] * dx[j];
9897 for (
unsigned int i = 0; i < n; ++i) {
9898 for (
unsigned int j = 0; j < n; ++j) {
9899 b[i][j] += corr[i] * dx[j] / dxnorm;
9904 if (
m_debug) std::cout <<
" Recomputing the covariance matrix.\n";
9905 updateMatrix =
true;
9909 std::cerr <<
m_className <<
"::FindZeroes: Search did not converge.\n";
9912 std::vector<double> f(n, 0.);
9913 Trace(wire, h, x, f, xMap, yMap, fxMap, fyMap);
9915 std::cout <<
" Final values:\n"
9916 <<
" Parameter Value Function\n";
9917 for (
unsigned int i = 0; i < n; ++i) {
9918 std::printf(
" %9d %12.5e %12.5e\n", i, x[i], f[i]);
9920 std::cout <<
" Total number of function calls: " << nCalls <<
"\n";
9925bool ComponentAnalyticField::Trace(
9926 const Wire& wire,
const double h,
const std::vector<double>& xx,
9927 std::vector<double>& delta,
const std::vector<double>& xMap,
9928 const std::vector<double>& yMap,
9929 const std::vector<std::vector<double> >& fxMap,
9930 const std::vector<std::vector<double> >& fyMap)
const {
9938 delta.assign(xx.size(), 0.);
9940 double z = -0.5 * wire.u;
9941 std::array<double, 2> xst = {0., 0.};
9942 std::array<double, 2> dxst = {xx[0], xx[1]};
9943 for (
unsigned int i = 0; i <= m_nShots; ++i) {
9944 const unsigned int k = 4 * i;
9947 xst = {xx[k - 2], xx[k - 1]};
9948 dxst = {xx[k], xx[k + 1]};
9951 for (
unsigned int j = 0; j < m_nSteps; ++j) {
9952 if (!StepRKN(wire, h, z, xst, dxst, xMap, yMap, fxMap, fyMap)) {
9958 delta[k] = xst[0] - xx[k + 2];
9959 delta[k + 1] = xst[1] - xx[k + 3];
9960 delta[k + 2] = dxst[0] - xx[k + 4];
9961 delta[k + 3] = dxst[1] - xx[k + 5];
9964 delta[k + 1] = xst[1];
9970bool ComponentAnalyticField::SetupDipoleTerms() {
9978 constexpr double epsp = 1.e-3;
9979 constexpr double epsa = 1.e-3;
9981 const unsigned int nWires = m_w.size();
9983 std::vector<double> phi2(nWires, 0.);
9984 m_cosph2.assign(nWires, 1.);
9985 m_sinph2.assign(nWires, 0.);
9986 m_amp2.assign(nWires, 0.);
9989 std::vector<double> phit2(nWires, 0.);
9990 std::vector<double> ampt2(nWires, 0.);
9991 constexpr unsigned int nMaxIter = 10;
9992 for (
unsigned int iter = 0; iter < nMaxIter; ++iter) {
9994 std::cout <<
"Iteration " << iter <<
"/" << nMaxIter <<
"\n"
9995 <<
" Wire correction angle [deg] amplitude\n";
9998 for (
unsigned int iw = 0; iw < nWires; ++iw) {
9999 const double xw = m_w[iw].x;
10000 const double yw = m_w[iw].y;
10001 const double rw = m_w[iw].r;
10005 constexpr unsigned int nAngles = 20;
10006 std::vector<double> angle(nAngles, 0.);
10007 std::vector<double> volt(nAngles, 0.);
10008 constexpr double rmult = 1.;
10009 const double r = rw * rmult;
10011 for (
unsigned int i = 0; i < nAngles; ++i) {
10012 angle[i] = TwoPi * (i + 1.) / nAngles;
10013 const double x = xw + r *
cos(angle[i]);
10014 const double y = yw + r *
sin(angle[i]);
10015 double ex = 0., ey = 0., ez = 0.;
10016 status = Field(x, y, 0., ex, ey, ez, volt[i],
true);
10018 std::cerr <<
"Unexpected status code; computation stopped.\n";
10021 volt[i] -= m_w[iw].v;
10025 if (status != 0)
continue;
10027 double ampdip = 0., phidip = 0.;
10028 FitDipoleMoment(angle, volt, ampdip, phidip,
false);
10030 phit2[iw] = phidip;
10031 ampt2[iw] = ampdip * r;
10033 std::printf(
" %3d %10.3f %12.5e\n",
10034 iw, RadToDegree * phit2[iw], ampt2[iw]);
10038 bool reiter =
false;
10039 if (
m_debug) std::cout <<
" Wire new angle [deg] amplitude\n";
10040 for (
unsigned int iw = 0; iw < nWires; ++iw) {
10042 bool converged =
true;
10043 if (std::abs(phi2[iw]) > epsp * (1. + std::abs(phi2[iw])) ||
10044 std::abs(m_amp2[iw]) > epsa * (1. + std::abs(m_amp2[iw]))) {
10049 const double s0 = m_sinph2[iw] * m_amp2[iw] +
sin(phit2[iw]) * ampt2[iw];
10050 const double c0 = m_cosph2[iw] * m_amp2[iw] +
cos(phit2[iw]) * ampt2[iw];
10051 phi2[iw] = atan2(s0, c0);
10052 m_cosph2[iw] =
cos(phi2[iw]);
10053 m_sinph2[iw] =
sin(phi2[iw]);
10054 const double s1 = m_sinph2[iw] * m_amp2[iw] +
sin(phit2[iw]) * ampt2[iw];
10055 const double c1 = m_cosph2[iw] * m_amp2[iw] +
cos(phit2[iw]) * ampt2[iw];
10056 m_amp2[iw] =
sqrt(s1 * s1 + c1 * c1);
10058 std::printf(
" %3d %10.3f %12.5e %s\n",
10059 iw, RadToDegree * phi2[iw], m_amp2[iw],
10060 converged ?
"CONVERGED" :
"");
10064 if (!reiter)
return true;
10067 std::cerr <<
m_className <<
"::SetupDipoleTerms:\n"
10068 <<
" Maximum number of dipole iterations exceeded "
10069 <<
"without convergence; abandoned.\n";
10073void ComponentAnalyticField::DipoleFieldA00(
10074 const double xpos,
const double ypos,
10075 double& ex,
double& ey,
double& volt,
const bool opt)
const {
10088 for (
unsigned int i = 0; i < m_nWires; ++i) {
10089 const auto& wire = m_w[i];
10090 const double dx = xpos - wire.x;
10091 const double dy = ypos - wire.y;
10092 const double dxm = xpos + wire.x - 2. * m_coplax;
10093 const double dym = ypos + wire.y - 2. * m_coplay;
10095 const double a = dx * dx - dy * dy;
10096 const double b = 2 * dx * dy;
10097 const double d2 = dx * dx + dy * dy;
10098 const double d4 = d2 * d2;
10099 double fx = (a * m_cosph2[i] + b * m_sinph2[i]) / d4;
10100 double fy = (b * m_cosph2[i] - a * m_sinph2[i]) / d4;
10101 if (opt) v = (dx * m_cosph2[i] + dy * m_sinph2[i]) / d2;
10104 const double am = dxm * dxm - dy * dy;
10105 const double bm = 2 * dxm * dy;
10106 const double d2m = dxm * dxm + dy * dy;
10107 const double d4m = d2m * d2m;
10108 fx -= (am * m_cosph2[i] + bm * m_sinph2[i]) / d4m;
10109 fy -= (bm * m_cosph2[i] - am * m_sinph2[i]) / d4m;
10110 if (opt) v -= (dxm * m_cosph2[i] + dy * m_sinph2[i]) / d2m;
10114 const double am = dx * dx - dym * dym;
10115 const double bm = 2 * dx * dym;
10116 const double d2m = dx * dx + dym * dym;
10117 const double d4m = d2m * d2m;
10118 fx -= (am * m_cosph2[i] + bm * m_sinph2[i]) / d4m;
10119 fy -= (bm * m_cosph2[i] - am * m_sinph2[i]) / d4m;
10120 if (opt) v -= (dx * m_cosph2[i] + dym * m_sinph2[i]) / d2m;
10123 if (m_ynplax && m_ynplay) {
10124 const double am = dxm * dxm - dym * dym;
10125 const double bm = 2 * dxm * dym;
10126 const double d2m = dxm * dxm + dym * dym;
10127 const double d4m = d2m * d2m;
10128 fx += (am * m_cosph2[i] + bm * m_sinph2[i]) / d4m;
10129 fy += (bm * m_cosph2[i] - am * m_sinph2[i]) / d4m;
10130 if (opt) v += (dxm * m_cosph2[i] + dym * m_sinph2[i]) / d2m;
10133 volt -= m_amp2[i] * v;
10134 ex -= m_amp2[i] * fx;
10135 ey -= m_amp2[i] * fy;
10139void ComponentAnalyticField::DipoleFieldB1X(
10140 const double xpos,
const double ypos,
10141 double& ex,
double& ey,
double& volt,
const bool opt)
const {
10153 const double tx = Pi / m_sx;
10154 const double tx2 = tx * tx;
10157 for (
unsigned int i = 0; i < m_nWires; ++i) {
10158 const auto& wire = m_w[i];
10160 const double dx = tx * (xpos - wire.x);
10161 const double dy = tx * (ypos - wire.y);
10162 const double a = 1 -
cos(2 * dx) * cosh(2 * dy);
10163 const double b =
sin(2 * dx) * sinh(2 * dy);
10164 const double sx =
sin(dx);
10165 const double shy = sinh(dy);
10166 const double d2 = sx * sx + shy * shy;
10167 const double d4 = d2 * d2;
10168 double fx = ( m_cosph2[i] * a + m_sinph2[i] * b) / d4;
10169 double fy = (-m_sinph2[i] * a + m_cosph2[i] * b) / d4;
10171 v = (m_cosph2[i] *
sin(2 * dx) + m_sinph2[i] * sinh(2 * dy)) / d2;
10175 const double dym = tx * (ypos + wire.y - 2. * m_coplay);
10176 const double am = 1 -
cos(2 * dx) * cosh(2 * dym);
10177 const double bm =
sin(2 * dx) * sinh(2 * dym);
10178 const double shym = sinh(dym);
10179 const double d2m = sx * sx + shym * shym;
10180 const double d4m = d2m * d2m;
10181 fx -= (m_cosph2[i] * am - m_sinph2[i] * bm) / d4m;
10182 fy -= (m_sinph2[i] * am + m_cosph2[i] * bm) / d4m;
10184 v -= (m_cosph2[i] *
sin(2 * dx) - m_sinph2[i] * sinh(2 * dym)) / d2m;
10188 ex -= m_amp2[i] * 0.5 * tx2 * fx;
10189 ey -= m_amp2[i] * 0.5 * tx2 * fy;
10190 if (opt) volt -= 0.5 * tx * m_amp2[i] * v;
10194void ComponentAnalyticField::DipoleFieldB1Y(
10195 const double xpos,
const double ypos,
10196 double& ex,
double& ey,
double& volt,
const bool opt)
const {
10208 const double ty = Pi / m_sy;
10209 const double ty2 = ty * ty;
10212 for (
unsigned int i = 0; i < m_nWires; ++i) {
10213 const auto& wire = m_w[i];
10215 const double dx = ty * (xpos - wire.x);
10216 const double dy = ty * (ypos - wire.y);
10217 const double a = 1 - cosh(2 * dx) *
cos(2 * dy);
10218 const double b = sinh(2 * dx) *
sin(2 * dy);
10219 const double shx = sinh(dx);
10220 const double sy =
sin(dy);
10221 const double d2 = shx * shx + sy * sy;
10222 const double d4 = d2 * d2;
10223 double fx = (-m_cosph2[i] * a + m_sinph2[i] * b) / d4;
10224 double fy = ( m_sinph2[i] * a + m_cosph2[i] * b) / d4;
10226 v = (m_cosph2[i] * sinh(2 * dx) + m_sinph2[i] *
sin(2 * dy)) / d2;
10230 const double dxm = ty * (xpos + wire.x - 2. * m_coplax);
10231 const double am = 1 - cosh(2 * dxm) *
cos(2 * dy);
10232 const double bm = sinh(2 * dxm) *
sin(2 * dy);
10233 const double shxm = sinh(dxm);
10234 const double d2m = shxm * shxm + sy * sy;
10235 const double d4m = d2m * d2m;
10236 fx -= (m_cosph2[i] * am + m_sinph2[i] * bm) / d4m;
10237 fy -= (m_sinph2[i] * am - m_cosph2[i] * bm) / d4m;
10239 v -= (-m_cosph2[i] * sinh(2 * dxm) + m_sinph2[i] *
sin(2 * dy)) / d2m;
10243 ex -= m_amp2[i] * 0.5 * ty2 * fx;
10244 ey -= m_amp2[i] * 0.5 * ty2 * fy;
10245 if (opt) volt -= 0.5 * ty * m_amp2[i] * v;
10249void ComponentAnalyticField::DipoleFieldB2X(
10250 const double xpos,
const double ypos,
10251 double& ex,
double& ey,
double& volt,
const bool opt)
const {
10263 const double tx = HalfPi / m_sx;
10264 const double tx2 = tx * tx;
10267 for (
unsigned int i = 0; i < m_nWires; ++i) {
10268 const auto& wire = m_w[i];
10269 const double dx = tx * (xpos - wire.x);
10270 const double dy = tx * (ypos - wire.y);
10272 const double a = 1 -
cos(2 * dx) * cosh(2 * dy);
10273 const double b =
sin(2 * dx) * sinh(2 * dy);
10274 const double sx =
sin(dx);
10275 const double shy = sinh(dy);
10276 const double d2 = sx * sx + shy * shy;
10277 const double d4 = d2 * d2;
10278 double fx = ( m_cosph2[i] * a + m_sinph2[i] * b) / d4;
10279 double fy = (-m_sinph2[i] * a + m_cosph2[i] * b) / d4;
10280 const double dxn = tx * (xpos + wire.x - 2. * m_coplax);
10281 const double an = 1 -
cos(2 * dxn) * cosh(2 * dy);
10282 const double bn =
sin(2 * dxn) * sinh(2 * dy);
10283 const double sxn =
sin(dxn);
10284 const double d2n = sxn * sxn + shy * shy;
10285 const double d4n = d2n * d2n;
10286 fx += (m_cosph2[i] *
an - m_sinph2[i] * bn) / d4n;
10287 fy += (m_sinph2[i] *
an + m_cosph2[i] * bn) / d4n;
10289 v = -
sin(dx + dxn) * (-2 * m_cosph2[i] * (
10290 (1 + shy * shy) * sx * sxn +
cos(dx) *
cos(dxn) * shy * shy) +
10291 m_sinph2[i] * m_b2sin[i] * sinh(2 * dy)) / (d2 * d2n);
10295 const double dym = tx * (ypos + wire.y - 2. * m_coplay);
10296 const double am = 1 -
cos(2 * dx) * cosh(2 * dym);
10297 const double bm =
sin(2 * dx) * sinh(2 * dym);
10298 const double shym = sinh(dym);
10299 const double d2m = sx * sx + shym * shym;
10300 const double d4m = d2m * d2m;
10301 fx -= (m_cosph2[i] * am - m_sinph2[i] * bm) / d4m;
10302 fy -= (m_sinph2[i] * am + m_cosph2[i] * bm) / d4m;
10303 const double amn = 1 -
cos(2 * dxn) * cosh(2 * dym);
10304 const double bmn =
sin(2 * dxn) * sinh(2 * dym);
10305 const double d2mn = sxn * sxn + shym * shym;
10306 const double d4mn = d2mn * d2mn;
10307 fx -= ( m_cosph2[i] * amn + m_sinph2[i] * bmn) / d4mn;
10308 fy -= (-m_sinph2[i] * amn + m_cosph2[i] * bmn) / d4mn;
10310 v +=
sin(dx + dxn) * (-2 * m_cosph2[i] * (
10311 (1 + shym * shym) * sx * sxn +
cos(dx) *
cos(dxn) * shym * shym) -
10312 m_sinph2[i] * m_b2sin[i] * sinh(2 * dym)) / (d2m * d2mn);
10316 ex -= m_amp2[i] * 0.5 * tx2 * fx;
10317 ey -= m_amp2[i] * 0.5 * tx2 * fy;
10318 if (opt) volt -= 0.5 * tx * m_amp2[i] * v;
10322void ComponentAnalyticField::DipoleFieldB2Y(
10323 const double xpos,
const double ypos,
10324 double& ex,
double& ey,
double& volt,
const bool opt)
const {
10336 const double ty = HalfPi / m_sy;
10337 const double ty2 = ty * ty;
10340 for (
unsigned int i = 0; i < m_nWires; ++i) {
10341 const auto& wire = m_w[i];
10342 const double dx = ty * (xpos - wire.x);
10343 const double dy = ty * (ypos - wire.y);
10345 const double a = 1 - cosh(2 * dx) *
cos(2 * dy);
10346 const double b = sinh(2 * dx) *
sin(2 * dy);
10347 const double shx = sinh(dx);
10348 const double sy =
sin(dy);
10349 const double d2 = shx * shx + sy * sy;
10350 const double d4 = d2 * d2;
10351 double fx = (-m_cosph2[i] * a + m_sinph2[i] * b) / d4;
10352 double fy = ( m_sinph2[i] * a + m_cosph2[i] * b) / d4;
10353 const double dyn = ty * (ypos + wire.y - 2. * m_coplay);
10354 const double an = 1 - cosh(2 * dx) *
sin(2 * dyn);
10355 const double bn = sinh(2 * dx) *
sin(2 * dyn);
10356 const double syn =
sin(dyn);
10357 const double d2n = shx * shx + syn * syn;
10358 const double d4n = d2n * d2n;
10359 fx += (m_cosph2[i] *
an + m_sinph2[i] * bn) / d4n;
10360 fy += (m_sinph2[i] *
an - m_cosph2[i] * bn) / d4n;
10363 v =
sin(dy + dyn) * (
10364 m_sinph2[i] * (-
cos(dy + dyn) +
cos(dy - dyn) * cosh(2 * dx)) -
10365 m_cosph2[i] * sinh(2 * dx) * (
cos(dyn) * sy +
cos(dy) * syn)) /
10370 const double dxm = ty * (xpos + wire.x - 2. * m_coplax);
10371 const double am = 1 - cosh(2 * dxm) *
cos(2 * dy);
10372 const double bm = sinh(2 * dxm) *
sin(2 * dy);
10373 const double shxm = sinh(dxm);
10374 const double d2m = shxm * shxm + sy * sy;
10375 const double d4m = d2m * d2m;
10376 fx -= (m_cosph2[i] * am + m_sinph2[i] * bm) / d4m;
10377 fy -= (m_sinph2[i] * am - m_cosph2[i] * bm) / d4m;
10378 const double amn = 1 - cosh(2 * dxm) *
cos(2 * dyn);
10379 const double bmn = sinh(2 * dxm) *
sin(2 * dyn);
10380 const double d2mn = shxm * shxm + syn * syn;
10381 const double d4mn = d2mn * d2mn;
10382 fx -= (-m_cosph2[i] * amn + m_sinph2[i] * bmn) / d4mn;
10383 fy -= ( m_sinph2[i] * amn + m_cosph2[i] * bmn) / d4mn;
10386 v -=
sin(dy + dyn) * (
10387 m_sinph2[i] * (-
cos(dy + dyn) +
cos(dy - dyn) * cosh(2 * dxm)) +
10388 m_cosph2[i] * sinh(2 * dxm) * (
cos(dyn) * sy -
cos(dy) * syn)) /
10394 ex -= m_amp2[i] * 0.5 * ty2 * fx;
10395 ey -= m_amp2[i] * 0.5 * ty2 * fy;
10396 if (opt) volt -= 0.5 * ty * m_amp2[i] * v;
10401 const unsigned int nPoles,
const bool print,
const bool plot,
10402 const double rmult,
const double eps,
10403 const unsigned int nMaxIter) {
10408 if (!m_cellset && !Prepare())
return false;
10410 if (iw >= m_nWires) {
10411 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
10412 <<
" Wire index out of range.\n";
10416 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
10417 <<
" Epsilon must be positive.\n";
10421 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
10422 <<
" Multipole order out of range.\n";
10426 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
10427 <<
" Radius multiplication factor out of range.\n";
10431 const double xw = m_w[iw].x;
10432 const double yw = m_w[iw].y;
10434 const double rw = m_w[iw].r;
10438 constexpr unsigned int nPoints = 20000;
10439 std::vector<double> angle(nPoints, 0.);
10440 std::vector<double> volt(nPoints, 0.);
10441 std::vector<double> weight(nPoints, 1.);
10442 for (
unsigned int i = 0; i < nPoints; ++i) {
10444 angle[i] = TwoPi * (i + 1.) / nPoints;
10446 const double x = xw + rmult * rw * cos(angle[i]);
10447 const double y = yw + rmult * rw * sin(angle[i]);
10448 double ex = 0., ey = 0., ez = 0., v = 0.;
10449 if (Field(x, y, 0., ex, ey, ez, v,
true) != 0) {
10450 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
10451 <<
" Unexpected location code. Computation stopped.\n";
10462 double vmin = *std::min_element(volt.cbegin(), volt.cend());
10463 double vmax = *std::max_element(volt.cbegin(), volt.cend());
10464 double vave = std::accumulate(volt.cbegin(), volt.cend(), 0.) / nPoints;
10466 for (
unsigned int i = 0; i < nPoints; ++i) volt[i] -= vave;
10471 const double vm = 0.5 * fabs(vmin) + fabs(vmax);
10472 double chi2 = 1.e-6 * nPoints * vm * vm;
10473 const double dist = 1.e-3 * (1. + vm);
10474 const unsigned int nPar = 2 * nPoles + 1;
10475 std::vector<double> pars(nPar, 0.);
10476 std::vector<double> epar(nPar, 0.);
10477 pars[0] = 0.5 * (vmax + vmin);
10478 for (
unsigned int i = 1; i <= nPoles; ++i) {
10479 pars[2 * i - 1] = 0.5 * (vmax - vmin);
10483 auto f = [nPoles](
const double x,
const std::vector<double>& par) {
10486 double sum = par[0];
10487 for (
unsigned int k = 1; k <= nPoles; ++k) {
10489 const float cphi = cos(x - par[2 * k]);
10496 nMaxIter, dist, chi2, eps,
m_debug, print)) {
10497 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
10498 <<
" Fitting the multipoles failed; computation stopped.\n";
10503 TCanvas* cfit =
new TCanvas(name.c_str(),
"Multipoles");
10506 cfit->DrawFrame(0., vmin, TwoPi, vmax,
10507 ";Angle around the wire [rad]; Potential - average [V]");
10509 graph.SetLineWidth(2);
10510 graph.SetLineColor(kBlack);
10511 graph.DrawGraph(angle.size(), angle.data(), volt.data(),
"lsame");
10513 constexpr unsigned int nP = 1000;
10514 std::array<double, nP> xp;
10515 std::array<double, nP> yp;
10516 for (
unsigned int i = 0; i < nP; ++i) {
10517 xp[i] = TwoPi * (i + 1.) / nP;
10518 yp[i] = f(xp[i], pars);
10520 graph.SetLineColor(kViolet + 3);
10521 graph.DrawGraph(nP, xp.data(), yp.data(),
"lsame");
10523 std::vector<double> parres = pars;
10524 for (
unsigned int i = 1; i <= nPoles; ++i) parres[2 * i - 1] = 0.;
10525 for (
unsigned int j = 1; j <= nPoles; ++j) {
10526 parres[2 * j - 1] = pars[2 * j - 1];
10527 for (
unsigned int i = 0; i < nP; ++i) {
10528 yp[i] = f(xp[i], parres);
10530 parres[2 * j - 1] = 0.;
10531 graph.SetLineColor(kAzure + j);
10532 graph.DrawGraph(nP, xp.data(), yp.data(),
"lsame");
10538 std::cout <<
m_className <<
"::MultipoleMoments:\n"
10539 <<
" Multipole moments for wire " << iw <<
":\n"
10540 <<
" Moment Value Angle [degree]\n";
10541 std::printf(
" %6u %15.8f Arbitrary\n", 0, vave);
10542 for (
unsigned int i = 1; i <= nPoles; ++i) {
10544 const double val = pow(rmult * rw, i) * pars[2 * i - 1];
10545 const double phi = RadToDegree * fmod(pars[2 * i], Pi);
10546 std::printf(
" %6u %15.8f %15.8f\n", i, val, phi);
void PrintCell()
Print all available information on the cell.
void SetGravity(const double dx, const double dy, const double dz)
Set the gravity orientation.
bool GetVoltageRange(double &pmin, double &pmax) override
Calculate the voltage range [V].
void SetPolarCoordinates()
Use polar coordinates.
void SetPeriodicityX(const double s)
Set the periodic length [cm] in the x-direction.
void EnableDipoleTerms(const bool on=true)
Request dipole terms be included for each of the wires (default: off).
bool GetPeriodicityY(double &s)
Get the periodic length in the y-direction.
void SetCartesianCoordinates()
Use Cartesian coordinates (default).
void AddPixelOnPlanePhi(const double phi, const double rmin, const double rmax, const double zmin, const double zmax, const std::string &label, const double gap=-1.)
Add a pixel on an existing plane at constant phi.
void AddTube(const double radius, const double voltage, const int nEdges, const std::string &label)
Add a tube.
void AddPlaneX(const double x, const double voltage, const std::string &label)
Add a plane at constant x.
void AddPixelOnPlaneX(const double x, const double ymin, const double ymax, const double zmin, const double zmax, const std::string &label, const double gap=-1., const double rot=0.)
void AddCharge(const double x, const double y, const double z, const double q)
Add a point charge.
void SetScanningGrid(const unsigned int nX, const unsigned int nY)
void SetNumberOfSteps(const unsigned int n)
Set the number of integration steps within each shot (must be >= 1).
std::string GetCellType()
void AddPixelOnPlaneR(const double r, const double phimin, const double phimax, const double zmin, const double zmax, const std::string &label, const double gap=-1.)
Add a pixel on an existing plane at constant radius.
bool GetWire(const unsigned int i, double &x, double &y, double &diameter, double &voltage, std::string &label, double &length, double &charge, int &ntrap) const
Retrieve the parameters of a wire.
bool GetPlaneR(const unsigned int i, double &r, double &voltage, std::string &label) const
Retrieve the parameters of a plane at constant radius.
bool WireDisplacement(const unsigned int iw, const bool detailed, std::vector< double > &csag, std::vector< double > &xsag, std::vector< double > &ysag, double &stretch, const bool print=true)
void GetGravity(double &dx, double &dy, double &dz) const
Get the gravity orientation.
ComponentAnalyticField()
Constructor.
void AddStripOnPlaneX(const char direction, const double x, const double smin, const double smax, const std::string &label, const double gap=-1.)
void ClearCharges()
Remove all point charges.
unsigned int GetNumberOfPlanesY() const
Get the number of equipotential planes at constant y.
void AddPlanePhi(const double phi, const double voltage, const std::string &label)
Add a plane at constant phi.
void AddPlaneR(const double r, const double voltage, const std::string &label)
Add a plane at constant radius.
bool ElectricFieldAtWire(const unsigned int iw, double &ex, double &ey)
bool MultipoleMoments(const unsigned int iw, const unsigned int order=4, const bool print=false, const bool plot=false, const double rmult=1., const double eps=1.e-4, const unsigned int nMaxIter=20)
void AddWire(const double x, const double y, const double diameter, const double voltage, const std::string &label, const double length=100., const double tension=50., const double rho=19.3, const int ntrap=5)
Add a wire at (x, y) .
unsigned int GetNumberOfPlanesX() const
Get the number of equipotential planes at constant x.
bool GetPeriodicityX(double &s)
Get the periodic length in the x-direction.
bool GetTube(double &r, double &voltage, int &nEdges, std::string &label) const
Retrieve the tube parameters.
bool GetPlaneX(const unsigned int i, double &x, double &voltage, std::string &label) const
Retrieve the parameters of a plane at constant x.
void AddPlaneY(const double y, const double voltage, const std::string &label)
Add a plane at constant y.
bool IsInTrapRadius(const double q0, const double x0, const double y0, const double z0, double &xw, double &yx, double &rw) override
bool GetElementaryCell(double &x0, double &y0, double &z0, double &x1, double &y1, double &z1) override
Get the coordinates of the elementary cell.
void SetPeriodicityPhi(const double phi)
Set the periodicity [degree] in phi.
bool GetPeriodicityPhi(double &s)
Get the periodicity [degree] in phi.
bool GetPlanePhi(const unsigned int i, double &phi, double &voltage, std::string &label) const
Retrieve the parameters of a plane at constant phi.
void AddStripOnPlaneY(const char direction, const double y, const double smin, const double smax, const std::string &label, const double gap=-1.)
Add a strip in the x or z direction on an existing plane at constant y.
bool GetBoundingBox(double &x0, double &y0, double &z0, double &x1, double &y1, double &z1) override
Get the bounding box coordinates.
bool ForcesOnWire(const unsigned int iw, std::vector< double > &xMap, std::vector< double > &yMap, std::vector< std::vector< double > > &fxMap, std::vector< std::vector< double > > &fyMap)
void SetScanningAreaFirstOrder(const double scale=2.)
bool IsWireCrossed(const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, double &xc, double &yc, double &zc, const bool centre, double &rc) override
void AddReadout(const std::string &label)
Setup the weighting field for a given group of wires or planes.
void AddPixelOnPlaneY(const double y, const double xmin, const double xmax, const double zmin, const double zmax, const std::string &label, const double gap=-1., const double rot=0.)
Add a pixel on an existing plane at constant y.
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).
unsigned int GetNumberOfPlanesPhi() const
Get the number of equipotential planes at constant phi.
void AddStripOnPlaneR(const char direction, const double r, const double smin, const double smax, const std::string &label, const double gap=-1.)
Add a strip in the phi or z direction on an existing plane at constant radius.
void PrintCharges() const
Print a list of the point charges.
void SetScanningArea(const double xmin, const double xmax, const double ymin, const double ymax)
bool GetPlaneY(const unsigned int i, double &y, double &voltage, std::string &label) const
Retrieve the parameters of a plane at constant y.
unsigned int GetNumberOfPlanesR() const
Get the number of equipotential planes at constant radius.
void AddStripOnPlanePhi(const char direction, const double phi, const double smin, const double smax, const std::string &label, const double gap=-1.)
Add a strip in the r or z direction on an existing plane at constant phi.
Abstract base class for components.
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.
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.
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
virtual bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)=0
Get the bounding box (envelope of the geometry).
virtual Medium * GetMedium(const double x, const double y, const double z, const bool tesselated=false) const =0
Retrieve the medium at a given point.
Abstract base class for media.
static std::string FindUnusedCanvasName(const std::string &s)
Find an unused canvas name.
int deqn(const int n, std::vector< std::vector< double > > &a, std::vector< double > &b)
int cinv(const int n, std::vector< std::vector< std::complex< double > > > &a)
Replace square matrix A by its inverse.
int deqinv(const int n, std::vector< std::vector< double > > &a, std::vector< double > &b)
Replaces b by the solution x of Ax = b, and replace A by its inverse.
double BesselK0L(const double xx)
double Legendre(const unsigned int n, const double x)
Legendre polynomials.
double BesselK1S(const double xx)
bool LeastSquaresFit(std::function< double(double, const std::vector< double > &)> f, std::vector< double > &par, std::vector< double > &epar, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &ey, const unsigned int nMaxIter, const double diff, double &chi2, const double eps, const bool debug, const bool verbose)
Least-squares minimisation.
double Divdif(const std::vector< double > &f, const std::vector< double > &a, int nn, double x, int mm)
double BesselK0S(const double xx)
double BesselK1L(const double xx)
DoubleAc cos(const DoubleAc &f)
DoubleAc pow(const DoubleAc &f, double p)
DoubleAc exp(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
DoubleAc sin(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)