17constexpr double Internal2Newton = 1.e-15 * Garfield::TwoPiEpsilon0 * 100.;
19std::pair<std::complex<double>, std::complex<double> > Th1(
20 const std::complex<double>& zeta,
const double p1,
const double p2) {
21 const std::complex<double> zsin =
sin(zeta);
22 const std::complex<double> zcof = 4. * zsin * zsin - 2.;
23 std::complex<double> zu = -p1 - zcof * p2;
24 std::complex<double> zunew = 1. - zcof * zu - p2;
25 const std::complex<double> zterm1 = (zunew + zu) * zsin;
26 zu = -3. * p1 - zcof * 5. * p2;
27 zunew = 1. - zcof * zu - 5. * p2;
28 const std::complex<double> zterm2 = (zunew - zu) *
cos(zeta);
29 return std::make_pair(std::move(zterm1), std::move(zterm2));
33void Cartesian2Polar(
const double x,
const double y,
double& r,
35 if (x == 0. && y == 0.) {
39 r =
sqrt(x * x + y * y);
40 theta = atan2(y, x) * Garfield::RadToDegree;
44void Polar2Cartesian(
const double r,
const double theta,
double& x,
46 const double thetap =
theta * Garfield::DegreeToRad;
53void Internal2Polar(
const double rho,
const double phi,
double& r,
62void Polar2Internal(
const double r,
const double theta,
double& rho,
65 rho = r > 0. ? log(r) : -25.;
71void Cartesian2Internal(
const double x,
const double y,
double& rho,
74 if (x == 0 && y == 0) {
82 rho = 0.5 * log(x * x + y * y);
88void Internal2Cartesian(
const double rho,
const double phi,
double& x,
94 const double r =
exp(rho);
99bool FitDipoleMoment(
const std::vector<double>& angle,
100 const std::vector<double>& volt,
101 double& ampdip,
double& phidip,
const bool dbg) {
109 const unsigned int n = angle.size();
113 constexpr unsigned int nTry = 100;
114 std::array<double, nTry> phiTry;
115 std::array<double, nTry> sumTry;
116 for (
unsigned int i = 0; i < nTry; ++i) {
118 phiTry[i] = i * Garfield::TwoPi / nTry;
120 for (
unsigned int j = 0; j < n; ++j) {
121 sumTry[i] += volt[j] *
cos(phiTry[i] - angle[j]);
125 if (sumTry[i] > sumMax) {
131 std::printf(
" Maximum of scan at phi = %12.5f, product = %12.5f\n",
139 constexpr double eps = 0.1;
140 double x1 = phiMax - eps;
142 double x3 = phiMax + eps;
146 for (
unsigned int j = 0; j < n; ++j) {
147 f1 += volt[j] *
cos(x1 - angle[j]);
148 f3 += volt[j] *
cos(x3 - angle[j]);
153 const double epsf = 1.e-3 * sumMax;
154 constexpr double epsx = 1.e-3 * Garfield::TwoPi;
155 constexpr unsigned int nMaxIter = 10;
156 for (
unsigned int i = 0; i < nMaxIter; ++i) {
157 if (dbg) std::cout <<
" Start of iteration " << i <<
".\n";
159 const double det = (f1 - f2) * x3 + (f3 - f1) * x2 + (f2 - f3) * x1;
160 if (std::abs(det) <= 0.) {
161 std::cerr <<
" Warning: Determinant = 0; parabolic search stopped.\n";
166 const double xp = ((f1 - f2) * x3 * x3 + (f3 - f1) * x2 * x2 +
167 (f2 - f3) * x1 * x1) / (2 * det);
169 for (
unsigned int j = 0; j < n; ++j) {
170 fp += volt[j] *
cos(xp - angle[j]);
175 std::printf(
" Point 1: x = %15.8f f = %15.8f\n", x1, f1);
176 std::printf(
" Point 2: x = %15.8f f = %15.8f\n", x2, f2);
177 std::printf(
" Point 3: x = %15.8f f = %15.8f\n", x3, f3);
178 std::printf(
" Parabola: x = %15.8f f = %15.8f\n", xp, fp);
181 const double tol = epsx * (epsx + std::abs(xp));
182 if (
fabs(xp - x1) < tol ||
fabs(xp - x2) < tol ||
fabs(xp - x3) < tol) {
184 std::cout <<
" Location convergence criterion satisfied.\n";
191 if (std::abs(fp - f1) < epsf * (std::abs(fp) + std::abs(f1) + epsf)) {
193 std::cout <<
" Function value convergence criterion satisfied.\n";
207 }
else if (fp > f2) {
212 }
else if (fp > f3) {
216 std::cerr <<
" Warning: Parabolic extremum is worse "
217 <<
"than current optimum; search stopped.\n";
218 std::printf(
" Point 1: x = %15.8f f = %15.8f\n", x1, f1);
219 std::printf(
" Point 2: x = %15.8f f = %15.8f\n", x2, f2);
220 std::printf(
" Point 3: x = %15.8f f = %15.8f\n", x3, f3);
221 std::printf(
" Parabola: x = %15.8f f = %15.8f\n", xp, fp);
228 std::cerr <<
" Warning: No convergence after maximum number of steps.\n"
229 <<
" Current extremum f = " << f2 <<
"\n"
230 <<
" Found for x = " << x2 <<
"\n";
250 if (!m_cellset && !Prepare())
return nullptr;
252 double xpos = xin, ypos = yin;
253 if (m_polar) Cartesian2Internal(xin, yin, xpos, ypos);
256 xpos -= m_sx * int(round(xin / m_sx));
259 if (m_pery && m_tube) {
260 Cartesian2Polar(xin, yin, xpos, ypos);
261 arot = RadToDegree * m_sy * int(round(DegreeToRad * ypos / m_sy));
263 Polar2Cartesian(xpos, ypos, xpos, ypos);
265 ypos -= m_sy * int(round(ypos / m_sy));
269 if (m_perx && m_ynplan[0] && xpos <= m_coplan[0]) xpos += m_sx;
270 if (m_perx && m_ynplan[1] && xpos >= m_coplan[1]) xpos -= m_sx;
271 if (m_pery && m_ynplan[2] && ypos <= m_coplan[2]) ypos += m_sy;
272 if (m_pery && m_ynplan[3] && ypos >= m_coplan[3]) ypos -= m_sy;
276 if (!InTube(xpos, ypos, m_cotube, m_ntube))
return nullptr;
278 if ((m_ynplan[0] && xpos < m_coplan[0]) ||
279 (m_ynplan[1] && xpos > m_coplan[1]) ||
280 (m_ynplan[2] && ypos < m_coplan[2]) ||
281 (m_ynplan[3] && ypos > m_coplan[3])) {
287 for (
const auto& wire : m_w) {
288 double dx = xpos - wire.x;
289 double dy = ypos - wire.y;
291 if (m_perx) dx -= m_sx * int(round(dx / m_sx));
292 if (m_pery) dy -= m_sy * int(round(dy / m_sy));
294 if (dx * dx + dy * dy < wire.r * wire.r)
return nullptr;
301 if (!m_cellset && !Prepare()) {
302 std::cerr <<
m_className <<
"::GetVoltageRange: Cell not set up.\n";
312 double& x1,
double& y1,
319 if (!m_cellset && !Prepare())
return false;
321 double rmax, thetamax;
322 Internal2Polar(m_xmax, m_ymax, rmax, thetamax);
344 if (!m_cellset && !Prepare()) {
345 std::cerr <<
m_className <<
"::PrintCell: Cell not set up.\n";
349 <<
"::PrintCell: Cell identification: " <<
GetCellType() <<
"\n";
352 std::cout <<
" Table of the wires\n";
354 std::cout <<
" Nr Diameter r phi Voltage";
356 std::cout <<
" Nr Diameter x y Voltage";
358 std::cout <<
" Charge Tension Length Density Label\n";
360 std::cout <<
" [micron] [cm] [deg] [Volt]";
362 std::cout <<
" [micron] [cm] [cm] [Volt]";
364 std::cout <<
" [pC/cm] [g] [cm] [g/cm3]\n";
365 for (
unsigned int i = 0; i < m_nWires; ++i) {
366 const auto& w = m_w[i];
371 Internal2Polar(w.x, w.y, xw, yw);
375 "%4d %9.2f %9.4f %9.4f %9.3f %12.4f %9.2f %9.2f %9.2f \"%s\"\n", i,
376 1.e4 * dw, xw, yw, w.v, w.e * TwoPiEpsilon0 * 1.e-3, w.tension,
377 w.u, w.density, w.type.c_str());
385 }
else if (m_ntube == 3) {
386 shape =
"Triangular";
387 }
else if (m_ntube == 4) {
389 }
else if (m_ntube == 5) {
390 shape =
"Pentagonal";
391 }
else if (m_ntube == 6) {
393 }
else if (m_ntube == 7) {
394 shape =
"Heptagonal";
395 }
else if (m_ntube == 8) {
398 shape =
"Polygonal with " + std::to_string(m_ntube) +
" corners";
400 std::cout <<
" Enclosing tube\n"
401 <<
" Potential: " << m_vttube <<
" V\n"
402 <<
" Radius: " << m_cotube <<
" cm\n"
403 <<
" Shape: " << shape <<
"\n"
404 <<
" Label: " << m_planes[4].type <<
"\n";
407 if (m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3]) {
408 std::cout <<
" Equipotential planes\n";
410 const std::string xr = m_polar ?
"r" :
"x";
411 if (m_ynplan[0] && m_ynplan[1]) {
412 std::cout <<
" There are two planes at constant " << xr <<
":\n";
413 }
else if (m_ynplan[0] || m_ynplan[1]) {
414 std::cout <<
" There is one plane at constant " << xr <<
":\n";
416 for (
unsigned int i = 0; i < 2; ++i) {
417 if (!m_ynplan[i])
continue;
419 std::cout <<
" r = " << exp(m_coplan[i]) <<
" cm, ";
421 std::cout <<
" x = " << m_coplan[i] <<
" cm, ";
423 if (fabs(m_vtplan[i]) > 1.e-4) {
424 std::cout <<
"potential = " << m_vtplan[i] <<
" V, ";
426 std::cout <<
"earthed, ";
428 const auto& plane = m_planes[i];
429 if (plane.type.empty() && plane.type !=
"?") {
430 std::cout <<
"label = " << plane.type <<
", ";
432 const unsigned int nStrips = plane.strips1.size() + plane.strips2.size();
433 const unsigned int nPixels = plane.pixels.size();
434 if (nStrips == 0 && nPixels == 0) {
435 std::cout <<
"no strips or pixels.\n";
436 }
else if (nPixels == 0) {
437 std::cout << nStrips <<
" strips.\n";
438 }
else if (nStrips == 0) {
439 std::cout << nPixels <<
" pixels.\n";
441 std::cout << nStrips <<
" strips, " << nPixels <<
" pixels.\n";
443 for (
const auto& strip : plane.strips2) {
446 double gap = i == 0 ? expm1(strip.gap) : -expm1(-strip.gap);
447 gap *= exp(m_coplan[i]);
448 std::cout << RadToDegree * strip.smin <<
" < phi < "
449 << RadToDegree * strip.smax
450 <<
" degrees, gap = " << gap <<
" cm";
452 std::cout << strip.smin <<
" < y < " << strip.smax
453 <<
" cm, gap = " << strip.gap <<
" cm";
455 if (!strip.type.empty() && strip.type !=
"?") {
456 std::cout <<
" (\"" << strip.type <<
"\")";
460 for (
const auto& strip : plane.strips1) {
461 std::cout <<
" " << strip.smin <<
" < z < " << strip.smax;
463 double gap = i == 0 ? expm1(strip.gap) : -expm1(-strip.gap);
464 gap *= exp(m_coplan[i]);
465 std::cout <<
" cm, gap = " << gap <<
" cm";
467 std::cout <<
" cm, gap = " << strip.gap <<
" cm";
469 if (!strip.type.empty() && strip.type !=
"?") {
470 std::cout <<
" (\"" << strip.type <<
"\")";
474 for (
const auto& pix : plane.pixels) {
477 std::cout << RadToDegree * pix.smin <<
" < phi < "
478 << RadToDegree * pix.smax <<
" degrees, ";
480 std::cout << pix.smin <<
" < y < " << pix.smax <<
" cm, ";
482 std::cout << pix.zmin <<
" < z < " << pix.zmax <<
" cm, gap = ";
484 double gap = i == 0 ? expm1(pix.gap) : -expm1(-pix.gap);
485 gap *= exp(m_coplan[i]);
486 std::cout << gap <<
" cm";
488 std::cout << pix.gap <<
" cm";
490 if (!pix.type.empty() && pix.type !=
"?") {
491 std::cout <<
" (\"" << pix.type <<
"\")";
497 const std::string yphi = m_polar ?
"phi" :
"y";
498 if (m_ynplan[2] && m_ynplan[3]) {
499 std::cout <<
" There are two planes at constant " << yphi <<
":\n";
500 }
else if (m_ynplan[2] || m_ynplan[3]) {
501 std::cout <<
" There is one plane at constant " << yphi <<
":\n";
503 for (
unsigned int i = 2; i < 4; ++i) {
504 if (!m_ynplan[i])
continue;
506 std::cout <<
" phi = " << RadToDegree * m_coplan[i] <<
" degrees, ";
508 std::cout <<
" y = " << m_coplan[i] <<
" cm, ";
510 if (fabs(m_vtplan[i]) > 1.e-4) {
511 std::cout <<
"potential = " << m_vtplan[i] <<
" V, ";
513 std::cout <<
"earthed, ";
515 const auto& plane = m_planes[i];
516 if (plane.type.empty() && plane.type !=
"?") {
517 std::cout <<
"label = " << plane.type <<
", ";
519 const unsigned int nStrips = plane.strips1.size() + plane.strips2.size();
520 const unsigned int nPixels = plane.pixels.size();
521 if (nStrips == 0 && nPixels == 0) {
522 std::cout <<
"no strips or pixels.\n";
523 }
else if (nPixels == 0) {
524 std::cout << nStrips <<
" strips.\n";
525 }
else if (nStrips == 0) {
526 std::cout << nPixels <<
" pixels.\n";
528 std::cout << nStrips <<
" strips, " << nPixels <<
" pixels.\n";
530 for (
const auto& strip : plane.strips2) {
533 std::cout << exp(strip.smin) <<
" < r < " << exp(strip.smax)
534 <<
" cm, gap = " << RadToDegree * strip.gap <<
" degrees";
536 std::cout << strip.smin <<
" < x < " << strip.smax
537 <<
" cm, gap = " << strip.gap <<
" cm";
539 if (!strip.type.empty() && strip.type !=
"?") {
540 std::cout <<
" (\"" << strip.type <<
"\")";
544 for (
const auto& strip : plane.strips1) {
545 std::cout <<
" " << strip.smin <<
" < z < " << strip.smax;
547 std::cout <<
" cm, gap = " << RadToDegree * strip.gap <<
" degrees";
549 std::cout <<
" cm, gap = " << strip.gap <<
" cm";
551 if (!strip.type.empty() && strip.type !=
"?") {
552 std::cout <<
" (\"" << strip.type <<
"\")";
556 for (
const auto& pix : plane.pixels) {
559 std::cout << exp(pix.smin) <<
" < r < " << exp(pix.smax) <<
" cm, ";
561 std::cout << pix.smin <<
" < x < " << pix.smax <<
" cm, ";
563 std::cout << pix.zmin <<
" < z < " << pix.zmax <<
" cm, gap = ";
565 std::cout << RadToDegree * pix.gap <<
" degrees";
567 std::cout << pix.gap <<
" cm";
569 if (!pix.type.empty() && pix.type !=
"?") {
570 std::cout <<
" (\"" << pix.type <<
"\")";
577 std::cout <<
" Periodicity\n";
579 std::cout <<
" The cell is repeated every ";
581 std::cout << exp(m_sx) <<
" cm in r.\n";
583 std::cout << m_sx <<
" cm in x.\n";
587 std::cout <<
" The cell is not periodic in r.\n";
589 std::cout <<
" The cell has no translation periodicity in x.\n";
593 std::cout <<
" The cell is repeated every ";
595 std::cout << RadToDegree * m_sy <<
" degrees in phi.\n";
597 std::cout << m_sy <<
" cm in y.\n";
601 std::cout <<
" The cell is not periodic in phi.\n";
603 std::cout <<
" The cell has no translation periodicity in y.\n";
606 std::cout <<
" Other data\n";
607 std::cout <<
" Gravity vector: (" << m_down[0] <<
", " << m_down[1]
608 <<
", " << m_down[2] <<
") [g].\n";
609 std::cout <<
" Cell dimensions:\n ";
611 std::cout << m_xmin <<
" < x < " << m_xmax <<
" cm, " << m_ymin <<
" < y < "
612 << m_ymax <<
" cm.\n";
615 Internal2Polar(m_xmin, m_ymin, xminp, yminp);
617 Internal2Polar(m_xmax, m_ymax, xmaxp, ymaxp);
618 std::cout << xminp <<
" < r < " << xmaxp <<
" cm, " << yminp <<
" < phi < "
619 << ymaxp <<
" degrees.\n";
621 std::cout <<
" Potential range:\n " << m_vmin <<
" < V < " << m_vmax
624 if (!(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3] || m_tube)) {
625 std::cout <<
" All voltages have been shifted by " << m_v0
626 <<
" V to avoid net wire charge.\n";
630 for (
const auto& w : m_w) sum += w.e;
631 std::cout <<
" The net charge on the wires is "
632 << 1.e-3 * TwoPiEpsilon0 * sum <<
" pC/cm.\n";
637 const double z0,
const double xx1,
638 const double yy1,
const double z1,
639 double& xc,
double& yc,
double& zc,
640 const bool centre,
double& rc) {
645 if (m_w.empty())
return false;
652 Cartesian2Internal(xx0, yy0, x0, y0);
653 Cartesian2Internal(xx1, yy1, x1, y1);
655 const double dx = x1 - x0;
656 const double dy = y1 - y0;
657 const double d2 = dx * dx + dy * dy;
659 if (d2 < Small)
return false;
660 const double invd2 = 1. / d2;
663 if ((m_perx && fabs(dx) >= m_sx) || (m_pery && fabs(dy) >= m_sy)) {
665 <<
" Particle crossed more than one period.\n";
673 const double xm = 0.5 * (x0 + x1);
674 const double ym = 0.5 * (y0 + y1);
676 for (
const auto& wire : m_w) {
679 xw += m_sx * int(round((xm - xw) / m_sx));
683 yw += m_sy * int(round((ym - yw) / m_sy));
686 const double xIn0 = dx * (xw - x0) + dy * (yw - y0);
688 if (xIn0 < 0.)
continue;
689 const double xIn1 = -(dx * (xw - x1) + dy * (yw - y1));
691 if (xIn1 < 0.)
continue;
693 const double xw0 = xw - x0;
694 const double xw1 = xw - x1;
695 const double yw0 = yw - y0;
696 const double yw1 = yw - y1;
697 const double dw02 = xw0 * xw0 + yw0 * yw0;
698 const double dw12 = xw1 * xw1 + yw1 * yw1;
699 if (xIn1 * xIn1 * dw02 > xIn0 * xIn0 * dw12) {
700 dMin2 = dw02 - xIn0 * xIn0 * invd2;
702 dMin2 = dw12 - xIn1 * xIn1 * invd2;
705 const double r2 = wire.r * wire.r;
710 Internal2Cartesian(xw, yw, xc, yc);
717 const double p = -xIn0 * invd2;
718 const double q = (dw02 - r2) * invd2;
719 const double s = sqrt(p * p - q);
720 const double t = std::min(-p + s, -p - s);
722 Internal2Cartesian(x0 + t * dx, y0 + t * dy, xc, yc);
727 zc = z0 + t * (z1 - z0);
730 if (m_polar) rc *= exp(wire.x);
738 const double yin,
const double zin,
739 double& xw,
double& yw,
745 Cartesian2Internal(xin, yin, x0, y0);
748 int nX = 0, nY = 0, nPhi = 0;
750 nX = int(round(x0 / m_sx));
753 if (m_pery && m_tube) {
754 Cartesian2Polar(xin, yin, x0, y0);
755 nPhi = int(round(DegreeToRad * y0 / m_sy));
756 y0 -= RadToDegree * m_sy * nPhi;
757 Polar2Cartesian(x0, y0, x0, y0);
759 nY = int(round(y0 / m_sy));
763 std::array<bool, 4> shift = {
false,
false,
false,
false};
764 if (m_perx && m_ynplan[0] && x0 <= m_coplan[0]) {
768 if (m_perx && m_ynplan[1] && x0 >= m_coplan[1]) {
772 if (m_pery && m_ynplan[2] && y0 <= m_coplan[2]) {
776 if (m_pery && m_ynplan[3] && y0 >= m_coplan[3]) {
781 for (
const auto& wire : m_w) {
783 if (qin * wire.e > 0.)
continue;
784 const double dxw0 = wire.x - x0;
785 const double dyw0 = wire.y - y0;
786 const double r2 = dxw0 * dxw0 + dyw0 * dyw0;
787 const double rTrap = wire.r * wire.nTrap;
788 if (r2 < rTrap * rTrap) {
792 if (shift[0]) xw -= m_sx;
793 if (shift[1]) xw += m_sx;
794 if (shift[2]) yw -= m_sy;
795 if (shift[3]) yw += m_sy;
796 if (m_pery && m_tube) {
798 Cartesian2Polar(xw, yw, rhow, phiw);
799 phiw += RadToDegree * m_sy * nPhi;
800 Polar2Cartesian(rhow, phiw, xw, yw);
804 if (m_perx) xw += m_sx * nX;
806 Internal2Cartesian(xw, yw, xw, yw);
810 std::cout <<
m_className <<
"::IsInTrapRadius: (" << xin <<
", "
811 << yin <<
", " << zin <<
")" <<
" within trap radius.\n";
821 const double diameter,
822 const double voltage,
823 const std::string& label,
824 const double length,
const double tension,
825 double rho,
const int ntrap) {
827 if (diameter <= 0.) {
828 std::cerr <<
m_className <<
"::AddWire: Unphysical wire diameter.\n";
833 std::cerr <<
m_className <<
"::AddWire: Unphysical wire tension.\n";
838 std::cerr <<
m_className <<
"::AddWire: Unphysical wire density.\n";
843 std::cerr <<
m_className <<
"::AddWire: Unphysical wire length.\n";
848 std::cerr <<
m_className <<
"::AddWire: Nbr. of trap radii must be > 0.\n";
852 if (m_polar && x <= diameter) {
853 std::cerr <<
m_className <<
"::AddWire: Wire is too close to the origin.\n";
860 double r = 0., phi = 0.;
861 Polar2Internal(x, y, r, phi);
864 wire.r = 0.5 * diameter / x;
868 wire.r = 0.5 * diameter;
876 wire.tension = tension;
879 m_w.push_back(std::move(wire));
889 const std::string& label) {
892 std::cerr <<
m_className <<
"::AddTube: Unphysical tube dimension.\n";
896 if (nEdges < 3 && nEdges != 0) {
897 std::cerr <<
m_className <<
"::AddTube: Unphysical number of tube edges ("
905 <<
" Warning: Existing tube settings will be overwritten.\n";
914 m_cotube2 = radius * radius;
919 m_planes[4].type = label;
920 m_planes[4].ind = -1;
928 const std::string& label) {
931 <<
" Not compatible with polar coordinates; ignored.\n";
934 if (m_ynplan[0] && m_ynplan[1]) {
936 <<
" Cannot have more than two planes at constant x.\n";
944 m_planes[1].type = label;
945 m_planes[1].ind = -1;
950 m_planes[0].type = label;
951 m_planes[0].ind = -1;
960 const std::string& label) {
963 <<
" Not compatible with polar coordinates; ignored.\n";
966 if (m_ynplan[2] && m_ynplan[3]) {
968 <<
" Cannot have more than two planes at constant y.\n";
976 m_planes[3].type = label;
977 m_planes[3].ind = -1;
982 m_planes[2].type = label;
983 m_planes[2].ind = -1;
992 const std::string& label) {
995 <<
" Not compatible with Cartesian coordinates; ignored.\n";
1000 <<
" Radius must be larger than zero; plane ignored.\n";
1004 if (m_ynplan[0] && m_ynplan[1]) {
1006 <<
" Cannot have more than two circular planes.\n";
1012 m_coplan[1] = log(r);
1014 m_planes[1].type = label;
1015 m_planes[1].ind = -1;
1018 m_coplan[0] = log(r);
1020 m_planes[0].type = label;
1021 m_planes[0].ind = -1;
1030 const std::string& label) {
1033 <<
" Not compatible with Cartesian coordinates; ignored.\n";
1036 if (m_ynplan[2] && m_ynplan[3]) {
1038 <<
" Cannot have more than two planes at constant phi.\n";
1044 m_coplan[3] = phi * DegreeToRad;
1046 m_planes[3].type = label;
1047 m_planes[3].ind = -1;
1050 m_coplan[2] = phi * DegreeToRad;
1052 m_planes[2].type = label;
1053 m_planes[2].ind = -1;
1055 if (m_pery && std::abs(m_sy - TwoPi) < 1.e-4) {
1068 const std::string& label,
1070 if (m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1071 std::cerr <<
m_className <<
"::AddStripOnPlaneX:\n"
1072 <<
" There are no planes at constant x.\n";
1076 if (dir !=
'y' && dir !=
'Y' && dir !=
'z' && dir !=
'Z') {
1077 std::cerr <<
m_className <<
"::AddStripOnPlaneX:\n"
1078 <<
" Invalid direction (" << dir <<
").\n"
1079 <<
" Only strips in y or z direction are possible.\n";
1083 if (fabs(smax - smin) < Small) {
1084 std::cerr <<
m_className <<
"::AddStripOnPlaneX:\n"
1085 <<
" Strip width must be greater than zero.\n";
1090 newStrip.type = label;
1092 newStrip.smin = std::min(smin, smax);
1093 newStrip.smax = std::max(smin, smax);
1094 newStrip.gap = gap > Small ? gap : -1.;
1098 const double d0 = fabs(m_coplan[0] - x);
1099 const double d1 = fabs(m_coplan[1] - x);
1100 if (d1 < d0) iplane = 1;
1103 if (dir ==
'y' || dir ==
'Y') {
1104 m_planes[iplane].strips1.push_back(std::move(newStrip));
1106 m_planes[iplane].strips2.push_back(std::move(newStrip));
1113 const std::string& label,
1115 if (m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1116 std::cerr <<
m_className <<
"::AddStripOnPlaneY:\n"
1117 <<
" There are no planes at constant y.\n";
1121 if (dir !=
'x' && dir !=
'X' && dir !=
'z' && dir !=
'Z') {
1122 std::cerr <<
m_className <<
"::AddStripOnPlaneY:\n"
1123 <<
" Invalid direction (" << dir <<
").\n"
1124 <<
" Only strips in x or z direction are possible.\n";
1128 if (fabs(smax - smin) < Small) {
1129 std::cerr <<
m_className <<
"::AddStripOnPlaneY:\n"
1130 <<
" Strip width must be greater than zero.\n";
1135 newStrip.type = label;
1137 newStrip.smin = std::min(smin, smax);
1138 newStrip.smax = std::max(smin, smax);
1139 newStrip.gap = gap > Small ? gap : -1.;
1143 const double d2 = fabs(m_coplan[2] - y);
1144 const double d3 = fabs(m_coplan[3] - y);
1145 if (d3 < d2) iplane = 3;
1148 if (dir ==
'x' || dir ==
'X') {
1149 m_planes[iplane].strips1.push_back(std::move(newStrip));
1151 m_planes[iplane].strips2.push_back(std::move(newStrip));
1158 const std::string& label,
1160 if (!m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1161 std::cerr <<
m_className <<
"::AddStripOnPlaneR:\n"
1162 <<
" There are no planes at constant r.\n";
1166 if (dir !=
'p' && dir !=
'P' && dir !=
'z' && dir !=
'Z') {
1167 std::cerr <<
m_className <<
"::AddStripOnPlaneR:\n"
1168 <<
" Invalid direction (" << dir <<
").\n"
1169 <<
" Only strips in p(hi) or z direction are possible.\n";
1173 if (fabs(smax - smin) < Small) {
1174 std::cerr <<
m_className <<
"::AddStripOnPlaneR:\n"
1175 <<
" Strip width must be greater than zero.\n";
1180 newStrip.type = label;
1182 if (dir ==
'z' || dir ==
'Z') {
1183 const double phimin = smin * DegreeToRad;
1184 const double phimax = smax * DegreeToRad;
1185 newStrip.smin = std::min(phimin, phimax);
1186 newStrip.smax = std::max(phimin, phimax);
1188 newStrip.smin = std::min(smin, smax);
1189 newStrip.smax = std::max(smin, smax);
1191 newStrip.gap = gap > Small ? gap : -1.;
1195 const double rho = r > 0. ? log(r) : -25.;
1196 const double d0 = fabs(m_coplan[0] - rho);
1197 const double d1 = fabs(m_coplan[1] - rho);
1198 if (d1 < d0) iplane = 1;
1201 if (dir ==
'p' || dir ==
'P') {
1202 m_planes[iplane].strips1.push_back(std::move(newStrip));
1204 m_planes[iplane].strips2.push_back(std::move(newStrip));
1212 const std::string& label,
1214 if (!m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1215 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1216 <<
" There are no planes at constant phi.\n";
1220 if (dir !=
'r' && dir !=
'R' && dir !=
'z' && dir !=
'Z') {
1221 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1222 <<
" Invalid direction (" << dir <<
").\n"
1223 <<
" Only strips in r or z direction are possible.\n";
1227 if (fabs(smax - smin) < Small) {
1228 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1229 <<
" Strip width must be greater than zero.\n";
1234 newStrip.type = label;
1236 if (dir==
'z' || dir ==
'Z') {
1237 if (smin < Small || smax < Small) {
1238 std::cerr <<
m_className <<
"::AddStripOnPlanePhi:\n"
1239 <<
" Radius must be greater than zero.\n";
1242 const double rhomin = log(smin);
1243 const double rhomax = log(smax);
1244 newStrip.smin = std::min(rhomin, rhomax);
1245 newStrip.smax = std::max(rhomin, rhomax);
1247 newStrip.smin = std::min(smin, smax);
1248 newStrip.smax = std::max(smin, smax);
1250 newStrip.gap = gap > Small ? DegreeToRad * gap : -1.;
1254 const double d2 = fabs(m_coplan[2] - phi * DegreeToRad);
1255 const double d3 = fabs(m_coplan[3] - phi * DegreeToRad);
1256 if (d3 < d2) iplane = 3;
1259 if (dir ==
'r' || dir ==
'R') {
1260 m_planes[iplane].strips1.push_back(std::move(newStrip));
1262 m_planes[iplane].strips2.push_back(std::move(newStrip));
1268 const double x,
const double ymin,
const double ymax,
const double zmin,
1269 const double zmax,
const std::string& label,
const double gap) {
1270 if (m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1271 std::cerr <<
m_className <<
"::AddPixelOnPlaneX:\n"
1272 <<
" There are no planes at constant x.\n";
1276 if (fabs(ymax - ymin) < Small || fabs(zmax - zmin) < Small) {
1277 std::cerr <<
m_className <<
"::AddPixelOnPlaneX:\n"
1278 <<
" Pixel width must be greater than zero.\n";
1283 newPixel.type = label;
1285 newPixel.smin = std::min(ymin, ymax);
1286 newPixel.smax = std::max(ymin, ymax);
1287 newPixel.zmin = std::min(zmin, zmax);
1288 newPixel.zmax = std::max(zmin, zmax);
1289 newPixel.gap = gap > Small ? gap : -1.;
1293 const double d0 = fabs(m_coplan[0] - x);
1294 const double d1 = fabs(m_coplan[1] - x);
1295 if (d1 < d0) iplane = 1;
1298 m_planes[iplane].pixels.push_back(std::move(newPixel));
1302 const double y,
const double xmin,
const double xmax,
const double zmin,
1303 const double zmax,
const std::string& label,
const double gap) {
1304 if (m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1305 std::cerr <<
m_className <<
"::AddPixelOnPlaneY:\n"
1306 <<
" There are no planes at constant y.\n";
1310 if (fabs(xmax - xmin) < Small || fabs(zmax - zmin) < Small) {
1311 std::cerr <<
m_className <<
"::AddPixelOnPlaneY:\n"
1312 <<
" Pixel width must be greater than zero.\n";
1317 newPixel.type = label;
1319 newPixel.smin = std::min(xmin, xmax);
1320 newPixel.smax = std::max(xmin, xmax);
1321 newPixel.zmin = std::min(zmin, zmax);
1322 newPixel.zmax = std::max(zmin, zmax);
1323 newPixel.gap = gap > Small ? gap : -1.;
1327 const double d0 = fabs(m_coplan[2] - y);
1328 const double d1 = fabs(m_coplan[3] - y);
1329 if (d1 < d0) iplane = 3;
1332 m_planes[iplane].pixels.push_back(std::move(newPixel));
1336 const double r,
const double phimin,
const double phimax,
1337 const double zmin,
const double zmax,
const std::string& label,
1339 if (!m_polar || (!m_ynplan[0] && !m_ynplan[1])) {
1340 std::cerr <<
m_className <<
"::AddPixelOnPlaneR:\n"
1341 <<
" There are no planes at constant r.\n";
1345 if (fabs(phimax - phimin) < Small || fabs(zmax - zmin) < Small) {
1346 std::cerr <<
m_className <<
"::AddPixelOnPlaneR:\n"
1347 <<
" Pixel width must be greater than zero.\n";
1352 newPixel.type = label;
1354 const double smin = phimin * DegreeToRad;
1355 const double smax = phimax * DegreeToRad;
1356 newPixel.smin = std::min(smin, smax);
1357 newPixel.smax = std::max(smin, smax);
1358 newPixel.zmin = std::min(zmin, zmax);
1359 newPixel.zmax = std::max(zmin, zmax);
1360 newPixel.gap = gap > Small ? gap : -1.;
1364 const double rho = r > 0. ? log(r) : -25.;
1365 const double d0 = fabs(m_coplan[0] - rho);
1366 const double d1 = fabs(m_coplan[1] - rho);
1367 if (d1 < d0) iplane = 1;
1370 m_planes[iplane].pixels.push_back(std::move(newPixel));
1374 const double phi,
const double rmin,
const double rmax,
1375 const double zmin,
const double zmax,
const std::string& label,
1377 if (!m_polar || (!m_ynplan[2] && !m_ynplan[3])) {
1378 std::cerr <<
m_className <<
"::AddPixelOnPlanePhi:\n"
1379 <<
" There are no planes at constant phi.\n";
1383 if (fabs(rmax - rmin) < Small || fabs(zmax - zmin) < Small) {
1384 std::cerr <<
m_className <<
"::AddPixelOnPlanePhi:\n"
1385 <<
" Pixel width must be greater than zero.\n";
1388 if (rmin < Small || rmax < Small) {
1389 std::cerr <<
m_className <<
"::AddPixelOnPlanePhi:\n"
1390 <<
" Radius must be greater than zero.\n";
1394 newPixel.type = label;
1396 const double smin = log(rmin);
1397 const double smax = log(rmax);
1398 newPixel.smin = std::min(smin, smax);
1399 newPixel.smax = std::max(smin, smax);
1400 newPixel.zmin = std::min(zmin, zmax);
1401 newPixel.zmax = std::max(zmin, zmax);
1402 newPixel.gap = gap > Small ? DegreeToRad * gap : -1.;
1406 const double d0 = fabs(m_coplan[2] - phi * DegreeToRad);
1407 const double d1 = fabs(m_coplan[3] - phi * DegreeToRad);
1408 if (d1 < d0) iplane = 3;
1411 m_planes[iplane].pixels.push_back(std::move(newPixel));
1423 std::cerr <<
m_className <<
"::SetPeriodicityX:\n"
1424 <<
" Cannot use x-periodicity with polar coordinates.\n";
1428 std::cerr <<
m_className <<
"::SetPeriodicityX:\n"
1429 <<
" Periodic length must be greater than zero.\n";
1435 UpdatePeriodicity();
1440 std::cerr <<
m_className <<
"::SetPeriodicityY:\n"
1441 <<
" Cannot use y-periodicity with polar coordinates.\n";
1445 std::cerr <<
m_className <<
"::SetPeriodicityY:\n"
1446 <<
" Periodic length must be greater than zero.\n";
1452 UpdatePeriodicity();
1456 if (!m_polar && !m_tube) {
1457 std::cerr <<
m_className <<
"::SetPeriodicityPhi:\n"
1458 <<
" Cannot use phi-periodicity with Cartesian coordinates.\n";
1461 if (std::abs(360. - s *
int(360. / s)) > 1.e-4) {
1462 std::cerr <<
m_className <<
"::SetPeriodicityPhi:\n"
1463 <<
" Phi periods must divide 360; ignored.\n";
1468 m_sy = DegreeToRad * s;
1469 m_mtube = int(360. / s);
1470 UpdatePeriodicity();
1494 if (!
m_periodic[1] || (!m_polar && !m_tube)) {
1499 s = RadToDegree * m_sy;
1503void ComponentAnalyticField::UpdatePeriodicity() {
1511 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n";
1512 std::cerr <<
" Periodicity in x direction was enabled"
1513 <<
" but periodic length is not set.\n";
1527 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n";
1528 std::cerr <<
" Periodicity in y direction was enabled"
1529 <<
" but periodic length is not set.\n";
1539 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1540 <<
" Periodicity in z is not possible.\n";
1544 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1545 <<
" Mirror periodicity is not possible.\n";
1549 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1550 <<
" Axial periodicity is not possible.\n";
1555 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1556 <<
" Rotation symmetry is not possible.\n";
1562 std::cout <<
m_className <<
"::SetCartesianCoordinates:\n "
1563 <<
"Switching to Cartesian coordinates; resetting the cell.\n";
1571 std::cout <<
m_className <<
"::SetPolarCoordinates:\n "
1572 <<
"Switching to polar coordinates; resetting the cell.\n";
1582 const double z,
const double q) {
1588 charge.e = q / FourPiEpsilon0;
1589 m_ch3d.push_back(std::move(charge));
1600 if (m_ch3d.empty()) {
1601 std::cout <<
" No charges present.\n";
1604 std::cout <<
" x [cm] y [cm] z [cm] charge [fC]\n";
1605 for (
const auto& charge : m_ch3d) {
1606 std::cout <<
" " << std::setw(9) << charge.x <<
" " << std::setw(9)
1607 << charge.y <<
" " << std::setw(9) << charge.z <<
" "
1608 << std::setw(11) << charge.e * FourPiEpsilon0 <<
"\n";
1615 }
else if (m_ynplan[0] && m_ynplan[1]) {
1617 }
else if (m_ynplan[0] || m_ynplan[1]) {
1626 }
else if (m_ynplan[2] && m_ynplan[3]) {
1628 }
else if (m_ynplan[2] || m_ynplan[3]) {
1637 }
else if (m_ynplan[0] && m_ynplan[1]) {
1639 }
else if (m_ynplan[0] || m_ynplan[1]) {
1648 }
else if (m_ynplan[2] && m_ynplan[3]) {
1650 }
else if (m_ynplan[2] || m_ynplan[3]) {
1657 double& diameter,
double& voltage,
1658 std::string& label,
double& length,
1659 double& charge,
int& ntrap)
const {
1660 if (i >= m_nWires) {
1661 std::cerr <<
m_className <<
"::GetWire: Index out of range.\n";
1666 double r = 0., theta = 0.;
1667 Internal2Polar(m_w[i].x, m_w[i].y, r, theta);
1670 diameter = 2 * m_w[i].r * r;
1674 diameter = 2 * m_w[i].r;
1677 label = m_w[i].type;
1680 ntrap = m_w[i].nTrap;
1686 std::string& label)
const {
1687 if (m_polar || i >= 2 || (i == 1 && !m_ynplan[1])) {
1688 std::cerr <<
m_className <<
"::GetPlaneX: Index out of range.\n";
1693 voltage = m_vtplan[i];
1694 label = m_planes[i].type;
1700 std::string& label)
const {
1701 if (m_polar || i >= 2 || (i == 1 && !m_ynplan[3])) {
1702 std::cerr <<
m_className <<
"::GetPlaneY: Index out of range.\n";
1706 y = m_coplan[i + 2];
1707 voltage = m_vtplan[i + 2];
1708 label = m_planes[i + 2].type;
1714 std::string& label)
const {
1715 if (!m_polar || i >= 2 || (i == 1 && !m_ynplan[1])) {
1716 std::cerr <<
m_className <<
"::GetPlaneR: Index out of range.\n";
1720 r = exp(m_coplan[i]);
1721 voltage = m_vtplan[i];
1722 label = m_planes[i].type;
1728 std::string& label)
const {
1729 if (!m_polar || i >= 2 || (i == 1 && !m_ynplan[3])) {
1730 std::cerr <<
m_className <<
"::GetPlanePhi: Index out of range.\n";
1734 phi = RadToDegree * m_coplan[i + 2];
1735 voltage = m_vtplan[i + 2];
1736 label = m_planes[i + 2].type;
1741 std::string& label)
const {
1742 if (!m_tube)
return false;
1746 label = m_planes[4].type;
1751 double& ex,
double& ey) {
1762 if (iw >= m_nWires) {
1763 std::cerr <<
m_className <<
"::ElectricFieldAtWire: Index out of range.\n";
1767 std::vector<bool> cnalso(m_nWires,
true);
1770 const double xpos = m_w[iw].x;
1771 const double ypos = m_w[iw].y;
1773 switch (m_cellType) {
1775 FieldAtWireA00(xpos, ypos, ex, ey, cnalso);
1778 FieldAtWireB1X(xpos, ypos, ex, ey, cnalso);
1781 FieldAtWireB1Y(xpos, ypos, ex, ey, cnalso);
1784 FieldAtWireB2X(xpos, ypos, ex, ey, cnalso);
1787 FieldAtWireB2Y(xpos, ypos, ex, ey, cnalso);
1790 FieldAtWireC10(xpos, ypos, ex, ey, cnalso);
1793 FieldAtWireC2X(xpos, ypos, ex, ey, cnalso);
1796 FieldAtWireC2Y(xpos, ypos, ex, ey, cnalso);
1799 FieldAtWireC30(xpos, ypos, ex, ey, cnalso);
1802 FieldAtWireD10(xpos, ypos, ex, ey, cnalso);
1805 FieldAtWireD20(xpos, ypos, ex, ey, cnalso);
1808 FieldAtWireD30(xpos, ypos, ex, ey, cnalso);
1811 std::cerr <<
m_className <<
"::ElectricFieldAtWire:\n"
1812 <<
" Unknown cell type (id " << m_cellType <<
")\n";
1820 const double r = exp(xpos);
1821 const double er = ex / r;
1822 const double ep = ey / r;
1823 const double ct = cos(ypos);
1824 const double st = sin(ypos);
1825 ex = +ct * er - st * ep;
1826 ey = +st * er + ct * ep;
1832 const unsigned int nY) {
1834 std::cerr <<
m_className <<
"::SetScanningGrid:\n"
1835 <<
" Number of x-lines must be > 1.\n";
1840 std::cerr <<
m_className <<
"::SetScanningGrid:\n"
1841 <<
" Number of y-lines must be > 1.\n";
1850 const double ymax) {
1851 if (std::abs(xmax - xmin) < Small || std::abs(ymax - ymin) < Small) {
1852 std::cerr <<
m_className <<
"::SetScanningArea:\n"
1853 <<
" Zero range not permitted.\n";
1856 m_scanRange = ScanningRange::User;
1857 m_xScanMin = std::min(xmin, xmax);
1858 m_xScanMax = std::max(xmin, xmax);
1859 m_yScanMin = std::min(ymin, ymax);
1860 m_yScanMax = std::max(ymin, ymax);
1864 m_scanRange = ScanningRange::FirstOrder;
1866 m_scaleRange = scale;
1868 std::cerr <<
m_className <<
"::SetScanningAreaFirstOrder:\n"
1869 <<
" Scaling factor must be > 0.\n";
1876 const double d = sqrt(dx * dx + dy * dy + dz * dz);
1883 <<
" The gravity vector has zero norm ; ignored.\n";
1896 const unsigned int iw, std::vector<double>& xMap, std::vector<double>& yMap,
1897 std::vector<std::vector<double> >& fxMap,
1898 std::vector<std::vector<double> >& fyMap) {
1899 if (!m_cellset && !Prepare()) {
1900 std::cerr <<
m_className <<
"::ForcesOnWire: Cell not set up.\n";
1904 if (iw >= m_nWires) {
1905 std::cerr <<
m_className <<
"::ForcesOnWire: Wire index out of range.\n";
1909 std::cerr <<
m_className <<
"::ForcesOnWire: Cannot handle polar cells.\n";
1912 const auto& wire = m_w[iw];
1914 double bxmin = m_perx ? wire.x - 0.5 * m_sx : 2 * m_xmin - m_xmax;
1915 double bxmax = m_perx ? wire.x + 0.5 * m_sx : 2 * m_xmax - m_xmin;
1916 double bymin = m_pery ? wire.y - 0.5 * m_sy : 2 * m_ymin - m_ymax;
1917 double bymax = m_pery ? wire.y + 0.5 * m_sy : 2 * m_ymax - m_ymin;
1920 if (std::abs(bxmax - bxmin) < 0.1 * std::abs(bymax - bymin)) {
1921 bxmin = wire.x - 0.5 * std::abs(bymax - bymin);
1922 bxmax = wire.x + 0.5 * std::abs(bymax - bymin);
1923 }
else if (std::abs(bymax - bymin) < 0.1 * std::abs(bxmax - bxmin)) {
1924 bymin = wire.y - 0.5 * std::abs(bxmax - bxmin);
1925 bymax = wire.y + 0.5 * std::abs(bxmax - bxmin);
1927 const double dw = 2 * wire.r;
1929 for (
unsigned int j = 0; j < m_nWires; ++j) {
1930 if (j == iw)
continue;
1931 const double xj = m_w[j].x;
1932 const double yj = m_w[j].y;
1933 const double dj = 2 * m_w[j].r;
1934 double xnear = m_perx ? xj - m_sx * int(round((xj - wire.x) / m_sx)) : xj;
1935 double ynear = m_pery ? yj - m_sy * int(round((yj - wire.y) / m_sy)) : yj;
1936 if (std::abs(xnear - wire.x) > std::abs(ynear - wire.y)) {
1937 if (xnear < wire.x) {
1938 bxmin = std::max(bxmin, xnear + dj + dw);
1939 if (m_perx) bxmax = std::min(bxmax, xnear + m_sx - dj - dw);
1941 bxmax = std::min(bxmax, xnear - dj - dw);
1942 if (m_perx) bxmin = std::max(bxmin, xnear - m_sx + dj + dw);
1945 if (ynear < wire.y) {
1946 bymin = std::max({bymin, ynear - dj - dw, ynear + dj + dw});
1947 if (m_pery) bymax = std::min(bymax, ynear + m_sy - dj - dw);
1949 bymax = std::min({bymax, ynear - dj - dw, ynear + dj + dw});
1950 if (m_pery) bymin = std::max(bymin, ynear - m_sy + dj + dw);
1955 if (m_ynplan[0]) bxmin = std::max(bxmin, m_coplan[0] + dw);
1956 if (m_ynplan[1]) bxmax = std::min(bxmax, m_coplan[1] - dw);
1957 if (m_ynplan[2]) bymin = std::max(bymin, m_coplan[2] + dw);
1958 if (m_ynplan[3]) bymax = std::min(bymax, m_coplan[3] - dw);
1962 const double d2 = m_cotube2 - dw * dw;
1964 std::cerr <<
m_className <<
"::ForcesOnWire:\n Diameter of wire " << iw
1965 <<
" is too large compared to the tube.\n";
1969 double corr = sqrt((bxmin * bxmin + bymin * bymin) / d2);
1974 corr = sqrt((bxmin * bxmin + bymax * bymax) / d2);
1979 corr = sqrt((bxmax * bxmax + bymin * bymin) / d2);
1984 corr = sqrt((bxmax * bxmax + bymax * bymax) / d2);
1991 if ((bxmin - wire.x) * (wire.x - bxmax) <= 0 ||
1992 (bymin - wire.y) * (wire.y - bymax) <= 0) {
1993 std::cerr <<
m_className <<
"::ForcesOnWire:\n Unable to find an area "
1994 <<
"free of elements around wire " << iw <<
".\n";
1998 double sxmin = bxmin;
1999 double sxmax = bxmax;
2000 double symin = bymin;
2001 double symax = bymax;
2002 if (m_scanRange == ScanningRange::User) {
2004 sxmin = wire.x + m_xScanMin;
2005 symin = wire.y + m_yScanMin;
2006 sxmax = wire.x + m_xScanMax;
2007 symax = wire.y + m_yScanMax;
2008 }
else if (m_scanRange == ScanningRange::FirstOrder) {
2010 double ex = 0., ey = 0.;
2012 double fx = -ex * wire.e * Internal2Newton;
2013 double fy = -ey * wire.e * Internal2Newton;
2014 if (m_useGravitationalForce) {
2016 const double m = 1.e-3 * wire.density * Pi * wire.r * wire.r;
2017 fx -= m_down[0] * GravitationalAcceleration * m;
2018 fy -= m_down[1] * GravitationalAcceleration * m;
2020 const double u2 = wire.u * wire.u;
2021 const double shiftx =
2022 -125 * fx * u2 / (GravitationalAcceleration * wire.tension);
2023 const double shifty =
2024 -125 * fy * u2 / (GravitationalAcceleration * wire.tension);
2026 const double tol = 0.1 * wire.r;
2027 if (std::abs(shiftx) > tol || std::abs(shifty) > tol) {
2028 sxmin = std::max(bxmin, std::min(wire.x + m_scaleRange * shiftx,
2029 wire.x - shiftx / m_scaleRange));
2030 symin = std::max(bymin, std::min(wire.y + m_scaleRange * shifty,
2031 wire.y - shifty / m_scaleRange));
2032 sxmax = std::min(bxmax, std::max(wire.x + m_scaleRange * shiftx,
2033 wire.x - shiftx / m_scaleRange));
2034 symax = std::min(bymax, std::max(wire.y + m_scaleRange * shifty,
2035 wire.y - shifty / m_scaleRange));
2037 if (std::abs(sxmax - sxmin) < 0.1 * std::abs(symax - symin)) {
2038 sxmin = std::max(bxmin, wire.x - 0.5 * std::abs(symax - symin));
2039 sxmax = std::min(bxmax, wire.x + 0.5 * std::abs(symax - symin));
2040 }
else if (std::abs(symax - symin) < 0.1 * std::abs(sxmax - sxmin)) {
2041 symin = std::max(bymin, wire.y - 0.5 * std::abs(sxmax - sxmin));
2042 symax = std::min(bymax, wire.y + 0.5 * std::abs(sxmax - sxmin));
2048 std::printf(
" Free area %12.5e < x < %12.5e\n", bxmin, bxmax);
2049 std::printf(
" %12.5e < y < %12.5e\n", bymin, bymax);
2050 std::printf(
" Scan area %12.5e < x < %12.5e\n", sxmin, sxmax);
2051 std::printf(
" %12.5e < y < %12.5e\n", symin, symax);
2054 xMap.resize(m_nScanX);
2055 const double stepx = (sxmax - sxmin) / (m_nScanX - 1);
2056 for (
unsigned int i = 0; i < m_nScanX; ++i) {
2057 xMap[i] = sxmin + i * stepx;
2059 yMap.resize(m_nScanY);
2060 const double stepy = (symax - symin) / (m_nScanY - 1);
2061 for (
unsigned int i = 0; i < m_nScanY; ++i) {
2062 yMap[i] = symin + i * stepy;
2065 const double x0 = wire.x;
2066 const double y0 = wire.y;
2068 fxMap.assign(m_nScanX, std::vector<double>(m_nScanY, 0.));
2069 fyMap.assign(m_nScanX, std::vector<double>(m_nScanY, 0.));
2071 for (
unsigned int i = 0; i < m_nScanX; ++i) {
2072 for (
unsigned int j = 0; j < m_nScanY; ++j) {
2074 m_w[iw].x = xMap[i];
2075 m_w[iw].y = yMap[j];
2078 std::cerr <<
m_className <<
"::ForcesOnWire: Wire " << iw <<
".\n"
2079 <<
" Scan involves a disallowed wire position.\n";
2085 std::cerr <<
m_className <<
"::ForcesOnWire: Wire " << iw <<
".\n"
2086 <<
" Failed to compute charges at a scan point.\n";
2091 double ex = 0., ey = 0.;
2093 fxMap[i][j] = -ex * wire.e * Internal2Newton;
2094 fyMap[i][j] = -ey * wire.e * Internal2Newton;
2106 std::cerr <<
m_className <<
"::SetNumberOfSteps:\n"
2107 <<
" Number of steps must be > 0.\n";
2114 const unsigned int iw,
const bool detailed, std::vector<double>& csag,
2115 std::vector<double>& xsag, std::vector<double>& ysag,
double& stretch,
2117 if (!m_cellset && !Prepare()) {
2118 std::cerr <<
m_className <<
"::WireDisplacement: Cell not set up.\n";
2121 if (iw >= m_nWires) {
2123 <<
"::WireDisplacement: Wire index out of range.\n";
2128 <<
"::WireDisplacement: Cannot handle polar cells.\n";
2131 const auto& wire = m_w[iw];
2133 const double x0 = wire.x;
2134 const double y0 = wire.y;
2137 std::cerr <<
m_className <<
"::WireDisplacement:\n"
2138 <<
" Charge calculation failed at central position.\n";
2142 double fx = 0., fy = 0.;
2143 if (m_useElectrostaticForce) {
2144 double ex = 0., ey = 0.;
2146 fx -= ex * wire.e * Internal2Newton;
2147 fy -= ey * wire.e * Internal2Newton;
2149 if (m_useGravitationalForce) {
2151 const double m = 1.e-3 * wire.density * Pi * wire.r * wire.r;
2152 fx -= m_down[0] * GravitationalAcceleration * m;
2153 fy -= m_down[1] * GravitationalAcceleration * m;
2155 const double u2 = wire.u * wire.u;
2156 const double shiftx =
2157 -125 * fx * u2 / (GravitationalAcceleration * wire.tension);
2158 const double shifty =
2159 -125 * fy * u2 / (GravitationalAcceleration * wire.tension);
2161 const double s = 4 * sqrt(shiftx * shiftx + shifty * shifty) / wire.u;
2162 double length = wire.u;
2164 const double t = sqrt(1 + s * s);
2165 length *= 0.5 * (t + log(s + t) / s);
2167 stretch = (length - wire.u) / wire.u;
2170 <<
"::WireDisplacement:\n"
2171 <<
" Forces and displacement in 0th order.\n"
2172 <<
" Wire information: number = " << iw <<
"\n"
2173 <<
" type = " << wire.type <<
"\n"
2174 <<
" location = (" << wire.x <<
", " << wire.y
2176 <<
" voltage = " << wire.v <<
" V\n"
2177 <<
" length = " << wire.u <<
" cm\n"
2178 <<
" tension = " << wire.tension <<
" g\n"
2179 <<
" In this position: Fx = " << fx <<
" N/cm\n"
2180 <<
" Fy = " << fy <<
" N/cm\n"
2181 <<
" x-shift = " << shiftx <<
" cm\n"
2182 <<
" y-shift = " << shifty <<
" cm\n"
2183 <<
" stretch = " << 100. * stretch <<
"%\n";
2191 std::vector<double> xMap(m_nScanX, 0.);
2192 std::vector<double> yMap(m_nScanY, 0.);
2193 std::vector<std::vector<double> > fxMap(m_nScanX,
2194 std::vector<double>(m_nScanY, 0.));
2195 std::vector<std::vector<double> > fyMap(m_nScanX,
2196 std::vector<double>(m_nScanY, 0.));
2198 std::cerr <<
m_className <<
"::WireDisplacement:\n"
2199 <<
" Could not compute the electrostatic force table.\n";
2203 if (!SagDetailed(wire, xMap, yMap, fxMap, fyMap, csag, xsag, ysag)) {
2204 std::cerr <<
m_className <<
"::WireDisplacement: Wire " << iw <<
".\n"
2205 <<
" Computation of the wire sag failed.\n";
2209 const double sxmin = xMap.front();
2210 const double sxmax = xMap.back();
2211 const double symin = yMap.front();
2212 const double symax = yMap.back();
2213 const unsigned int nSag = xsag.size();
2214 bool outside =
false;
2220 for (
unsigned int i = 0; i < nSag; ++i) {
2221 if (x0 + xsag[i] < sxmin || x0 + xsag[i] > sxmax || y0 + ysag[i] < symin ||
2222 y0 + ysag[i] > symax) {
2227 xMax = std::max(xMax, std::abs(xsag[i]));
2228 yMax = std::max(yMax, std::abs(ysag[i]));
2229 if (i == 0)
continue;
2230 const double dx = xsag[i] - xsag[i - 1];
2231 const double dy = ysag[i] - ysag[i - 1];
2232 const double dz = csag[i] - csag[i - 1];
2233 length += sqrt(dx * dx + dy * dy + dz * dz);
2237 stretch = (length - wire.u) / wire.u;
2241 <<
m_className <<
"::WireDisplacement: Warning.\n "
2242 <<
"The wire profile is located partially outside the scanning area.\n";
2245 std::cout <<
" Sag profile for wire " << iw <<
".\n"
2246 <<
" Point z [cm] x-sag [um] y-sag [um]\n";
2247 for (
unsigned int i = 0; i < nSag; ++i) {
2248 std::printf(
" %3d %10.4f %10.4f %10.4f\n",
2249 i, csag[i], xsag[i] * 1.e4, ysag[i] * 1.e4);
2251 std::printf(
" Average sag in x and y: %10.4f and %10.4f micron\n",
2252 1.e4 * xAvg, 1.e4 * yAvg);
2253 std::printf(
" Maximum sag in x and y: %10.4f and %10.4f micron\n",
2254 1.e4 * xMax, 1.e4 * yMax);
2255 std::cout <<
" Elongation: " << 100. * stretch <<
"%\n";
2260int ComponentAnalyticField::Field(
const double xin,
const double yin,
2261 const double zin,
double& ex,
double& ey,
2262 double& ez,
double& volt,
const bool opt) {
2282 ex = ey = ez = volt = 0.;
2285 if (!m_cellset && !Prepare())
return -11;
2287 double xpos = xin, ypos = yin;
2288 if (m_polar) Cartesian2Internal(xin, yin, xpos, ypos);
2291 xpos -= m_sx * int(round(xin / m_sx));
2294 if (m_pery && m_tube) {
2295 Cartesian2Polar(xin, yin, xpos, ypos);
2296 arot = RadToDegree * m_sy * int(round(DegreeToRad * ypos / m_sy));
2298 Polar2Cartesian(xpos, ypos, xpos, ypos);
2299 }
else if (m_pery) {
2300 ypos -= m_sy * int(round(ypos / m_sy));
2304 if (m_perx && m_ynplan[0] && xpos <= m_coplan[0]) xpos += m_sx;
2305 if (m_perx && m_ynplan[1] && xpos >= m_coplan[1]) xpos -= m_sx;
2306 if (m_pery && m_ynplan[2] && ypos <= m_coplan[2]) ypos += m_sy;
2307 if (m_pery && m_ynplan[3] && ypos >= m_coplan[3]) ypos -= m_sy;
2311 if (!InTube(xpos, ypos, m_cotube, m_ntube)) {
2316 if (m_ynplan[0] && xpos < m_coplan[0]) {
2320 if (m_ynplan[1] && xpos > m_coplan[1]) {
2324 if (m_ynplan[2] && ypos < m_coplan[2]) {
2328 if (m_ynplan[3] && ypos > m_coplan[3]) {
2335 for (
int i = m_nWires; i--;) {
2336 double dx = xpos - m_w[i].x;
2337 double dy = ypos - m_w[i].y;
2339 if (m_perx) dx -= m_sx * int(round(dx / m_sx));
2340 if (m_pery) dy -= m_sy * int(round(dy / m_sy));
2342 if (dx * dx + dy * dy < m_w[i].r * m_w[i].r) {
2349 switch (m_cellType) {
2351 FieldA00(xpos, ypos, ex, ey, volt, opt);
2354 FieldB1X(xpos, ypos, ex, ey, volt, opt);
2357 FieldB1Y(xpos, ypos, ex, ey, volt, opt);
2360 FieldB2X(xpos, ypos, ex, ey, volt, opt);
2363 FieldB2Y(xpos, ypos, ex, ey, volt, opt);
2366 FieldC10(xpos, ypos, ex, ey, volt, opt);
2369 FieldC2X(xpos, ypos, ex, ey, volt, opt);
2372 FieldC2Y(xpos, ypos, ex, ey, volt, opt);
2375 FieldC30(xpos, ypos, ex, ey, volt, opt);
2378 FieldD10(xpos, ypos, ex, ey, volt, opt);
2381 FieldD20(xpos, ypos, ex, ey, volt, opt);
2384 FieldD30(xpos, ypos, ex, ey, volt, opt);
2389 std::cerr <<
" Unknown cell type (id " << m_cellType <<
")\n";
2396 double exd = 0., eyd = 0., voltd = 0.;
2397 switch (m_cellType) {
2399 DipoleFieldA00(xpos, ypos, exd, eyd, voltd, opt);
2402 DipoleFieldB1X(xpos, ypos, exd, eyd, voltd, opt);
2405 DipoleFieldB1Y(xpos, ypos, exd, eyd, voltd, opt);
2408 DipoleFieldB2X(xpos, ypos, exd, eyd, voltd, opt);
2411 DipoleFieldB2Y(xpos, ypos, exd, eyd, voltd, opt);
2422 if (m_pery && m_tube) {
2424 Cartesian2Polar(ex, ey, xaux, yaux);
2426 Polar2Cartesian(xaux, yaux, ex, ey);
2432 volt += m_corvta * xpos + m_corvtb * ypos + m_corvtc;
2435 if (!m_ch3d.empty()) {
2436 double ex3d = 0., ey3d = 0., ez3d = 0., volt3d = 0.;
2437 switch (m_cellType) {
2441 Field3dA00(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2444 Field3dB2X(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2447 Field3dB2Y(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2450 Field3dD10(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2453 Field3dA00(xin, yin, zin, ex3d, ey3d, ez3d, volt3d);
2463 const double r =
exp(xpos);
2464 const double er = ex / r;
2465 const double ep = ey / r;
2466 const double theta = atan2(yin, xin);
2467 const double ct =
cos(theta);
2468 const double st =
sin(theta);
2469 ex = +ct * er -
st * ep;
2470 ey = +
st * er + ct * ep;
2475void ComponentAnalyticField::CellInit() {
2487 m_xmin = m_xmax = 0.;
2488 m_ymin = m_ymax = 0.;
2489 m_zmin = m_zmax = 0.;
2490 m_vmin = m_vmax = 0.;
2493 m_perx = m_pery =
false;
2499 m_cellTypeFourier =
A00;
2524 m_zmult = std::complex<double>(0., 0.);
2525 m_p1 = m_p2 = m_c1 = 0.;
2532 m_corvta = m_corvtb = m_corvtc = 0.;
2535 for (
int i = 0; i < 5; ++i) {
2536 m_planes[i].type =
'?';
2537 m_planes[i].ind = -1;
2538 m_planes[i].ewxcor = 0.;
2539 m_planes[i].ewycor = 0.;
2540 m_planes[i].strips1.clear();
2541 m_planes[i].strips2.clear();
2542 m_planes[i].pixels.clear();
2544 for (
int i = 0; i < 4; ++i) {
2545 m_ynplan[i] =
false;
2550 m_ynplax = m_ynplay =
false;
2551 m_coplax = m_coplay = 1.;
2573bool ComponentAnalyticField::Prepare() {
2577 <<
" The cell does not meet the requirements.\n";
2585 <<
" Type identification of the cell failed.\n";
2590 <<
" Cell is of type " << CellType() <<
".\n";
2595 std::cerr <<
m_className <<
"::Prepare: Calculation of charges failed.\n";
2600 <<
" Calculation of charges was successful.\n";
2604 if (!PrepareStrips()) {
2605 std::cerr <<
m_className <<
"::Prepare: Strip/pixel preparation failed.\n";
2613 if (!SetupDipoleTerms()) {
2615 <<
" Computing the dipole moments failed.\n";
2622bool ComponentAnalyticField::CellCheck() {
2636 const std::string xr = m_polar ?
"r" :
"x";
2637 double conew1 = m_coplan[0] - m_sx * int(round(m_coplan[0] / m_sx));
2638 double conew2 = m_coplan[1] - m_sx * int(round(m_coplan[1] / m_sx));
2640 if (m_ynplan[0] && m_ynplan[1] && conew1 == conew2) {
2647 if ((conew1 != m_coplan[0] && m_ynplan[0]) ||
2648 (conew2 != m_coplan[1] && m_ynplan[1])) {
2649 std::cout <<
m_className <<
"::CellCheck:\n The planes in "
2650 << xr <<
" are moved to the basic period.\n"
2651 <<
" This should not affect the results.\n";
2653 m_coplan[0] = conew1;
2654 m_coplan[1] = conew2;
2657 if (m_ynplan[0] && m_ynplan[1] &&
fabs(m_coplan[1] - m_coplan[0]) != m_sx) {
2658 std::cerr <<
m_className <<
"::CellCheck:\n The separation of the "
2659 << xr <<
" planes does not match the period.\n"
2660 <<
" The periodicity is cancelled.\n";
2664 if (m_ynplan[0] && m_ynplan[1] && m_vtplan[0] != m_vtplan[1]) {
2665 std::cerr <<
m_className <<
"::CellCheck:\n The voltages of the two "
2666 << xr <<
" planes differ.\n"
2667 <<
" The periodicity is cancelled.\n";
2674 const std::string yp = m_polar ?
"phi" :
"y";
2675 double conew3 = m_coplan[2] - m_sy * int(round(m_coplan[2] / m_sy));
2676 double conew4 = m_coplan[3] - m_sy * int(round(m_coplan[3] / m_sy));
2678 if (m_ynplan[2] && m_ynplan[3] && conew3 == conew4) {
2685 if ((conew3 != m_coplan[2] && m_ynplan[2]) ||
2686 (conew4 != m_coplan[3] && m_ynplan[3])) {
2687 std::cout <<
m_className <<
"::CellCheck:\n The planes in "
2688 << yp <<
" are moved to the basic period.\n"
2689 <<
" This should not affect the results.\n";
2691 m_coplan[2] = conew3;
2692 m_coplan[3] = conew4;
2695 if (m_ynplan[2] && m_ynplan[3] &&
fabs(m_coplan[3] - m_coplan[2]) != m_sy) {
2696 std::cerr <<
m_className <<
"::CellCheck:\n The separation of the two "
2697 << yp <<
" planes does not match the period.\n"
2698 <<
" The periodicity is cancelled.\n";
2702 if (m_ynplan[2] && m_ynplan[3] && m_vtplan[2] != m_vtplan[3]) {
2703 std::cerr <<
m_className <<
"::CellCheck:\n The voltages of the two "
2704 << yp <<
" planes differ.\n"
2705 <<
" The periodicity is cancelled.\n";
2711 for (
int i = 0; i < 2; ++i) {
2712 for (
int j = 2; j < 3; ++j) {
2713 if (m_ynplan[i] && m_ynplan[j] && m_vtplan[i] != m_vtplan[j]) {
2714 const std::string yp = m_polar ?
"phi" :
"y";
2716 <<
" Conflicting potential of two crossing planes.\n"
2717 <<
" One " << yp <<
" plane is removed.\n";
2718 m_ynplan[j] =
false;
2724 for (
int i = 0; i < 3; i += 2) {
2725 if (m_ynplan[i] && m_ynplan[i + 1]) {
2726 if (m_coplan[i] == m_coplan[i + 1]) {
2728 <<
" Two planes are on top of each other.\n"
2729 <<
" One of them is removed.\n";
2730 m_ynplan[i + 1] =
false;
2732 if (m_coplan[i] > m_coplan[i + 1]) {
2734 std::cout <<
m_className <<
"::CellCheck:\n Planes "
2735 << i <<
" and " << i + 1 <<
" are interchanged.\n";
2738 const double cohlp = m_coplan[i];
2739 m_coplan[i] = m_coplan[i + 1];
2740 m_coplan[i + 1] = cohlp;
2742 const double vthlp = m_vtplan[i];
2743 m_vtplan[i] = m_vtplan[i + 1];
2744 m_vtplan[i + 1] = vthlp;
2746 Plane plahlp = m_planes[i];
2747 m_planes[i] = m_planes[i + 1];
2748 m_planes[i + 1] = plahlp;
2755 for (
auto& wire : m_w) {
2756 double xnew = wire.x - m_sx * int(round(wire.x / m_sx));
2757 if (m_ynplan[0] && xnew <= m_coplan[0]) xnew += m_sx;
2758 if (m_ynplan[1] && xnew >= m_coplan[1]) xnew -= m_sx;
2759 if (
fabs(xnew - wire.x) > 1.e-8) {
2760 double xprt = wire.x;
2761 double yprt = wire.y;
2762 if (m_polar) Internal2Polar(wire.x, wire.y, xprt, yprt);
2763 const std::string xr = m_polar ?
"r" :
"x";
2764 std::cout <<
m_className <<
"::CellCheck:\n The " << wire.type
2765 <<
"-wire at (" << xprt <<
", " << yprt
2766 <<
") is moved to the basic " << xr <<
" period.\n"
2767 <<
" This should not affect the results.\n";
2774 if (m_tube && m_pery) {
2775 for (
unsigned int i = 0; i < m_nWires; ++i) {
2776 double xnew = m_w[i].x;
2777 double ynew = m_w[i].y;
2778 Cartesian2Polar(xnew, ynew, xnew, ynew);
2779 if (
int(round(DegreeToRad * ynew / m_sy)) != 0) {
2781 std::cout <<
" The " << m_w[i].type <<
"-wire at (" << m_w[i].x
2783 <<
") is moved to the basic phi period.\n";
2784 std::cout <<
" This should not affect the results.\n";
2785 ynew -= RadToDegree * m_sy * int(round(DegreeToRad * ynew / m_sy));
2786 Polar2Cartesian(xnew, ynew, m_w[i].x, m_w[i].y);
2789 }
else if (m_pery) {
2790 for (
auto& wire : m_w) {
2791 double ynew = wire.y - m_sy * int(round(wire.y / m_sy));
2792 if (m_ynplan[2] && ynew <= m_coplan[2]) ynew += m_sy;
2793 if (m_ynplan[3] && ynew >= m_coplan[3]) ynew -= m_sy;
2794 if (
fabs(ynew - wire.y) > 1.e-8) {
2795 double xprt = wire.x;
2796 double yprt = wire.y;
2797 if (m_polar) Internal2Polar(wire.x, wire.y, xprt, yprt);
2798 const std::string yp = m_polar ?
"phi" :
"y";
2799 std::cout <<
m_className <<
"::CellCheck:\n The " << wire.type
2800 <<
"-wire at (" << xprt <<
", " << yprt
2801 <<
") is moved to the basic " << yp <<
" period.\n"
2802 <<
" This should not affect the results.\n";
2809 int iplan1 = 0, iplan2 = 0, iplan3 = 0, iplan4 = 0;
2810 for (
const auto& wire : m_w) {
2811 if (m_ynplan[0] && wire.x <= m_coplan[0]) ++iplan1;
2812 if (m_ynplan[1] && wire.x <= m_coplan[1]) ++iplan2;
2813 if (m_ynplan[2] && wire.y <= m_coplan[2]) ++iplan3;
2814 if (m_ynplan[3] && wire.y <= m_coplan[3]) ++iplan4;
2818 const int imid = int(m_nWires) / 2;
2819 if (m_ynplan[0] && m_ynplan[1]) {
2820 if (iplan1 > imid) {
2821 m_ynplan[1] =
false;
2826 if (iplan2 < imid) {
2827 m_ynplan[0] =
false;
2833 if (m_ynplan[0] && !m_ynplan[1]) {
2834 if (iplan1 > imid) {
2840 if (m_ynplan[1] && !m_ynplan[0]) {
2841 if (iplan2 < imid) {
2848 if (m_ynplan[2] && m_ynplan[3]) {
2849 if (iplan3 > imid) {
2850 m_ynplan[3] =
false;
2855 if (iplan4 < imid) {
2856 m_ynplan[2] =
false;
2862 if (m_ynplan[2] && !m_ynplan[3]) {
2863 if (iplan3 > imid) {
2869 if (m_ynplan[3] && !m_ynplan[2]) {
2870 if (iplan4 < imid) {
2879 m_ynplan[0] =
false;
2881 m_coplan[1] = m_coplan[0];
2882 m_vtplan[1] = m_vtplan[0];
2883 m_planes[1] = m_planes[0];
2887 m_ynplan[1] =
false;
2889 m_coplan[0] = m_coplan[1];
2890 m_vtplan[0] = m_vtplan[1];
2891 m_planes[0] = m_planes[1];
2895 m_ynplan[2] =
false;
2897 m_coplan[3] = m_coplan[2];
2898 m_vtplan[3] = m_vtplan[2];
2899 m_planes[3] = m_planes[2];
2903 m_ynplan[3] =
false;
2905 m_coplan[2] = m_coplan[3];
2906 m_vtplan[2] = m_vtplan[3];
2907 m_planes[2] = m_planes[3];
2910 std::vector<bool> wrong(m_nWires,
false);
2912 for (
unsigned int i = 0; i < m_nWires; ++i) {
2913 const double rw = m_w[i].r;
2914 const double dw = 2. * rw;
2915 if (m_ynplan[0] && m_w[i].x - rw <= m_coplan[0]) wrong[i] =
true;
2916 if (m_ynplan[1] && m_w[i].x + rw >= m_coplan[1]) wrong[i] =
true;
2917 if (m_ynplan[2] && m_w[i].y - rw <= m_coplan[2]) wrong[i] =
true;
2918 if (m_ynplan[3] && m_w[i].y + rw >= m_coplan[3]) wrong[i] =
true;
2920 if (!InTube(m_w[i].x, m_w[i].y, m_cotube, m_ntube)) {
2922 std::cerr <<
" The " << m_w[i].type <<
"-wire at (" << m_w[i].x
2923 <<
", " << m_w[i].y <<
") is located outside the tube.\n";
2924 std::cerr <<
" This wire is removed.\n";
2927 }
else if (wrong[i]) {
2928 double xprt = m_w[i].x;
2929 double yprt = m_w[i].y;
2930 if (m_polar) Internal2Polar(m_w[i].x, m_w[i].y, xprt, yprt);
2931 std::cerr <<
m_className <<
"::CellCheck:\n The " << m_w[i].type
2932 <<
"-wire at (" << xprt <<
", " << yprt <<
") is located "
2933 <<
"outside the planes.\n This wire is removed.\n";
2934 }
else if ((m_perx && dw >= m_sx) || (m_pery && dw >= m_sy)) {
2935 double xprt = m_w[i].x;
2936 double yprt = m_w[i].y;
2937 if (m_polar) Internal2Polar(m_w[i].x, m_w[i].y, xprt, yprt);
2938 std::cerr <<
m_className <<
"::CellCheck:\n The diameter of the "
2939 << m_w[i].type <<
"-wire at (" << xprt <<
", " << yprt
2940 <<
") exceeds 1 period.\n This wire is removed.\n";
2946 for (
unsigned int i = 0; i < m_nWires; ++i) {
2947 if (wrong[i])
continue;
2948 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
2949 if (wrong[j])
continue;
2954 double xaux1, xaux2, yaux1, yaux2;
2955 Cartesian2Polar(m_w[i].x, m_w[i].y, xaux1, yaux1);
2956 Cartesian2Polar(m_w[j].x, m_w[j].y, xaux2, yaux2);
2957 yaux1 -= m_sy * int(round(yaux1 / m_sy));
2958 yaux2 -= m_sy * int(round(yaux2 / m_sy));
2959 Polar2Cartesian(xaux1, yaux1, xaux1, yaux1);
2960 Polar2Cartesian(xaux2, yaux2, xaux2, yaux2);
2961 xsepar = xaux1 - xaux2;
2962 ysepar = yaux1 - yaux2;
2964 xsepar = m_w[i].x - m_w[j].x;
2965 ysepar = m_w[i].y - m_w[j].y;
2968 xsepar =
fabs(m_w[i].x - m_w[j].x);
2969 if (m_perx) xsepar -= m_sx * int(round(xsepar / m_sx));
2970 ysepar =
fabs(m_w[i].y - m_w[j].y);
2971 if (m_pery) ysepar -= m_sy * int(round(ysepar / m_sy));
2973 const double rij = m_w[i].r + m_w[j].r;
2974 if (xsepar * xsepar + ysepar * ysepar > rij * rij)
continue;
2975 double xprti = m_w[i].x;
2976 double yprti = m_w[i].y;
2977 double xprtj = m_w[j].x;
2978 double yprtj = m_w[j].y;
2980 Internal2Polar(m_w[i].x, m_w[i].y, xprti, yprti);
2981 Internal2Polar(m_w[j].x, m_w[j].y, xprtj, yprtj);
2983 std::cerr <<
m_className <<
"::CellCheck:\n Wires " << m_w[i].type
2984 <<
" at (" << xprti <<
", " << yprti <<
") and " << m_w[j].type
2985 <<
" at (" << xprtj <<
", " << yprtj
2986 <<
") overlap at least partially.\n"
2987 <<
" The latter wire is removed.\n";
2993 const int iWires = m_nWires;
2995 for (
int i = 0; i < iWires; ++i) {
2997 m_w[m_nWires] = m_w[i];
3003 int nElements = m_nWires;
3004 if (m_ynplan[0]) ++nElements;
3005 if (m_ynplan[1]) ++nElements;
3006 if (m_ynplan[2]) ++nElements;
3007 if (m_ynplan[3]) ++nElements;
3008 if (m_tube) ++nElements;
3010 if (nElements < 2) {
3012 std::cerr <<
" At least 2 elements are necessary.\n";
3013 std::cerr <<
" Cell rejected.\n";
3023 m_xmin = m_xmax = 0.;
3024 m_ymin = m_ymax = 0.;
3025 m_zmin = m_zmax = 0.;
3026 m_vmin = m_vmax = 0.;
3029 for (
const auto& wire : m_w) {
3030 const double rw = wire.r;
3032 m_xmin = std::min(m_xmin, wire.x - rw);
3033 m_xmax = std::max(m_xmax, wire.x + rw);
3035 m_xmin = wire.x - rw;
3036 m_xmax = wire.x + rw;
3040 m_ymin = std::min(m_ymin, wire.y - rw);
3041 m_ymax = std::max(m_ymax, wire.y + rw);
3043 m_ymin = wire.y - rw;
3044 m_ymax = wire.y + rw;
3048 m_zmin = std::min(m_zmin, -0.5 * wire.u);
3049 m_zmax = std::max(m_zmax, +0.5 * wire.u);
3051 m_zmin = -0.5 * wire.u;
3052 m_zmax = +0.5 * wire.u;
3056 m_vmin = std::min(m_vmin, wire.v);
3057 m_vmax = std::max(m_vmax, wire.v);
3059 m_vmin = m_vmax = wire.v;
3064 for (
int i = 0; i < 4; ++i) {
3065 if (!m_ynplan[i])
continue;
3068 m_xmin = std::min(m_xmin, m_coplan[i]);
3069 m_xmax = std::max(m_xmax, m_coplan[i]);
3071 m_xmin = m_xmax = m_coplan[i];
3076 m_ymin = std::min(m_ymin, m_coplan[i]);
3077 m_ymax = std::max(m_ymax, m_coplan[i]);
3079 m_ymin = m_ymax = m_coplan[i];
3084 m_vmin = std::min(m_vmin, m_vtplan[i]);
3085 m_vmax = std::max(m_vmax, m_vtplan[i]);
3087 m_vmin = m_vmax = m_vtplan[i];
3094 m_xmin = -1.1 * m_cotube;
3095 m_xmax = +1.1 * m_cotube;
3097 m_ymin = -1.1 * m_cotube;
3098 m_ymax = +1.1 * m_cotube;
3100 m_vmin = std::min(m_vmin, m_vttube);
3101 m_vmax = std::max(m_vmax, m_vttube);
3106 if (m_perx && m_sx > (m_xmax - m_xmin)) {
3107 m_xmin = -0.5 * m_sx;
3108 m_xmax = +0.5 * m_sx;
3112 if (m_pery && m_sy > (m_ymax - m_ymin)) {
3113 m_ymin = -0.5 * m_sy;
3114 m_ymax = +0.5 * m_sy;
3118 if (m_polar && (m_ymax - m_ymin) >= TwoPi) {
3125 if (setx && m_xmin != m_xmax && (m_ymin == m_ymax || !sety)) {
3126 m_ymin -= 0.5 *
fabs(m_xmax - m_xmin);
3127 m_ymax += 0.5 *
fabs(m_xmax - m_xmin);
3130 if (sety && m_ymin != m_ymax && (m_xmin == m_xmax || !setx)) {
3131 m_xmin -= 0.5 *
fabs(m_ymax - m_ymin);
3132 m_xmax += 0.5 *
fabs(m_ymax - m_ymin);
3137 m_zmin = -0.25 * (
fabs(m_xmax - m_xmin) +
fabs(m_ymax - m_ymin));
3138 m_zmax = +0.25 * (
fabs(m_xmax - m_xmin) +
fabs(m_ymax - m_ymin));
3143 if (!(setx && sety && setz)) {
3145 std::cerr <<
" Unable to establish"
3146 <<
" default dimensions in all directions.\n";
3150 if (m_vmin == m_vmax || !setv) {
3152 std::cerr <<
" All potentials in the cell are the same.\n";
3153 std::cerr <<
" There is no point in going on.\n";
3161bool ComponentAnalyticField::WireCheck()
const {
3167 if (m_nWires == 0)
return false;
3169 if (m_nWires == 1 &&
3170 !(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3]) && !m_tube) {
3174 for (
unsigned int i = 0; i < m_nWires; ++i) {
3175 const auto& wire = m_w[i];
3176 if (m_ynplan[0] && wire.x - wire.r <= m_coplan[0])
return false;
3177 if (m_ynplan[1] && wire.x + wire.r >= m_coplan[1])
return false;
3178 if (m_ynplan[2] && wire.y - wire.r <= m_coplan[2])
return false;
3179 if (m_ynplan[3] && wire.y + wire.r >= m_coplan[3])
return false;
3181 if (!InTube(wire.x, wire.y, m_cotube, m_ntube))
return false;
3182 }
else if ((m_perx && 2 * wire.r >= m_sx) ||
3183 (m_pery && 2 * wire.r >= m_sy)) {
3188 for (
unsigned int i = 0; i < m_nWires; ++i) {
3189 const double xi = m_w[i].x;
3190 const double yi = m_w[i].y;
3191 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3192 const double xj = m_w[j].x;
3193 const double yj = m_w[j].y;
3194 double xsepar = std::abs(xi - xj);
3195 double ysepar = std::abs(yi - yj);
3198 double xaux1 = 0., yaux1 = 0.;
3199 double xaux2 = 0., yaux2 = 0.;
3200 Cartesian2Polar(xi, yi, xaux1, yaux1);
3201 Cartesian2Polar(xj, yj, xaux2, yaux2);
3202 yaux1 -= m_sy * int(round(yaux1 / m_sy));
3203 yaux2 -= m_sy * int(round(yaux2 / m_sy));
3204 Polar2Cartesian(xaux1, yaux1, xaux1, yaux1);
3205 Polar2Cartesian(xaux2, yaux2, xaux2, yaux2);
3206 xsepar = xaux1 - xaux2;
3207 ysepar = yaux1 - yaux2;
3210 if (m_perx) xsepar -= m_sx * int(round(xsepar / m_sx));
3211 if (m_pery) ysepar -= m_sy * int(round(ysepar / m_sy));
3213 const double rij = m_w[i].r + m_w[j].r;
3214 if (xsepar * xsepar + ysepar * ysepar < rij * rij)
return false;
3220bool ComponentAnalyticField::CellType() {
3229 }
else if (m_ntube >= 3 && m_ntube <= 8) {
3237 <<
" Potentials for tube with " << m_ntube
3238 <<
" edges are not yet available.\n"
3239 <<
" Using a round tube instead.\n";
3247 if (!(m_perx || m_pery) && !(m_ynplan[0] && m_ynplan[1]) &&
3248 !(m_ynplan[2] && m_ynplan[3])) {
3254 if (m_perx && !m_pery && !(m_ynplan[0] || m_ynplan[1]) &&
3255 !(m_ynplan[2] && m_ynplan[3])) {
3261 if (m_pery && !m_perx && !(m_ynplan[0] && m_ynplan[1]) &&
3262 !(m_ynplan[2] || m_ynplan[3])) {
3268 if (m_perx && !m_pery && !(m_ynplan[2] && m_ynplan[3])) {
3273 if (!(m_perx || m_pery) && !(m_ynplan[2] && m_ynplan[3]) &&
3274 (m_ynplan[0] && m_ynplan[1])) {
3275 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3281 if (m_pery && !m_perx && !(m_ynplan[0] && m_ynplan[1])) {
3286 if (!(m_perx || m_pery) && !(m_ynplan[0] && m_ynplan[1]) &&
3287 (m_ynplan[2] && m_ynplan[3])) {
3288 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3294 if (!(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3]) && m_perx &&
3301 if (!((m_ynplan[2] && m_pery) || (m_ynplan[2] && m_ynplan[3]))) {
3302 if (m_ynplan[0] && m_ynplan[1]) {
3303 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3307 if (m_perx && m_ynplan[0]) {
3314 if (!((m_ynplan[0] && m_perx) || (m_ynplan[0] && m_ynplan[1]))) {
3315 if (m_ynplan[2] && m_ynplan[3]) {
3316 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3320 if (m_pery && m_ynplan[2]) {
3327 if (m_perx && m_pery) {
3333 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3339 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3344 if (m_ynplan[0] && m_ynplan[1] && m_ynplan[2] && m_ynplan[3]) {
3345 m_sx =
fabs(m_coplan[1] - m_coplan[0]);
3346 m_sy =
fabs(m_coplan[3] - m_coplan[2]);
3356 switch (m_cellType) {
3389bool ComponentAnalyticField::PrepareStrips() {
3395 double gapDef[4] = {0., 0., 0., 0.};
3400 gapDef[0] = m_coplan[1] - m_coplan[0];
3401 }
else if (m_nWires <= 0) {
3404 gapDef[0] = m_w[0].x - m_coplan[0];
3405 for (
const auto& wire : m_w) {
3406 gapDef[0] = std::min(wire.x - m_coplan[0], gapDef[0]);
3413 gapDef[1] = m_coplan[1] - m_coplan[0];
3414 }
else if (m_nWires <= 0) {
3417 gapDef[1] = m_coplan[1] - m_w[0].x;
3418 for (
const auto& wire : m_w) {
3419 gapDef[1] = std::min(m_coplan[1] - wire.x, gapDef[1]);
3426 gapDef[2] = m_coplan[3] - m_coplan[2];
3427 }
else if (m_nWires <= 0) {
3430 gapDef[2] = m_w[0].y - m_coplan[2];
3431 for (
const auto& wire : m_w) {
3432 gapDef[2] = std::min(wire.y - m_coplan[2], gapDef[2]);
3439 gapDef[3] = m_coplan[3] - m_coplan[2];
3440 }
else if (m_nWires <= 0) {
3443 gapDef[3] = m_coplan[3] - m_w[0].y;
3444 for (
const auto& wire : m_w) {
3445 gapDef[3] = std::min(m_coplan[3] - wire.y, gapDef[3]);
3451 for (
unsigned int i = 0; i < 4; ++i) {
3452 for (
auto& strip : m_planes[i].strips1) {
3453 if (strip.gap < 0. && gapDef[i] < 0.) {
3455 <<
" Not able to set a default anode-cathode gap\n";
3457 std::cerr <<
" for r/phi-strips of plane " << i <<
".\n";
3459 std::cerr <<
" for x/y-strips of plane " << i <<
".\n";
3463 if (strip.gap < 0.) {
3464 strip.gap = gapDef[i];
3465 }
else if (m_polar && i < 2) {
3467 strip.gap = log1p(strip.gap /
exp(m_coplan[i]));
3469 strip.gap = -log1p(-strip.gap /
exp(m_coplan[i]));
3473 for (
auto& strip : m_planes[i].strips2) {
3474 if (strip.gap < 0. && gapDef[i] < 0.) {
3476 <<
" Not able to set a default anode-cathode gap\n"
3477 <<
" for z-strips of plane " << i <<
".\n";
3480 if (strip.gap < 0.) {
3481 strip.gap = gapDef[i];
3482 }
else if (m_polar && i < 2) {
3484 strip.gap = log1p(strip.gap /
exp(m_coplan[i]));
3486 strip.gap = -log1p(-strip.gap /
exp(m_coplan[i]));
3490 for (
auto& pixel : m_planes[i].pixels) {
3491 if (pixel.gap < 0. && gapDef[i] < 0.) {
3493 <<
" Not able to set a default anode-cathode gap\n"
3494 <<
" for pixels on plane " << i <<
".\n";
3497 if (pixel.gap < 0.) {
3498 pixel.gap = gapDef[i];
3499 }
else if (m_polar && i < 2) {
3501 pixel.gap = log1p(pixel.gap /
exp(m_coplan[i]));
3503 pixel.gap = -log1p(-pixel.gap /
exp(m_coplan[i]));
3514 if (std::find(m_readout.begin(), m_readout.end(), label) != m_readout.end()) {
3516 std::cout <<
" Readout group " << label <<
" already exists.\n";
3519 m_readout.push_back(label);
3521 unsigned int nWiresFound = 0;
3522 for (
const auto& wire : m_w) {
3523 if (wire.type == label) ++nWiresFound;
3526 unsigned int nPlanesFound = 0;
3527 unsigned int nStripsFound = 0;
3528 unsigned int nPixelsFound = 0;
3529 for (
int i = 0; i < 5; ++i) {
3530 if (m_planes[i].type == label) ++nPlanesFound;
3531 for (
const auto& strip : m_planes[i].strips1) {
3532 if (strip.type == label) ++nStripsFound;
3534 for (
const auto& strip : m_planes[i].strips2) {
3535 if (strip.type == label) ++nStripsFound;
3537 for (
const auto& pixel : m_planes[i].pixels) {
3538 if (pixel.type == label) ++nPixelsFound;
3542 if (nWiresFound == 0 && nPlanesFound == 0 && nStripsFound == 0 &&
3543 nPixelsFound == 0) {
3545 std::cerr <<
" At present there are no wires, planes or strips\n";
3546 std::cerr <<
" associated to readout group " << label <<
".\n";
3549 std::cout <<
" Readout group " << label <<
" comprises:\n";
3550 if (nWiresFound > 1) {
3551 std::cout <<
" " << nWiresFound <<
" wires\n";
3552 }
else if (nWiresFound == 1) {
3553 std::cout <<
" 1 wire\n";
3555 if (nPlanesFound > 1) {
3556 std::cout <<
" " << nPlanesFound <<
" planes\n";
3557 }
else if (nPlanesFound == 1) {
3558 std::cout <<
" 1 plane\n";
3560 if (nStripsFound > 1) {
3561 std::cout <<
" " << nStripsFound <<
" strips\n";
3562 }
else if (nStripsFound == 1) {
3563 std::cout <<
" 1 strip\n";
3565 if (nPixelsFound > 1) {
3566 std::cout <<
" " << nPixelsFound <<
" pixels\n";
3567 }
else if (nPixelsFound == 1) {
3568 std::cout <<
" 1 pixel\n";
3575bool ComponentAnalyticField::Setup() {
3583 m_coplax = m_coplan[0];
3585 }
else if (m_ynplan[1]) {
3586 m_coplax = m_coplan[1];
3593 m_coplay = m_coplan[2];
3595 }
else if (m_ynplan[3]) {
3596 m_coplay = m_coplan[3];
3606 m_corvtc = m_vttube;
3607 }
else if ((m_ynplan[0] && m_ynplan[1]) && !(m_ynplan[2] || m_ynplan[3])) {
3608 m_corvta = (m_vtplan[0] - m_vtplan[1]) / (m_coplan[0] - m_coplan[1]);
3610 m_corvtc = (m_vtplan[1] * m_coplan[0] - m_vtplan[0] * m_coplan[1]) /
3611 (m_coplan[0] - m_coplan[1]);
3612 }
else if ((m_ynplan[2] && m_ynplan[3]) && !(m_ynplan[0] || m_ynplan[1])) {
3614 m_corvtb = (m_vtplan[2] - m_vtplan[3]) / (m_coplan[2] - m_coplan[3]);
3615 m_corvtc = (m_vtplan[3] * m_coplan[2] - m_vtplan[2] * m_coplan[3]) /
3616 (m_coplan[2] - m_coplan[3]);
3618 m_corvta = m_corvtb = m_corvtc = 0.;
3619 if (m_ynplan[0]) m_corvtc = m_vtplan[0];
3620 if (m_ynplan[1]) m_corvtc = m_vtplan[1];
3621 if (m_ynplan[2]) m_corvtc = m_vtplan[2];
3622 if (m_ynplan[3]) m_corvtc = m_vtplan[3];
3626 if (m_nWires <= 0)
return true;
3629 m_a.assign(m_nWires, std::vector<double>(m_nWires, 0.));
3634 switch (m_cellType) {
3672 std::cerr <<
m_className <<
"::Setup: Unknown cell type.\n";
3681 std::cerr <<
" Preparing the cell for field calculations"
3682 <<
" did not succeed.\n";
3688bool ComponentAnalyticField::SetupA00() {
3697 for (
unsigned int i = 0; i < m_nWires; ++i) {
3698 m_a[i][i] = m_w[i].r * m_w[i].r;
3700 if (m_ynplax) m_a[i][i] /= 4. *
pow(m_w[i].x - m_coplax, 2);
3701 if (m_ynplay) m_a[i][i] /= 4. *
pow(m_w[i].y - m_coplay, 2);
3703 if (m_ynplax && m_ynplay)
3705 4.0 * (
pow(m_w[i].x - m_coplax, 2) +
pow(m_w[i].y - m_coplay, 2));
3707 m_a[i][i] = -0.5 * log(m_a[i][i]);
3709 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3710 m_a[i][j] =
pow(m_w[i].x - m_w[j].x, 2) +
pow(m_w[i].y - m_w[j].y, 2);
3713 m_a[i][j] = m_a[i][j] / (
pow(m_w[i].x + m_w[j].x - 2. * m_coplax, 2) +
3714 pow(m_w[i].y - m_w[j].y, 2));
3716 m_a[i][j] = m_a[i][j] / (
pow(m_w[i].x - m_w[j].x, 2) +
3717 pow(m_w[i].y + m_w[j].y - 2. * m_coplay, 2));
3719 if (m_ynplax && m_ynplay)
3720 m_a[i][j] *=
pow(m_w[i].x + m_w[j].x - 2. * m_coplax, 2) +
3721 pow(m_w[i].y + m_w[j].y - 2. * m_coplay, 2);
3723 m_a[i][j] = -0.5 * log(m_a[i][j]);
3725 m_a[j][i] = m_a[i][j];
3732bool ComponentAnalyticField::SetupB1X() {
3743 double xx = 0., yy = 0., yymirr = 0.;
3747 for (
unsigned int i = 0; i < m_nWires; ++i) {
3748 m_a[i][i] = -log(m_w[i].r * Pi / m_sx);
3751 yy = (Pi / m_sx) * 2. * (m_w[i].y - m_coplay);
3752 if (
fabs(yy) > 20.) m_a[i][i] +=
fabs(yy) - CLog2;
3753 if (
fabs(yy) <= 20.) m_a[i][i] += log(
fabs(sinh(yy)));
3756 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3757 xx = (Pi / m_sx) * (m_w[i].x - m_w[j].x);
3758 yy = (Pi / m_sx) * (m_w[i].y - m_w[j].y);
3759 if (
fabs(yy) > 20.) m_a[i][j] = -
fabs(yy) + CLog2;
3760 if (
fabs(yy) <= 20.) {
3761 const double sinhy = sinh(yy);
3762 const double sinx =
sin(xx);
3763 m_a[i][j] = -0.5 * log(sinhy * sinhy + sinx * sinx);
3768 yymirr = (Pi / m_sx) * (m_w[i].y + m_w[j].y - 2. * m_coplay);
3769 if (
fabs(yymirr) > 20.) r2plan =
fabs(yymirr) - CLog2;
3770 if (
fabs(yymirr) <= 20.) {
3771 const double sinhy = sinh(yymirr);
3772 const double sinx =
sin(xx);
3773 r2plan = 0.5 * log(sinhy * sinhy + sinx * sinx);
3775 m_a[i][j] += r2plan;
3778 m_a[j][i] = m_a[i][j];
3785bool ComponentAnalyticField::SetupB1Y() {
3795 double xx = 0., yy = 0., xxmirr = 0.;
3799 for (
unsigned int i = 0; i < m_nWires; ++i) {
3800 m_a[i][i] = -log(m_w[i].r * Pi / m_sy);
3803 xx = (Pi / m_sy) * 2. * (m_w[i].x - m_coplax);
3804 if (
fabs(xx) > 20.) m_a[i][i] +=
fabs(xx) - CLog2;
3805 if (
fabs(xx) <= 20.) m_a[i][i] += log(
fabs(sinh(xx)));
3808 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3809 xx = (Pi / m_sy) * (m_w[i].x - m_w[j].x);
3810 yy = (Pi / m_sy) * (m_w[i].y - m_w[j].y);
3811 if (
fabs(xx) > 20.) m_a[i][j] = -
fabs(xx) + CLog2;
3812 if (
fabs(xx) <= 20.) {
3813 const double sinhx = sinh(xx);
3814 const double siny =
sin(yy);
3815 m_a[i][j] = -0.5 * log(sinhx * sinhx + siny * siny);
3819 xxmirr = (Pi / m_sy) * (m_w[i].x + m_w[j].x - 2. * m_coplax);
3821 if (
fabs(xxmirr) > 20.) r2plan =
fabs(xxmirr) - CLog2;
3822 if (
fabs(xxmirr) <= 20.) {
3823 const double sinhx = sinh(xxmirr);
3824 const double siny =
sin(yy);
3825 r2plan = 0.5 * log(sinhx * sinhx + siny * siny);
3827 m_a[i][j] += r2plan;
3830 m_a[j][i] = m_a[i][j];
3837bool ComponentAnalyticField::SetupB2X() {
3849 m_b2sin.resize(m_nWires);
3852 for (
unsigned int i = 0; i < m_nWires; ++i) {
3853 double xx = (Pi / m_sx) * (m_w[i].x - m_coplax);
3854 m_a[i][i] = (0.5 * m_w[i].r * Pi / m_sx) /
sin(xx);
3857 const double yymirr = (Pi / m_sx) * (m_w[i].y - m_coplay);
3858 if (
fabs(yymirr) <= 20.) {
3859 const double sinhy = sinh(yymirr);
3860 const double sinx =
sin(xx);
3861 m_a[i][i] *=
sqrt(sinhy * sinhy + sinx * sinx) / sinhy;
3865 m_a[i][i] = -log(
fabs(m_a[i][i]));
3867 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
3868 xx = HalfPi * (m_w[i].x - m_w[j].x) / m_sx;
3869 const double yy = HalfPi * (m_w[i].y - m_w[j].y) / m_sx;
3870 const double xxneg =
3871 HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplax) / m_sx;
3872 if (
fabs(yy) <= 20.) {
3873 const double sinhy = sinh(yy);
3874 const double sinxx =
sin(xx);
3875 const double sinxxneg =
sin(xxneg);
3876 m_a[i][j] = (sinhy * sinhy + sinxx * sinxx) /
3877 (sinhy * sinhy + sinxxneg * sinxxneg);
3879 if (
fabs(yy) > 20.) m_a[i][j] = 1.0;
3882 const double yymirr =
3883 HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplay) / m_sx;
3884 if (
fabs(yymirr) <= 20.) {
3885 const double sinhy = sinh(yymirr);
3886 const double sinxx =
sin(xx);
3887 const double sinxxneg =
sin(xxneg);
3888 m_a[i][j] *= (sinhy * sinhy + sinxxneg * sinxxneg) /
3889 (sinhy * sinhy + sinxx * sinxx);
3893 m_a[i][j] = -0.5 * log(m_a[i][j]);
3894 m_a[j][i] = m_a[i][j];
3897 m_b2sin[i] =
sin(Pi * (m_coplax - m_w[i].x) / m_sx);
3903bool ComponentAnalyticField::SetupB2Y() {
3915 m_b2sin.resize(m_nWires);
3918 for (
unsigned int i = 0; i < m_nWires; ++i) {
3919 double yy = (Pi / m_sy) * (m_w[i].y - m_coplay);
3920 m_a[i][i] = (0.5 * m_w[i].r * Pi / m_sy) /
sin(yy);
3923 const double xxmirr = (Pi / m_sy) * (m_w[i].x - m_coplax);
3924 if (
fabs(xxmirr) <= 20.) {
3925 const double sinhx = sinh(xxmirr);
3926 const double sinyy =
sin(yy);
3927 m_a[i][i] *=
sqrt(sinhx * sinhx + sinyy * sinyy) / sinhx;
3931 m_a[i][i] = -log(
fabs(m_a[i][i]));
3933 for (
unsigned int j = i + 1; j < m_nWires; j++) {
3934 const double xx = HalfPi * (m_w[i].x - m_w[j].x) / m_sy;
3935 yy = HalfPi * (m_w[i].y - m_w[j].y) / m_sy;
3936 const double yyneg =
3937 HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplay) / m_sy;
3938 if (
fabs(xx) <= 20.) {
3939 const double sinhx = sinh(xx);
3940 const double sinyy =
sin(yy);
3941 const double sinyyneg =
sin(yyneg);
3942 m_a[i][j] = (sinhx * sinhx + sinyy * sinyy) /
3943 (sinhx * sinhx + sinyyneg * sinyyneg);
3945 if (
fabs(xx) > 20.) m_a[i][j] = 1.0;
3948 const double xxmirr =
3949 HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplax) / m_sy;
3950 if (
fabs(xxmirr) <= 20.) {
3951 const double sinhx = sinh(xxmirr);
3952 const double sinyy =
sin(yy);
3953 const double sinyyneg =
sin(yyneg);
3954 m_a[i][j] *= (sinhx * sinhx + sinyyneg * sinyyneg) /
3955 (sinhx * sinhx + sinyy * sinyy);
3959 m_a[i][j] = -0.5 * log(m_a[i][j]);
3960 m_a[j][i] = m_a[i][j];
3963 m_b2sin[i] =
sin(Pi * (m_coplay - m_w[i].y) / m_sy);
3969bool ComponentAnalyticField::SetupC10() {
3987 if (m_sy / m_sx < 8.) p =
exp(-Pi * m_sy / m_sx);
3988 m_zmult = std::complex<double>(Pi / m_sx, 0.);
3991 if (m_sx / m_sy < 8.) p =
exp(-Pi * m_sx / m_sy);
3992 m_zmult = std::complex<double>(0., Pi / m_sy);
3995 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
3999 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4001 std::cout <<
" zmult = " << m_zmult <<
"\n";
4002 std::cout <<
" mode = " << m_mode <<
"\n";
4006 for (
unsigned int i = 0; i < m_nWires; ++i) {
4007 for (
unsigned int j = 0; j < m_nWires; ++j) {
4008 const double xyi = m_mode == 0 ? m_w[i].x : m_w[i].y;
4009 const double xyj = m_mode == 0 ? m_w[j].x : m_w[j].y;
4010 const double temp = xyi * xyj * TwoPi / (m_sx * m_sy);
4012 m_a[i][j] = Ph2Lim(m_w[i].r) - temp;
4014 m_a[i][j] = Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) - temp;
4019 if (!Charge())
return false;
4022 for (
unsigned int j = 0; j < m_nWires; ++j) {
4023 const double xyj = m_mode == 0 ? m_w[j].x : m_w[j].y;
4024 s += m_w[j].e * xyj;
4026 m_c1 = -s * 2. * Pi / (m_sx * m_sy);
4030bool ComponentAnalyticField::SetupC2X() {
4044 if (2. * m_sx <= m_sy) {
4046 if (m_sy / m_sx < 25.) p =
exp(-HalfPi * m_sy / m_sx);
4047 m_zmult = std::complex<double>(HalfPi / m_sx, 0.);
4050 if (m_sx / m_sy < 6.) p =
exp(-2. * Pi * m_sx / m_sy);
4051 m_zmult = std::complex<double>(0., Pi / m_sy);
4054 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
4058 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4060 std::cout <<
" zmult = " << m_zmult <<
"\n";
4061 std::cout <<
" mode = " << m_mode <<
"\n";
4065 for (
unsigned int i = 0; i < m_nWires; ++i) {
4067 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
4068 for (
unsigned int j = 0; j < m_nWires; ++j) {
4071 temp = (m_w[i].x - cx) * (m_w[j].x - cx) * TwoPi / (m_sx * m_sy);
4075 Ph2Lim(m_w[i].r) - Ph2(2. * (m_w[i].x - cx), 0.) - temp;
4077 m_a[i][j] = Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
4078 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) -
4084 if (!Charge())
return false;
4089 for (
unsigned int i = 0; i < m_nWires; ++i) {
4091 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
4092 s += m_w[i].e * (m_w[i].x - cx);
4094 m_c1 = -s * TwoPi / (m_sx * m_sy);
4099bool ComponentAnalyticField::SetupC2Y() {
4113 if (m_sx <= 2. * m_sy) {
4115 if (m_sy / m_sx <= 6.) p =
exp(-2. * Pi * m_sy / m_sx);
4116 m_zmult = std::complex<double>(Pi / m_sx, 0.);
4119 if (m_sx / m_sy <= 25.) p =
exp(-HalfPi * m_sx / m_sy);
4120 m_zmult = std::complex<double>(0., HalfPi / m_sy);
4123 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
4127 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4129 std::cout <<
" zmult = " << m_zmult <<
"\n";
4130 std::cout <<
" mode = " << m_mode <<
"\n";
4134 for (
unsigned int i = 0; i < m_nWires; ++i) {
4136 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
4137 for (
unsigned int j = 0; j < m_nWires; ++j) {
4140 temp = (m_w[i].y - cy) * (m_w[j].y - cy) * TwoPi / (m_sx * m_sy);
4144 Ph2Lim(m_w[i].r) - Ph2(0., 2. * (m_w[j].y - cy)) - temp;
4146 m_a[i][j] = Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
4147 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) -
4153 if (!Charge())
return false;
4158 for (
unsigned int i = 0; i < m_nWires; ++i) {
4160 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
4161 s += m_w[i].e * (m_w[i].y - cy);
4163 m_c1 = -s * TwoPi / (m_sx * m_sy);
4168bool ComponentAnalyticField::SetupC30() {
4184 if (m_sy / m_sx <= 13.) p =
exp(-Pi * m_sy / m_sx);
4185 m_zmult = std::complex<double>(HalfPi / m_sx, 0.);
4188 if (m_sx / m_sy <= 13.) p =
exp(-Pi * m_sx / m_sy);
4189 m_zmult = std::complex<double>(0., HalfPi / m_sy);
4192 if (m_p1 > 1.e-10) m_p2 =
pow(p, 6);
4196 std::cout <<
" p, p1, p2 = " << p <<
", " << m_p1 <<
", " << m_p2
4198 std::cout <<
" zmult = " << m_zmult <<
"\n";
4199 std::cout <<
" mode = " << m_mode <<
"\n";
4203 for (
unsigned int i = 0; i < m_nWires; ++i) {
4204 double cx = m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
4205 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
4206 for (
unsigned int j = 0; j < m_nWires; ++j) {
4208 m_a[i][i] = Ph2Lim(m_w[i].r) - Ph2(0., 2. * (m_w[i].y - cy)) -
4209 Ph2(2. * (m_w[i].x - cx), 0.) +
4210 Ph2(2. * (m_w[i].x - cx), 2. * (m_w[i].y - cy));
4213 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
4214 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) -
4215 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) +
4216 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y + m_w[j].y - 2. * cy);
4221 if (!Charge())
return false;
4227bool ComponentAnalyticField::SetupD10() {
4236 for (
unsigned int i = 0; i < m_nWires; ++i) {
4238 m_a[i][i] = -log(m_w[i].r * m_cotube /
4239 (m_cotube2 - (m_w[i].x * m_w[i].x + m_w[i].y * m_w[i].y)));
4241 std::complex<double> zi(m_w[i].x, m_w[i].y);
4243 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
4245 std::complex<double> zj(m_w[j].x, m_w[j].y);
4246 m_a[i][j] = -log(abs(m_cotube * (zi - zj) / (m_cotube2 - conj(zi) * zj)));
4248 m_a[j][i] = m_a[i][j];
4255bool ComponentAnalyticField::SetupD20() {
4265 for (
unsigned int i = 0; i < m_nWires; ++i) {
4267 std::complex<double> zi(m_w[i].x, m_w[i].y);
4268 if (abs(zi) < m_w[i].r) {
4271 for (
unsigned int j = 0; j < m_nWires; ++j) {
4277 (m_w[i].x * m_w[i].x + m_w[i].y * m_w[i].y) / m_cotube));
4280 std::complex<double> zj(m_w[j].x, m_w[j].y);
4281 m_a[j][i] = -log(abs((1. / m_cotube) * (zi - zj) /
4282 (1. - conj(zi) * zj / m_cotube2)));
4288 for (
unsigned int j = 0; j < m_nWires; ++j) {
4292 -log(abs(m_w[i].r * m_mtube *
pow(zi, m_mtube - 1) /
4293 (
pow(m_cotube, m_mtube) *
4294 (1. -
pow((abs(zi) / m_cotube), 2 * m_mtube)))));
4297 std::complex<double> zj(m_w[j].x, m_w[j].y);
4298 m_a[j][i] = -log(abs((1 /
pow(m_cotube, m_mtube)) *
4299 (
pow(zj, m_mtube) -
pow(zi, m_mtube)) /
4300 (1. -
pow(zj * conj(zi) / m_cotube2, m_mtube))));
4309bool ComponentAnalyticField::SetupD30() {
4318 wmap.assign(m_nWires, std::complex<double>(0., 0.));
4320 std::complex<double> wd = std::complex<double>(0., 0.);
4323 m_kappa = tgamma((m_ntube + 1.) / m_ntube) *
4324 tgamma((m_ntube - 2.) / m_ntube) / tgamma((m_ntube - 1.) / m_ntube);
4326 for (
unsigned int i = 0; i < m_nWires; ++i) {
4328 ConformalMap(std::complex<double>(m_w[i].x, m_w[i].y) / m_cotube, wmap[i],
4332 abs((m_w[i].r / m_cotube) * wd / (1. -
pow(abs(wmap[i]), 2))));
4334 for (
unsigned int j = 0; j < i; ++j) {
4336 -log(abs((wmap[i] - wmap[j]) / (1. - conj(wmap[i]) * wmap[j])));
4338 m_a[j][i] = m_a[i][j];
4345bool ComponentAnalyticField::Charge() {
4354 std::vector<double> b(m_nWires, 0.);
4355 for (
unsigned int i = 0; i < m_nWires; ++i) {
4356 b[i] = m_w[i].v - (m_corvta * m_w[i].x + m_corvtb * m_w[i].y + m_corvtc);
4361 if (!(m_ynplan[0] || m_ynplan[1] || m_ynplan[2] || m_ynplan[3] || m_tube)) {
4364 m_a.resize(m_nWires + 1);
4365 m_a[m_nWires].clear();
4366 for (
unsigned int i = 0; i < m_nWires; ++i) {
4367 m_a[i].push_back(1.);
4368 m_a[m_nWires].push_back(1.);
4370 m_a[m_nWires].push_back(0.);
4373 std::cerr <<
m_className <<
"::Charge: Matrix inversion failed.\n";
4377 if (m_a[m_nWires][m_nWires] != 0.) {
4378 const double t = 1. / m_a[m_nWires][m_nWires];
4379 for (
unsigned int i = 0; i < m_nWires; ++i) {
4380 for (
unsigned int j = 0; j < m_nWires; ++j) {
4381 m_a[i][j] -= t * m_a[i][m_nWires] * m_a[m_nWires][j];
4386 <<
" True inverse of the capacitance matrix"
4387 <<
" could not be calculated.\n";
4395 std::cerr <<
m_className <<
"::Charge: Matrix inversion failed.\n";
4405 <<
" Failure to solve the capacitance equations.\n"
4406 <<
" No charges are available.\n";
4411 for (
unsigned int i = 0; i < m_nWires; ++i) m_w[i].e = b[i];
4416 std::cout <<
" Dump of the capacitance matrix after inversion:\n";
4417 for (
unsigned int i = 0; i < m_nWires; i += 10) {
4418 for (
unsigned int j = 0; j < m_nWires; j += 10) {
4419 std::cout <<
" (Block " << i / 10 <<
", " << j / 10 <<
")\n";
4420 for (
unsigned int ii = 0; ii < 10; ++ii) {
4421 if (i + ii >= m_nWires)
break;
4422 for (
unsigned int jj = 0; jj < 10; ++jj) {
4423 if (j + jj >= m_nWires)
break;
4424 std::cout << std::setw(6) << m_a[i + ii][j + jj] <<
" ";
4432 std::cout <<
" End of the inverted capacitance matrix.\n";
4436 if (m_chargeCheck) {
4438 std::cout <<
" Quality check of the charge calculation.\n";
4439 std::cout <<
" Wire E as obtained E reconstructed\n";
4440 for (
unsigned int i = 0; i < m_nWires; ++i) {
4442 for (
unsigned int j = 0; j < m_nWires; ++j) {
4445 (m_corvta * m_w[j].x + m_corvtb * m_w[j].y + m_corvtc));
4447 std::cout <<
" " << i <<
" " << m_w[i].e <<
" " << b[i]
4454double ComponentAnalyticField::Ph2(
const double xpos,
const double ypos)
const {
4469 std::complex<double> zeta = m_zmult * std::complex<double>(xpos, ypos);
4470 if (
fabs(imag(zeta)) < 10.) {
4471 std::complex<double> zsin =
sin(zeta);
4472 std::complex<double> zcof = 4. * zsin * zsin - 2.;
4473 std::complex<double> zu = -m_p1 - zcof * m_p2;
4474 std::complex<double> zunew = 1. - zcof * zu - m_p2;
4475 std::complex<double> zterm = (zunew + zu) * zsin;
4476 return -log(abs(zterm));
4479 return -
fabs(imag(zeta)) + CLog2;
4482void ComponentAnalyticField::ConformalMap(
const std::complex<double>& z,
4483 std::complex<double>& ww,
4484 std::complex<double>& wd)
const {
4497 constexpr std::array<std::array<double, 16>, 6> cc1 = {
4498 {{{0.1000000000e+01, -.1666666865e+00, 0.3174602985e-01, -.5731921643e-02,
4499 0.1040112227e-02, -.1886279933e-03, 0.3421107249e-04, -.6204730198e-05,
4500 0.1125329618e-05, -.2040969207e-06, 0.3701631357e-07, -.6713513301e-08,
4501 0.1217605794e-08, -.2208327132e-09, 0.4005162868e-10,
4503 {{0.1000000000e+01, -.1000000238e+00, 0.8333332837e-02, -.7051283028e-03,
4504 0.5967194738e-04, -.5049648280e-05, 0.4273189802e-06, -.3616123934e-07,
4505 0.3060091514e-08, -.2589557457e-09, 0.2191374859e-10, -.1854418528e-11,
4506 0.1569274224e-12, -.1327975205e-13, 0.1123779363e-14,
4508 {{0.1000000000e+01, -.6666666269e-01, 0.1212121220e-02, -.2626262140e-03,
4509 -.3322110570e-04, -.9413293810e-05, -.2570029210e-05, -.7695705904e-06,
4510 -.2422486887e-06, -.7945993730e-07, -.2691839640e-07, -.9361642128e-08,
4511 -.3327319087e-08, -.1204430555e-08, -.4428404310e-09,
4513 {{0.1000000000e+01, -.4761904851e-01, -.1221001148e-02, -.3753788769e-03,
4514 -.9415557724e-04, -.2862767724e-04, -.9587882232e-05, -.3441659828e-05,
4515 -.1299798896e-05, -.5103651119e-06, -.2066504408e-06, -.8578405186e-07,
4516 -.3635090096e-07, -.1567239494e-07, -.6857355572e-08,
4518 {{0.1000000000e+01, -.3571428731e-01, -.2040816238e-02, -.4936389159e-03,
4519 -.1446709794e-03, -.4963850370e-04, -.1877940667e-04, -.7600909157e-05,
4520 -.3232265954e-05, -.1427365532e-05, -.6493634714e-06, -.3026190711e-06,
4521 -.1438593245e-06, -.6953911225e-07, -.3409525462e-07,
4523 {{0.1000000000e+01, -.2777777612e-01, -.2246732125e-02, -.5571441725e-03,
4524 -.1790652314e-03, -.6708275760e-04, -.2766949183e-04, -.1219387286e-04,
4525 -.5640039490e-05, -.2706697160e-05, -.1337270078e-05, -.6763995657e-06,
4526 -.3488264610e-06, -.1828456675e-06, -.9718036154e-07,
4527 -.5227070332e-07}}}};
4529 constexpr std::array<std::array<double, 16>, 6> cc2 = {
4530 {{{0.3333333135e+00, -.5555555597e-01, 0.1014109328e-01, -.1837154618e-02,
4531 0.3332451452e-03, -.6043842586e-04, 0.1096152027e-04, -.1988050826e-05,
4532 0.3605655365e-06, -.6539443120e-07, 0.1186035448e-07, -.2151069323e-08,
4533 0.3901317047e-09, -.7075676156e-10, 0.1283289534e-10,
4535 {{0.1000000000e+01, -.5000000000e+00, 0.3000000119e+00, -.1750000119e+00,
4536 0.1016666889e+00, -.5916666612e-01, 0.3442307562e-01, -.2002724260e-01,
4537 0.1165192947e-01, -.6779119372e-02, 0.3944106400e-02, -.2294691978e-02,
4538 0.1335057430e-02, -.7767395582e-03, 0.4519091453e-03,
4540 {{0.1248050690e+01, -.7788147926e+00, 0.6355384588e+00, -.4899077415e+00,
4541 0.3713272810e+00, -.2838423252e+00, 0.2174729109e+00, -.1663445234e+00,
4542 0.1271933913e+00, -.9728997946e-01, 0.7442557812e-01, -.5692918226e-01,
4543 0.4354400188e-01, -.3330700099e-01, 0.2547712997e-01,
4545 {{0.1333333015e+01, -.8888888955e+00, 0.8395061493e+00, -.7242798209e+00,
4546 0.6016069055e+00, -.5107235312e+00, 0.4393203855e+00, -.3745460510e+00,
4547 0.3175755739e+00, -.2703750730e+00, 0.2308617830e+00, -.1966916919e+00,
4548 0.1672732830e+00, -.1424439549e+00, 0.1214511395e+00,
4550 {{0.1359752655e+01, -.9244638681e+00, 0.9593217969e+00, -.8771237731e+00,
4551 0.7490229011e+00, -.6677658558e+00, 0.6196745634e+00, -.5591596961e+00,
4552 0.4905325770e+00, -.4393517375e+00, 0.4029803872e+00, -.3631100059e+00,
4553 0.3199430704e+00, -.2866140604e+00, 0.2627358437e+00,
4555 {{0.1362840652e+01, -.9286670089e+00, 0.1035511017e+01, -.9800255299e+00,
4556 0.8315343261e+00, -.7592730522e+00, 0.7612683773e+00, -.7132136226e+00,
4557 0.6074471474e+00, -.5554352999e+00, 0.5699443221e+00, -.5357525349e+00,
4558 0.4329345822e+00, -.3916820884e+00, 0.4401986003e+00,
4559 -.4197303057e+00}}}};
4561 constexpr int nterm = 15;
4566 }
else if (abs(z) < 0.75) {
4568 std::complex<double> zterm =
pow(m_kappa * z, m_ntube);
4569 std::complex<double> wdsum = 0.;
4570 std::complex<double> wsum = cc1[m_ntube - 3][nterm];
4571 for (
int i = nterm; i--;) {
4572 wdsum = wsum + zterm * wdsum;
4573 wsum = cc1[m_ntube - 3][i] + zterm * wsum;
4576 ww = m_kappa *
z * wsum;
4577 wd = m_kappa * (wsum + double(m_ntube) * zterm * wdsum);
4581 double arot = -TwoPi *
4582 int(round(atan2(imag(z), real(z)) * m_ntube / TwoPi)) /
4584 const std::complex<double> zz =
4585 z * std::complex<double>(
cos(arot),
sin(arot));
4587 std::complex<double> zterm =
4588 pow(m_kappa * (1. - zz), m_ntube / (m_ntube - 2.));
4589 std::complex<double> wdsum = 0.;
4590 std::complex<double> wsum = cc2[m_ntube - 3][nterm];
4591 for (
int i = nterm; i--;) {
4592 wdsum = wsum + zterm * wdsum;
4593 wsum = cc2[m_ntube - 3][i] + zterm * wsum;
4596 ww = std::complex<double>(
cos(arot), -
sin(arot)) * (1. - zterm * wsum);
4597 wd = m_ntube * m_kappa *
pow(m_kappa * (1. - zz), 2. / (m_ntube - 2.)) *
4598 (wsum + zterm * wdsum) / (m_ntube - 2.);
4602void ComponentAnalyticField::E2Sum(
const double xpos,
const double ypos,
4603 double& ex,
double& ey)
const {
4615 constexpr std::complex<double> icons(0., 1.);
4617 std::complex<double> wsum = 0.;
4618 for (
const auto& wire : m_w) {
4620 m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
4621 if (imag(zeta) > 15.) {
4622 wsum -= wire.e * icons;
4623 }
else if (imag(zeta) < -15.) {
4624 wsum += wire.e * icons;
4626 const auto zterm = Th1(zeta, m_p1, m_p2);
4627 wsum += wire.e * (zterm.second / zterm.first);
4630 ex = -real(-m_zmult * wsum);
4631 ey = imag(-m_zmult * wsum);
4634void ComponentAnalyticField::FieldA00(
const double xpos,
const double ypos,
4635 double& ex,
double& ey,
double& volt,
4636 const bool opt)
const {
4655 double xxmirr = 0., yymirr = 0.;
4657 for (
const auto& wire : m_w) {
4658 const double xx = xpos - wire.x;
4659 const double yy = ypos - wire.y;
4660 double r2 = xx * xx + yy * yy;
4662 double exhelp = xx / r2;
4663 double eyhelp = yy / r2;
4666 xxmirr = wire.x + (xpos - 2. * m_coplax);
4667 const double r2plan = xxmirr * xxmirr + yy * yy;
4668 exhelp -= xxmirr / r2plan;
4669 eyhelp -= yy / r2plan;
4674 yymirr = wire.y + (ypos - 2. * m_coplay);
4675 const double r2plan = xx * xx + yymirr * yymirr;
4676 exhelp -= xx / r2plan;
4677 eyhelp -= yymirr / r2plan;
4681 if (m_ynplax && m_ynplay) {
4682 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
4683 exhelp += xxmirr / r2plan;
4684 eyhelp += yymirr / r2plan;
4688 if (opt) volt -= 0.5 * wire.e * log(r2);
4689 ex += wire.e * exhelp;
4690 ey += wire.e * eyhelp;
4694void ComponentAnalyticField::FieldB1X(
const double xpos,
const double ypos,
4695 double& ex,
double& ey,
double& volt,
4696 const bool opt)
const {
4705 constexpr std::complex<double> icons(0., 1.);
4707 std::complex<double> ecompl;
4715 const double tx = Pi / m_sx;
4717 for (
const auto& wire : m_w) {
4718 const double xx = tx * (xpos - wire.x);
4719 const double yy = tx * (ypos - wire.y);
4723 }
else if (yy < -20.) {
4726 const std::complex<double> zz(xx, yy);
4727 const auto expzz =
exp(2. * icons * zz);
4728 ecompl = icons * (expzz + 1.) / (expzz - 1.);
4732 if (
fabs(yy) > 20.) r2 = -
fabs(yy) + CLog2;
4733 if (
fabs(yy) <= 20.) r2 = -0.5 * log(
pow(sinh(yy), 2) +
pow(
sin(xx), 2));
4737 const double yymirr = tx * (ypos + wire.y - 2. * m_coplay);
4740 }
else if (yymirr < -20.) {
4743 const std::complex<double> zzmirr(xx, yymirr);
4744 const auto expzzmirr =
exp(2. * icons * zzmirr);
4745 ecompl += -icons * (expzzmirr + 1.) / (expzzmirr - 1.);
4747 if (opt &&
fabs(yymirr) > 20.) r2 +=
fabs(yymirr) - CLog2;
4748 if (opt &&
fabs(yymirr) <= 20.)
4749 r2 += 0.5 * log(
pow(sinh(yymirr), 2) +
pow(
sin(xx), 2));
4752 ex += wire.e * real(ecompl);
4753 ey -= wire.e * imag(ecompl);
4754 if (opt) volt += wire.e * r2;
4760void ComponentAnalyticField::FieldB1Y(
const double xpos,
const double ypos,
4761 double& ex,
double& ey,
double& volt,
4762 const bool opt)
const {
4771 std::complex<double> ecompl;
4779 const double ty = Pi / m_sy;
4781 for (
const auto& wire : m_w) {
4782 const double xx = ty * (xpos - wire.x);
4783 const double yy = ty * (ypos - wire.y);
4787 }
else if (xx < -20.) {
4790 const std::complex<double> zz(xx, yy);
4791 const auto expzz =
exp(2. * zz);
4792 ecompl = (expzz + 1.) / (expzz - 1.);
4795 if (
fabs(xx) > 20.) r2 = -
fabs(xx) + CLog2;
4796 if (
fabs(xx) <= 20.) r2 = -0.5 * log(
pow(sinh(xx), 2) +
pow(
sin(yy), 2));
4800 const double xxmirr = ty * (xpos + wire.x - 2. * m_coplax);
4803 }
else if (xxmirr < -20.) {
4806 const std::complex<double> zzmirr(xxmirr, yy);
4807 const auto expzzmirr =
exp(2. * zzmirr);
4808 ecompl -= (expzzmirr + 1.) / (expzzmirr - 1.);
4810 if (opt &&
fabs(xxmirr) > 20.) r2 +=
fabs(xxmirr) - CLog2;
4811 if (opt &&
fabs(xxmirr) <= 20.)
4812 r2 += 0.5 * log(
pow(sinh(xxmirr), 2) +
pow(
sin(yy), 2));
4815 ex += wire.e * real(ecompl);
4816 ey -= wire.e * imag(ecompl);
4817 if (opt) volt += wire.e * r2;
4823void ComponentAnalyticField::FieldB2X(
const double xpos,
const double ypos,
4824 double& ex,
double& ey,
double& volt,
4825 const bool opt)
const {
4839 const double tx = HalfPi / m_sx;
4841 for (
unsigned int i = 0; i < m_nWires; ++i) {
4842 const double xx = tx * (xpos - m_w[i].x);
4843 const double yy = tx * (ypos - m_w[i].y);
4844 const double xxneg = tx * (xpos - m_w[i].x - 2 * m_coplax);
4846 std::complex<double> ecompl(0., 0.);
4848 if (
fabs(yy) <= 20.) {
4849 const std::complex<double> zz(xx, yy);
4850 const std::complex<double> zzneg(xxneg, yy);
4851 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
4853 const double sinhy = sinh(yy);
4854 const double sinxx =
sin(xx);
4855 const double sinxxneg =
sin(xxneg);
4856 r2 = (sinhy * sinhy + sinxx * sinxx) /
4857 (sinhy * sinhy + sinxxneg * sinxxneg);
4862 const double yymirr = tx * (ypos + m_w[i].y - 2 * m_coplay);
4863 if (
fabs(yymirr) <= 20.) {
4864 const std::complex<double> zzmirr(xx, yymirr);
4865 const std::complex<double> zznmirr(xxneg, yymirr);
4866 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
4868 const double sinhy = sinh(yymirr);
4869 const double sinxx =
sin(xx);
4870 const double sinxxneg =
sin(xxneg);
4871 const double r2plan = (sinhy * sinhy + sinxx * sinxx) /
4872 (sinhy * sinhy + sinxxneg * sinxxneg);
4878 ex += m_w[i].e * real(ecompl);
4879 ey -= m_w[i].e * imag(ecompl);
4880 if (opt) volt -= 0.5 * m_w[i].e * log(r2);
4886void ComponentAnalyticField::FieldB2Y(
const double xpos,
const double ypos,
4887 double& ex,
double& ey,
double& volt,
4888 const bool opt)
const {
4898 const std::complex<double> icons(0., 1.);
4904 const double ty = HalfPi / m_sy;
4906 for (
unsigned int i = 0; i < m_nWires; ++i) {
4907 const double xx = ty * (xpos - m_w[i].x);
4908 const double yy = ty * (ypos - m_w[i].y);
4909 const double yyneg = ty * (ypos + m_w[i].y - 2 * m_coplay);
4911 std::complex<double> ecompl(0., 0.);
4913 if (
fabs(xx) <= 20.) {
4914 const std::complex<double> zz(xx, yy);
4915 const std::complex<double> zzneg(xx, yyneg);
4916 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
4918 const double sinhx = sinh(xx);
4919 const double sinyy =
sin(yy);
4920 const double sinyyneg =
sin(yyneg);
4921 r2 = (sinhx * sinhx + sinyy * sinyy) /
4922 (sinhx * sinhx + sinyyneg * sinyyneg);
4927 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
4928 if (
fabs(xxmirr) <= 20.) {
4929 const std::complex<double> zzmirr(xxmirr, yy);
4930 const std::complex<double> zznmirr(xxmirr, yyneg);
4932 icons * m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
4934 const double sinhx = sinh(xxmirr);
4935 const double sinyy =
sin(yy);
4936 const double sinyyneg =
sin(yyneg);
4937 const double r2plan = (sinhx * sinhx + sinyy * sinyy) /
4938 (sinhx * sinhx + sinyyneg * sinyyneg);
4944 ex += m_w[i].e * real(ecompl);
4945 ey -= m_w[i].e * imag(ecompl);
4946 if (opt) volt -= 0.5 * m_w[i].e * log(r2);
4952void ComponentAnalyticField::FieldC10(
const double xpos,
const double ypos,
4953 double& ex,
double& ey,
double& volt,
4954 const bool opt)
const {
4963 if (m_mode == 0) volt = m_v0 + m_c1 * xpos;
4964 if (m_mode == 1) volt = m_v0 + m_c1 * ypos;
4965 for (
const auto& wire : m_w) {
4966 volt += wire.e * Ph2(xpos - wire.x, ypos - wire.y);
4971 E2Sum(xpos, ypos, ex, ey);
4972 if (m_mode == 0) ex -= m_c1;
4973 if (m_mode == 1) ey -= m_c1;
4976void ComponentAnalyticField::FieldC2X(
const double xpos,
const double ypos,
4977 double& ex,
double& ey,
double& volt,
4978 const bool opt)
const {
4985 constexpr std::complex<double> icons(0., 1.);
4988 std::complex<double> wsum1 = 0.;
4989 std::complex<double> wsum2 = 0.;
4993 for (
const auto& wire : m_w) {
4995 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
4996 if (imag(zeta) > 15.) {
4997 wsum1 -= wire.e * icons;
4998 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
4999 }
else if (imag(zeta) < -15.) {
5000 wsum1 += wire.e * icons;
5001 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5003 const auto zterm = Th1(zeta, m_p1, m_p2);
5004 wsum1 += wire.e * (zterm.second / zterm.first);
5005 if (opt) volt -= wire.e * log(abs(zterm.first));
5008 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
5011 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
5012 if (imag(zeta) > 15.) {
5013 wsum2 -= wire.e * icons;
5014 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5015 }
else if (imag(zeta) < -15.) {
5016 wsum2 += wire.e * icons;
5017 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5019 const auto zterm = Th1(zeta, m_p1, m_p2);
5020 wsum2 += wire.e * (zterm.second / zterm.first);
5021 if (opt) volt += wire.e * log(abs(zterm.first));
5024 if (opt && m_mode == 0) {
5025 volt -= TwoPi * wire.e * (xpos - cx) * (wire.x - cx) / (m_sx * m_sy);
5029 ex = real(m_zmult * (wsum1 + wsum2));
5030 ey = -imag(m_zmult * (wsum1 - wsum2));
5032 if (m_mode == 0) ex -= m_c1;
5035void ComponentAnalyticField::FieldC2Y(
const double xpos,
const double ypos,
5036 double& ex,
double& ey,
double& volt,
5037 const bool opt)
const {
5044 constexpr std::complex<double> icons(0., 1.);
5048 std::complex<double> wsum1 = 0.;
5049 std::complex<double> wsum2 = 0.;
5052 for (
const auto& wire : m_w) {
5054 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
5055 if (imag(zeta) > 15.) {
5056 wsum1 -= wire.e * icons;
5057 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5058 }
else if (imag(zeta) < -15.) {
5059 wsum1 += wire.e * icons;
5060 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5062 const auto zterm = Th1(zeta, m_p1, m_p2);
5063 wsum1 += wire.e * (zterm.second / zterm.first);
5064 if (opt) volt -= wire.e * log(abs(zterm.first));
5067 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
5070 m_zmult * std::complex<double>(xpos - wire.x, 2 * cy - ypos - wire.y);
5071 if (imag(zeta) > 15.) {
5072 wsum2 -= wire.e * icons;
5073 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5074 }
else if (imag(zeta) < -15.) {
5075 wsum2 += wire.e * icons;
5076 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5078 const auto zterm = Th1(zeta, m_p1, m_p2);
5079 wsum2 += wire.e * (zterm.second / zterm.first);
5080 if (opt) volt += wire.e * log(abs(zterm.first));
5083 if (opt && m_mode == 1) {
5084 volt -= TwoPi * wire.e * (ypos - cy) * (wire.y - cy) / (m_sx * m_sy);
5088 ex = real(m_zmult * (wsum1 - wsum2));
5089 ey = -imag(m_zmult * (wsum1 + wsum2));
5091 if (m_mode == 1) ey -= m_c1;
5094void ComponentAnalyticField::FieldC30(
const double xpos,
const double ypos,
5095 double& ex,
double& ey,
double& volt,
5096 const bool opt)
const {
5103 constexpr std::complex<double> icons(0., 1.);
5106 std::complex<double> wsum1 = 0.;
5107 std::complex<double> wsum2 = 0.;
5108 std::complex<double> wsum3 = 0.;
5109 std::complex<double> wsum4 = 0.;
5113 for (
const auto& wire : m_w) {
5115 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
5116 if (imag(zeta) > 15.) {
5117 wsum1 -= wire.e * icons;
5118 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5119 }
else if (imag(zeta) < -15.) {
5120 wsum1 += wire.e * icons;
5121 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5123 const auto zterm = Th1(zeta, m_p1, m_p2);
5124 wsum1 += wire.e * (zterm.second / zterm.first);
5125 if (opt) volt -= wire.e * log(abs(zterm.first));
5128 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
5131 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
5132 if (imag(zeta) > 15.) {
5133 wsum2 -= wire.e * icons;
5134 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5135 }
else if (imag(zeta) < -15.) {
5136 wsum2 += wire.e * icons;
5137 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5139 const auto zterm = Th1(zeta, m_p1, m_p2);
5140 wsum2 += wire.e * (zterm.second / zterm.first);
5141 if (opt) volt += wire.e * log(abs(zterm.first));
5144 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
5147 m_zmult * std::complex<double>(xpos - wire.x, 2. * cy - ypos - wire.y);
5148 if (imag(zeta) > 15.) {
5149 wsum3 -= wire.e * icons;
5150 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5151 }
else if (imag(zeta) < -15.) {
5152 wsum3 += wire.e * icons;
5153 if (opt) volt += wire.e * (
fabs(imag(zeta)) - CLog2);
5155 const auto zterm = Th1(zeta, m_p1, m_p2);
5156 wsum3 += wire.e * (zterm.second / zterm.first);
5157 if (opt) volt += wire.e * log(abs(zterm.first));
5160 zeta = m_zmult * std::complex<double>(2. * cx - xpos - wire.x,
5161 2. * cy - ypos - wire.y);
5162 if (imag(zeta) > 15.) {
5163 wsum4 -= wire.e * icons;
5164 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5165 }
else if (imag(zeta) < -15.) {
5166 wsum4 += wire.e * icons;
5167 if (opt) volt -= wire.e * (
fabs(imag(zeta)) - CLog2);
5169 const auto zterm = Th1(zeta, m_p1, m_p2);
5170 wsum4 += wire.e * (zterm.second / zterm.first);
5171 if (opt) volt -= wire.e * log(abs(zterm.first));
5175 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
5176 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
5179void ComponentAnalyticField::FieldD10(
const double xpos,
const double ypos,
5180 double& ex,
double& ey,
double& volt,
5181 const bool opt)
const {
5197 const std::complex<double> zpos = std::complex<double>(xpos, ypos);
5199 for (
const auto& wire : m_w) {
5201 const std::complex<double> zi(wire.x, wire.y);
5205 log(abs(m_cotube * (zpos - zi) / (m_cotube2 - zpos * conj(zi))));
5208 const std::complex<double> wi =
5209 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
5210 ex += wire.e * real(wi);
5211 ey += wire.e * imag(wi);
5215void ComponentAnalyticField::FieldD20(
const double xpos,
const double ypos,
5216 double& ex,
double& ey,
double& volt,
5217 const bool opt)
const {
5233 const std::complex<double> zpos = std::complex<double>(xpos, ypos);
5235 for (
const auto& wire : m_w) {
5237 const std::complex<double> zi(wire.x, wire.y);
5239 if (abs(zi) > wire.r) {
5243 wire.e * log(abs((1. /
pow(m_cotube, m_mtube)) *
5244 (
pow(zpos, m_mtube) -
pow(zi, m_mtube)) /
5245 (1. -
pow(zpos * conj(zi) / m_cotube2, m_mtube))));
5248 const std::complex<double> wi =
5249 double(m_mtube) *
pow(conj(zpos), m_mtube - 1) *
5250 (1. / conj(
pow(zpos, m_mtube) -
pow(zi, m_mtube)) +
5252 (
pow(m_cotube, 2 * m_mtube) -
pow(conj(zpos) * zi, m_mtube)));
5253 ex += wire.e * real(wi);
5254 ey += wire.e * imag(wi);
5258 volt -= wire.e * log(abs((1. / m_cotube) * (zpos - zi) /
5259 (1. - zpos * conj(zi) / m_cotube2)));
5261 const std::complex<double> wi =
5262 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
5264 ex += wire.e * real(wi);
5265 ey += wire.e * imag(wi);
5270void ComponentAnalyticField::FieldD30(
const double xpos,
const double ypos,
5271 double& ex,
double& ey,
double& volt,
5272 const bool opt)
const {
5287 std::complex<double> whelp;
5290 std::complex<double> wpos, wdpos;
5291 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
5293 for (
int i = m_nWires; i--;) {
5297 m_w[i].e * log(abs((wpos - wmap[i]) / (1. - wpos * conj(wmap[i]))));
5299 whelp = wdpos * (1. -
pow(abs(wmap[i]), 2)) /
5300 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
5302 ex += m_w[i].e * real(whelp);
5303 ey -= m_w[i].e * imag(whelp);
5309bool ComponentAnalyticField::InTube(
const double x0,
const double y0,
5310 const double a,
const int n)
const {
5319 if (x0 == 0. && y0 == 0.)
return true;
5323 if (x0 * x0 + y0 * y0 > a * a)
return false;
5327 if (n < 0 || n == 1 || n == 2) {
5329 std::cerr <<
" Invalid number of edges (n = " << n <<
")\n";
5335 double phi = atan2(y0, x0);
5336 if (phi < 0.)
phi += TwoPi;
5337 phi -= TwoPi * int(0.5 * n * phi / Pi) / n;
5339 if ((x0 * x0 + y0 * y0) *
pow(
cos(Pi / n - phi), 2) >
5340 a * a *
pow(
cos(Pi / n), 2))
5346void ComponentAnalyticField::Field3dA00(
const double xpos,
const double ypos,
5347 const double zpos,
double& ex,
5348 double& ey,
double& ez,
double& volt) {
5361 ex = ey = ez = volt = 0.;
5364 for (
const auto& charge : m_ch3d) {
5366 const double dx = xpos - charge.x;
5367 const double dy = ypos - charge.y;
5368 const double dz = zpos - charge.z;
5369 const double r =
sqrt(dx * dx + dy * dy + dz * dz);
5370 if (
fabs(r) < Small)
continue;
5371 const double r3 =
pow(r, 3);
5372 double exhelp = -dx / r3;
5373 double eyhelp = -dy / r3;
5374 double ezhelp = -dz / r3;
5375 double vhelp = 1. / r;
5377 double dxm = 0., dym = 0.;
5379 dxm = charge.x + xpos - 2 * m_coplax;
5380 const double rplan =
sqrt(dxm * dxm + dy * dy);
5381 if (
fabs(rplan) < Small)
continue;
5382 const double rplan3 =
pow(rplan, 3);
5383 exhelp += dxm / rplan3;
5384 eyhelp += dy / rplan3;
5385 ezhelp += dz / rplan3;
5386 vhelp -= 1. / rplan;
5390 dym = charge.y + ypos - 2. * m_coplay;
5391 const double rplan =
sqrt(dx * dx + dym * dym);
5392 if (
fabs(rplan) < Small)
continue;
5393 const double rplan3 =
pow(rplan, 3);
5394 exhelp += dx / rplan3;
5395 eyhelp += dym / rplan3;
5396 ezhelp += dz / rplan3;
5397 vhelp -= 1. / rplan;
5400 if (m_ynplax && m_ynplay) {
5401 const double rplan =
sqrt(dxm * dxm + dym * dym);
5402 if (
fabs(rplan) < Small)
continue;
5403 const double rplan3 =
pow(rplan, 3);
5404 exhelp -= dxm / rplan3;
5405 eyhelp -= dym / rplan3;
5406 ezhelp -= dz / rplan3;
5407 vhelp += 1. / rplan;
5410 ex -= charge.e * exhelp;
5411 ey -= charge.e * eyhelp;
5412 ez -= charge.e * ezhelp;
5413 volt += charge.e * vhelp;
5417void ComponentAnalyticField::Field3dB2X(
const double xpos,
const double ypos,
5418 const double zpos,
double& ex,
5419 double& ey,
double& ez,
double& volt) {
5429 const double rcut = 1.;
5431 double rr1, rr2, rm1, rm2, err, ezz;
5432 double exsum = 0., eysum = 0., ezsum = 0., vsum = 0.;
5433 double k0r, k1r, k0rm, k1rm;
5436 ex = ey = ez = volt = 0.;
5439 for (
const auto& charge : m_ch3d) {
5441 if (xpos == charge.x && ypos == charge.y && zpos == charge.z)
continue;
5442 const double dx = xpos - charge.x;
5443 const double dy = ypos - charge.y;
5444 const double dz = zpos - charge.z;
5445 const double dxm = xpos + charge.x - 2 * m_coplax;
5447 if (dy * dy + dz * dz >
pow(rcut * 2 * m_sx, 2)) {
5449 exsum = eysum = ezsum = vsum = 0.;
5451 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5453 const double rr = Pi * j *
sqrt(dy * dy + dz * dz) / m_sx;
5454 const double zzp = Pi * j * dx / m_sx;
5455 const double zzn = Pi * j * dxm / m_sx;
5465 const double czzp =
cos(zzp);
5466 const double czzn =
cos(zzn);
5467 vsum += (1. / m_sx) * k0r * (czzp - czzn);
5468 err = (TwoPi * j / (m_sx * m_sx)) * k1r * (czzp - czzn);
5469 ezz = (TwoPi * j / (m_sx * m_sx)) * k0r * (
sin(zzp) -
sin(zzn));
5471 eysum += err * dy /
sqrt(dy * dy + dz * dz);
5472 ezsum += err * dz /
sqrt(dy * dy + dz * dz);
5478 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5480 rr1 =
sqrt(
pow(dx + j * 2 * m_sx, 2) + dy * dy + dz * dz);
5481 rr2 =
sqrt(
pow(dx - j * 2 * m_sx, 2) + dy * dy + dz * dz);
5482 rm1 =
sqrt(
pow(dxm - j * 2 * m_sx, 2) + dy * dy + dz * dz);
5483 rm2 =
sqrt(
pow(dxm + j * 2 * m_sx, 2) + dy * dy + dz * dz);
5484 const double rr13 =
pow(rr1, 3);
5485 const double rm13 =
pow(rm1, 3);
5488 vsum = 1. / rr1 - 1. / rm1;
5489 exsum = dx / rr13 - dxm / rm13;
5490 eysum = dy * (1. / rr13 - 1. / rm13);
5491 ezsum = dz * (1. / rr13 - 1. / rm13);
5494 const double rr23 =
pow(rr2, 3);
5495 const double rm23 =
pow(rm2, 3);
5497 vsum += 1. / rr1 + 1. / rr2 - 1. / rm1 - 1. / rm2;
5498 exsum += (dx + j * 2 * m_sx) / rr13 + (dx - j * 2 * m_sx) / rr23 -
5499 (dxm - j * 2 * m_sx) / rm13 - (dxm + j * 2 * m_sx) / rm23;
5500 eysum += dy * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5501 ezsum += dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5506 const double dym = ypos + charge.y - 2. * m_coplay;
5507 if (dym * dym + dz * dz >
pow(rcut * 2 * m_sx, 2)) {
5510 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5512 const double rrm = Pi * j *
sqrt(dym * dym + dz * dz) / m_sx;
5513 const double zzp = Pi * j * dx / m_sx;
5514 const double zzn = Pi * j * dxm / m_sx;
5524 const double czzp =
cos(zzp);
5525 const double czzn =
cos(zzn);
5526 vsum += (1. / m_sx) * k0rm * (czzp - czzn);
5527 err = (TwoPi / (m_sx * m_sx)) * k1rm * (czzp - czzn);
5528 ezz = (TwoPi / (m_sx * m_sx)) * k0rm * (
sin(zzp) -
sin(zzn));
5530 eysum += err * dym /
sqrt(dym * dym + dz * dz);
5531 ezsum += err * dz /
sqrt(dym * dym + dz * dz);
5536 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5538 rr1 =
sqrt(
pow(dx + j * 2 * m_sx, 2) + dym * dym + dz * dz);
5539 rr2 =
sqrt(
pow(dx - j * 2 * m_sx, 2) + dym * dym + dz * dz);
5540 rm1 =
sqrt(
pow(dxm - j * 2 * m_sx, 2) + dym * dym + dz * dz);
5541 rm2 =
sqrt(
pow(dxm + j * 2 * m_sx, 2) + dym * dym + dz * dz);
5542 const double rr13 =
pow(rr1, 3);
5543 const double rm13 =
pow(rm1, 3);
5546 vsum += -1. / rr1 + 1. / rm1;
5547 exsum += -dx / rr13 + dxm / rm13;
5548 eysum += -dym * (1. / rr13 - 1. / rm13);
5549 ezsum += -dz * (1. / rr13 - 1. / rm13);
5552 const double rr23 =
pow(rr2, 3);
5553 const double rm23 =
pow(rm2, 3);
5555 vsum += -1. / rr1 - 1. / rr2 + 1. / rm1 + 1. / rm2;
5556 exsum += -(dx + j * 2 * m_sx) / rr13 - (dx - j * 2 * m_sx) / rr23 +
5557 (dxm - j * 2 * m_sx) / rm13 + (dxm + j * 2 * m_sx) / rm23;
5558 eysum += -dym * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5559 ezsum += -dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5563 ex += charge.e * exsum;
5564 ey += charge.e * eysum;
5565 ez += charge.e * ezsum;
5566 volt += charge.e * vsum;
5570void ComponentAnalyticField::Field3dB2Y(
const double xpos,
const double ypos,
5571 const double zpos,
double& ex,
5572 double& ey,
double& ez,
double& volt) {
5582 const double rcut = 1.;
5584 double rr1, rr2, rm1, rm2, err, ezz;
5585 double exsum = 0., eysum = 0., ezsum = 0., vsum = 0.;
5586 double k0r, k1r, k0rm, k1rm;
5589 ex = ey = ez = volt = 0.;
5592 for (
const auto& charge : m_ch3d) {
5594 if (xpos == charge.x && ypos == charge.y && zpos == charge.z)
continue;
5595 const double dx = xpos - charge.x;
5596 const double dy = ypos - charge.y;
5597 const double dz = zpos - charge.z;
5598 const double dym = ypos + charge.y - 2 * m_coplay;
5600 if (dx * dx + dz * dz >
pow(rcut * 2 * m_sy, 2)) {
5602 exsum = eysum = ezsum = vsum = 0.;
5604 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5606 const double rr = Pi * j *
sqrt(dx * dx + dz * dz) / m_sy;
5607 const double zzp = Pi * j * dy / m_sy;
5608 const double zzn = Pi * j * dym / m_sy;
5618 const double czzp =
cos(zzp);
5619 const double czzn =
cos(zzn);
5620 vsum += (1. / m_sy) * k0r * (czzp - czzn);
5621 err = (TwoPi * j / (m_sy * m_sy)) * k1r * (czzp - czzn);
5622 ezz = (TwoPi * j / (m_sy * m_sy)) * k0r * (
sin(zzp) -
sin(zzn));
5623 exsum += err * dx /
sqrt(dx * dx + dz * dz);
5624 ezsum += err * dz /
sqrt(dx * dx + dz * dz);
5631 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5633 rr1 =
sqrt(dx * dx + dz * dz +
pow(dy + j * 2 * m_sy, 2));
5634 rr2 =
sqrt(dx * dx + dz * dz +
pow(dy - j * 2 * m_sy, 2));
5635 rm1 =
sqrt(dx * dx + dz * dz +
pow(dym - j * 2 * m_sy, 2));
5636 rm2 =
sqrt(dx * dx + dz * dz +
pow(dym + j * 2 * m_sy, 2));
5637 const double rr13 =
pow(rr1, 3);
5638 const double rm13 =
pow(rm1, 3);
5641 vsum = 1. / rr1 - 1. / rm1;
5642 exsum = dx * (1. / rr13 - 1. / rm13);
5643 ezsum = dz * (1. / rr13 - 1. / rm13);
5644 eysum = dy / rr13 - dym / rm13;
5648 const double rr23 =
pow(rr2, 3);
5649 const double rm23 =
pow(rm2, 3);
5650 vsum += 1. / rr1 + 1. / rr2 - 1. / rm1 - 1. / rm2;
5651 exsum += dx * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5652 ezsum += dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5653 eysum += (dy + j * 2 * m_sy) / rr13 + (dy - j * 2 * m_sy) / rr23 -
5654 (dym - j * 2 * m_sy) / rm13 - (dym + j * 2 * m_sy) / rm23;
5659 const double dxm = xpos + charge.x - 2. * m_coplax;
5660 if (dxm * dxm + dz * dz >
pow(rcut * 2 * m_sy, 2)) {
5663 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5665 const double rrm = Pi * j *
sqrt(dxm * dxm + dz * dz) / m_sy;
5666 const double zzp = Pi * j * dy / m_sy;
5667 const double zzn = Pi * j * dym / m_sy;
5677 const double czzp =
cos(zzp);
5678 const double czzn =
cos(zzn);
5679 vsum += (1. / m_sy) * k0rm * (czzp - czzn);
5680 err = (TwoPi / (m_sy * m_sy)) * k1rm * (czzp - czzn);
5681 ezz = (TwoPi / (m_sy * m_sy)) * k0rm * (
sin(zzp) -
sin(zzn));
5682 exsum += err * dxm /
sqrt(dxm * dxm + dz * dz);
5683 ezsum += err * dz /
sqrt(dxm * dxm + dz * dz);
5689 for (
unsigned int j = 0; j <= m_nTermPoly; ++j) {
5691 rr1 =
sqrt(
pow(dy + j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5692 rr2 =
sqrt(
pow(dy - j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5693 rm1 =
sqrt(
pow(dym - j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5694 rm2 =
sqrt(
pow(dym + j * 2 * m_sy, 2) + dxm * dxm + dz * dz);
5695 const double rr13 =
pow(rr1, 3);
5696 const double rm13 =
pow(rm1, 3);
5699 vsum += -1. / rr1 + 1. / rm1;
5700 exsum += -dxm * (1. / rr13 - 1. / rm13);
5701 ezsum += -dz * (1. / rr13 - 1. / rm13);
5702 eysum += -dy / rr13 + dym / rm13;
5705 const double rr23 =
pow(rr2, 3);
5706 const double rm23 =
pow(rm2, 3);
5708 vsum += -1. / rr1 - 1. / rr2 + 1. / rm1 + 1. / rm2;
5709 exsum += -dxm * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5710 ezsum += -dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5711 eysum += -(dy + j * 2 * m_sy) / rr13 - (dy - j * 2 * m_sy) / rr23 +
5712 (dym - j * 2 * m_sy) / rm13 + (dym + j * 2 * m_sy) / rm23;
5716 ex += charge.e * exsum;
5717 ey += charge.e * eysum;
5718 ez += charge.e * ezsum;
5719 volt += charge.e * vsum;
5723void ComponentAnalyticField::Field3dD10(
const double xxpos,
const double yypos,
5724 const double zzpos,
double& eex,
5725 double& eey,
double& eez,
5736 const double rcut = 1.;
5738 double x3d, y3d, z3d;
5739 double exsum = 0., eysum = 0., ezsum = 0., vsum = 0.;
5740 double rr1, rr2, rm1, rm2, err, ezz;
5744 eex = eey = eez = volt = 0.;
5745 double ex = 0., ey = 0., ez = 0.;
5750 std::cerr <<
" Inappropriate potential function.\n";
5755 const double ssx = log(m_cotube / m_w[0].r);
5756 const double cpl = log(m_w[0].r);
5759 const double xpos = 0.5 * log(xxpos * xxpos + yypos * yypos);
5760 const double ypos = atan2(yypos, xxpos);
5761 const double zpos = zzpos;
5764 for (
const auto& charge : m_ch3d) {
5765 for (
int ii = -1; ii <= 1; ++ii) {
5767 x3d = 0.5 * log(charge.x * charge.x + charge.y * charge.y);
5768 y3d = atan2(charge.y, charge.x + ii * TwoPi);
5770 const double dx = xpos - x3d;
5771 const double dy = ypos - y3d;
5772 const double dz = zpos - z3d;
5773 const double dxm = xpos + x3d - 2 * cpl;
5775 if (xpos == x3d && ypos == y3d && zpos == z3d)
continue;
5777 if (dy * dy + dz * dz >
pow(rcut * 2 * ssx, 2)) {
5779 exsum = eysum = ezsum = vsum = 0.;
5781 for (
unsigned int j = 1; j <= m_nTermBessel; ++j) {
5783 const double rr = Pi * j *
sqrt(dy * dy + dz * dz) / ssx;
5784 const double zzp = Pi * j * dx / ssx;
5785 const double zzn = Pi * j * dxm / ssx;
5795 const double czzp =
cos(zzp);
5796 const double czzn =
cos(zzn);
5797 vsum += (1. / ssx) * k0r * (czzp - czzn);
5798 err = (j * TwoPi / (ssx * ssx)) * k1r * (czzp - czzn);
5799 ezz = (j * TwoPi / (ssx * ssx)) * k0r * (
sin(zzp) -
sin(zzn));
5801 eysum += err * dy /
sqrt(dy * dy + dz * dz);
5802 ezsum += err * dz /
sqrt(dy * dy + dz * dz);
5808 for (
unsigned int j = 0; j < m_nTermPoly; ++j) {
5810 rr1 =
sqrt(
pow(dx + j * 2 * ssx, 2) + dy * dy + dz * dz);
5811 rr2 =
sqrt(
pow(dx - j * 2 * ssx, 2) + dy * dy + dz * dz);
5812 rm1 =
sqrt(
pow(dxm - j * 2 * ssx, 2) + dy * dy + dz * dz);
5813 rm2 =
sqrt(
pow(dxm + j * 2 * ssx, 2) + dy * dy + dz * dz);
5814 const double rr13 =
pow(rr1, 3);
5815 const double rm13 =
pow(rm1, 3);
5818 vsum = 1. / rr1 - 1. / rm1;
5819 exsum = dxm / rr13 - dxm / rm13;
5820 eysum = dy * (1. / rr13 - 1. / rm13);
5821 ezsum = dz * (1. / rr13 - 1. / rm13);
5824 const double rr23 =
pow(rr2, 3);
5825 const double rm23 =
pow(rm2, 3);
5827 vsum += 1. / rr1 + 1. / rr2 - 1. / rm1 - 1. / rm2;
5828 exsum += (dx + j * 2 * ssx) / rr13 + (dx - j * 2 * ssx) / rr23 -
5829 (dxm - j * 2 * ssx) / rm13 - (dxm + j * 2 * ssx) / rm23;
5830 eysum += dy * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5831 ezsum += dz * (1. / rr13 + 1. / rr23 - 1. / rm13 - 1. / rm23);
5834 ex += charge.e * exsum;
5835 ey += charge.e * eysum;
5836 ez += charge.e * ezsum;
5842 eex =
exp(-xpos) * (ex *
cos(ypos) - ey *
sin(ypos));
5843 eey =
exp(-ypos) * (ex *
sin(ypos) + ey *
cos(ypos));
5847bool ComponentAnalyticField::PrepareSignals() {
5853 if (m_readout.empty()) {
5854 std::cerr <<
m_className <<
"::PrepareSignals:\n";
5855 std::cerr <<
" There are no readout groups defined.\n";
5856 std::cerr <<
" Calculation of weighting fields makes no sense.\n";
5860 if (!m_cellset && !Prepare()) {
5861 std::cerr <<
m_className <<
"::PrepareSignals: Cell not set up.\n";
5867 if (m_nFourier == 0) {
5868 m_cellTypeFourier = m_cellType;
5869 }
else if (m_cellType ==
A00 || m_cellType ==
B1X || m_cellType ==
B1Y ||
5870 m_cellType ==
C10) {
5871 m_cellTypeFourier =
A00;
5872 }
else if (m_cellType ==
B2X || m_cellType ==
C2X) {
5873 m_cellTypeFourier =
B2X;
5874 }
else if (m_cellType ==
B2Y || m_cellType ==
C2Y) {
5875 m_cellTypeFourier =
B2Y;
5876 }
else if (m_cellType ==
C30) {
5877 m_cellTypeFourier =
C30;
5878 }
else if (m_cellType ==
D10) {
5879 m_cellTypeFourier =
D10;
5880 }
else if (m_cellType ==
D30) {
5881 m_cellTypeFourier =
D30;
5885 <<
" No potentials available to handle cell type "
5891 m_fperx = m_fpery =
false;
5892 if (m_nFourier == 0) {
5895 if (m_cellType ==
B1X || m_cellType ==
C10 || m_cellType ==
C2Y) {
5898 if (m_cellType ==
B1Y || m_cellType ==
C10 || m_cellType ==
C2X) {
5901 m_mfexp = int(0.1 + log(1. * m_nFourier) / log(2.));
5903 m_fperx = m_fpery =
false;
5907 m_mxmin = m_mymin = m_mxmax = m_mymax = 0;
5909 m_mxmin = std::min(0, 1 - m_nFourier / 2);
5910 m_mxmax = m_nFourier / 2;
5913 m_mymin = std::min(0, 1 - m_nFourier / 2);
5914 m_mymax = m_nFourier / 2;
5920 <<
" Cell type: " <<
GetCellType(m_cellType) <<
"\n"
5921 <<
" Fourier cell type: " <<
GetCellType(m_cellTypeFourier)
5923 std::cout <<
" x convolutions: " << m_fperx <<
"\n"
5924 <<
" y convolutions: " << m_fpery <<
"\n";
5925 std::cout <<
" No of Fourier terms: " << m_nFourier <<
" (= 2**"
5926 << m_mfexp <<
")\n";
5930 if (!SetupWireSignals()) {
5931 std::cerr <<
m_className <<
"::PrepareSignals:\n";
5932 std::cerr <<
" Preparing wire signal capacitance matrices failed.\n";
5936 if (!SetupPlaneSignals()) {
5937 std::cerr <<
m_className <<
"::PrepareSignals:\n";
5938 std::cerr <<
" Preparing plane charges failed.\n";
5948 const unsigned int nReadout = m_readout.size();
5949 for (
unsigned int i = 0; i < nReadout; ++i) {
5950 for (
auto& wire : m_w) {
5951 if (wire.type == m_readout[i]) wire.ind = i;
5953 for (
unsigned int j = 0; j < 5; ++j) {
5954 if (m_planes[j].type == m_readout[i]) m_planes[j].ind = i;
5955 for (
auto& strip : m_planes[j].strips1) {
5956 if (strip.type == m_readout[i]) strip.ind = i;
5958 for (
auto& strip : m_planes[j].strips2) {
5959 if (strip.type == m_readout[i]) strip.ind = i;
5961 for (
auto& pixel : m_planes[j].pixels) {
5962 if (pixel.type == m_readout[i]) pixel.ind = i;
5972bool ComponentAnalyticField::SetupWireSignals() {
5985 m_sigmat.assign(m_nWires, std::vector<std::complex<double> >(m_nWires));
5987 std::vector<std::vector<std::complex<double> > > fftmat;
5989 if (m_fperx || m_fpery) {
5990 fftmat.resize(m_nFourier);
5991 for (
int i = 0; i < m_nFourier; ++i) {
5992 fftmat[i].resize(m_nWires);
5996 if (m_fperx || m_fpery) {
6007 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6008 for (
int my = m_mymin; my <= m_mymax; ++my) {
6010 if (m_cellTypeFourier ==
A00) {
6012 }
else if (m_cellTypeFourier ==
B2X) {
6014 }
else if (m_cellTypeFourier ==
B2Y) {
6016 }
else if (m_cellTypeFourier ==
C2X) {
6018 }
else if (m_cellTypeFourier ==
C2Y) {
6020 }
else if (m_cellTypeFourier ==
C30) {
6022 }
else if (m_cellTypeFourier ==
D10) {
6024 }
else if (m_cellTypeFourier ==
D30) {
6027 std::cerr <<
m_className <<
"::SetupWireSignals:\n";
6028 std::cerr <<
" Unknown signal cell type " << m_cellTypeFourier
6033 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6034 std::cout <<
" Signal matrix MX = " << mx <<
", MY = " << my
6035 <<
" has been calculated.\n";
6037 if (m_fperx || m_fpery) {
6045 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6046 std::cout <<
" Dump of signal matrix (" << mx <<
", " << my
6047 <<
") before inversion:\n";
6048 for (
unsigned int i = 0; i < m_nWires; i += 10) {
6049 for (
unsigned int j = 0; j < m_nWires; j += 10) {
6050 std::cout <<
" (Re-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6051 for (
unsigned int ii = 0; ii < 10; ++ii) {
6052 if (i + ii >= m_nWires)
break;
6053 for (
unsigned int jj = 0; jj < 10; ++jj) {
6054 if (j + jj >= m_nWires)
break;
6055 std::cout << real(m_sigmat[i + ii][j + jj]) <<
" ";
6060 std::cout <<
" (Im-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6061 for (
unsigned int ii = 0; ii < 10; ++ii) {
6062 if (i + ii >= m_nWires)
break;
6063 for (
unsigned int jj = 0; jj < 10; ++jj) {
6064 if (j + jj >= m_nWires)
break;
6065 std::cout << imag(m_sigmat[i + ii][j + jj]) <<
" ";
6072 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6073 std::cout <<
" End of the uninverted capacitance matrix dump.\n";
6080 if ((m_fperx && !m_fpery) || (m_fpery && !m_fperx)) {
6081 for (
unsigned int i = 0; i < m_nWires; ++i) {
6082 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6085 for (
unsigned int j = 0; j < m_nWires; ++j) {
6086 fftmat[m + m_nFourier / 2][j] = m_sigmat[i][j];
6089 for (
unsigned int j = 0; j < m_nWires; ++j) {
6092 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6095 for (
unsigned int j = 0; j < m_nWires; ++j) {
6096 m_sigmat[i][j] = fftmat[m + m_nFourier / 2][j];
6104 if (m_fperx || m_fpery) {
6105 for (
unsigned int i = 0; i < m_nWires; ++i) {
6106 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6107 for (
int my = m_mymin; my <= m_mymax; ++my) {
6110 for (
unsigned int j = 0; j < m_nWires; ++j) {
6111 fftmat[my + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6114 for (
unsigned int j = 0; j < m_nWires; ++j) {
6117 for (
int my = m_mymin; my <= m_mymax; ++my) {
6120 for (
unsigned int j = 0; j < m_nWires; ++j) {
6121 m_sigmat[i][j] = fftmat[my + m_nFourier / 2 - 1][j];
6127 for (
int my = m_mymin; my <= m_mymax; ++my) {
6128 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6131 for (
unsigned int j = 0; j < m_nWires; ++j) {
6132 fftmat[mx + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6135 for (
unsigned int j = 0; j < m_nWires; ++j) {
6138 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6141 for (
unsigned int j = 0; j < m_nWires; ++j) {
6142 m_sigmat[i][j] = fftmat[mx + m_nFourier / 2 - 1][j];
6152 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6153 for (
int my = m_mymin; my <= m_mymax; ++my) {
6155 if (m_fperx || m_fpery) {
6160 if (m_nWires >= 1) {
6162 std::cerr <<
m_className <<
"::PrepareWireSignals:\n";
6163 std::cerr <<
" Inversion of signal matrix (" << mx <<
", " << my
6165 std::cerr <<
" No reliable results.\n";
6166 std::cerr <<
" Preparation of weighting fields is abandoned.\n";
6171 if (m_fperx || m_fpery) {
6180 if ((m_fperx && !m_fpery) || (m_fpery && !m_fperx)) {
6181 for (
unsigned int i = 0; i < m_nWires; ++i) {
6182 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6185 for (
unsigned int j = 0; j < m_nWires; ++j) {
6186 fftmat[m + m_nFourier / 2][j] = m_sigmat[i][j];
6189 for (
unsigned int j = 0; j < m_nWires; ++j) {
6192 for (
int m = -m_nFourier / 2; m < m_nFourier / 2; ++m) {
6195 for (
unsigned int j = 0; j < m_nWires; ++j) {
6196 m_sigmat[i][j] = fftmat[m + m_nFourier / 2][j] / double(m_nFourier);
6204 if (m_fperx && m_fpery) {
6205 for (
unsigned int i = 0; i < m_nWires; ++i) {
6206 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6207 for (
int my = m_mymin; my <= m_mymax; ++my) {
6210 for (
unsigned int j = 0; j < m_nWires; ++j) {
6211 fftmat[my + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6214 for (
unsigned int j = 0; j < m_nWires; ++j) {
6217 for (
int my = m_mymin; my <= m_mymax; ++my) {
6220 for (
unsigned int j = 0; j < m_nWires; ++j) {
6222 fftmat[my + m_nFourier / 2 - 1][j] / double(m_nFourier);
6228 for (
int my = m_mymin; my <= m_mymax; ++my) {
6229 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6232 for (
unsigned int j = 0; j < m_nWires; ++j) {
6233 fftmat[mx + m_nFourier / 2 - 1][j] = m_sigmat[i][j];
6236 for (
unsigned int j = 0; j < m_nWires; ++j) {
6239 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6242 for (
unsigned int j = 0; j < m_nWires; ++j) {
6244 fftmat[mx + m_nFourier / 2 - 1][j] / double(m_nFourier);
6255 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6256 for (
int my = m_mymin; my <= m_mymax; ++my) {
6257 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6258 std::cout <<
" Dump of signal matrix (" << mx <<
", " << my
6259 <<
") after inversion:\n";
6260 for (
unsigned int i = 0; i < m_nWires; i += 10) {
6261 for (
unsigned int j = 0; j < m_nWires; j += 10) {
6262 std::cout <<
" (Re-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6263 for (
unsigned int ii = 0; ii < 10; ++ii) {
6264 if (i + ii >= m_nWires)
break;
6265 for (
unsigned int jj = 0; jj < 10; ++jj) {
6266 if (j + jj >= m_nWires)
break;
6267 std::cout << real(m_sigmat[i + ii][j + jj]) <<
" ";
6272 std::cout <<
" (Im-Block " << i / 10 <<
", " << j / 10 <<
")\n";
6273 for (
int ii = 0; ii < 10; ++ii) {
6274 if (i + ii >= m_nWires)
break;
6275 for (
int jj = 0; jj < 10; ++jj) {
6276 if (j + jj >= m_nWires)
break;
6277 std::cout << imag(m_sigmat[i + ii][j + jj]) <<
" ";
6284 std::cout <<
m_className <<
"::SetupWireSignals:\n";
6285 std::cout <<
" End of the inverted capacitance matrix dump.\n";
6292bool ComponentAnalyticField::SetupPlaneSignals() {
6299 const int nPlanes = 5;
6300 m_qplane.assign(nPlanes, std::vector<double>(m_nWires, 0.));
6305 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6306 for (
int my = m_mymin; my <= m_mymax; ++my) {
6315 m_qplane.assign(nPlanes, std::vector<double>(m_nWires, 0.));
6319 for (
unsigned int i = 0; i < m_nWires; ++i) {
6321 vw = -(m_coplan[1] - m_w[i].x) / (m_coplan[1] - m_coplan[0]);
6322 }
else if (m_perx) {
6323 vw = -(m_coplan[0] + m_sx - m_w[i].x) / m_sx;
6328 for (
unsigned int j = 0; j < m_nWires; ++j) {
6329 m_qplane[0][j] += real(m_sigmat[i][j]) * vw;
6336 for (
unsigned int i = 0; i < m_nWires; ++i) {
6338 vw = -(m_coplan[0] - m_w[i].x) / (m_coplan[0] - m_coplan[1]);
6339 }
else if (m_perx) {
6340 vw = -(m_w[i].x - m_coplan[1] + m_sx) / m_sx;
6345 for (
unsigned int j = 0; j < m_nWires; ++j) {
6346 m_qplane[1][j] += real(m_sigmat[i][j]) * vw;
6353 for (
unsigned int i = 0; i < m_nWires; ++i) {
6355 vw = -(m_coplan[3] - m_w[i].y) / (m_coplan[3] - m_coplan[2]);
6356 }
else if (m_pery) {
6357 vw = -(m_coplan[2] + m_sy - m_w[i].y) / m_sy;
6362 for (
unsigned int j = 0; j < m_nWires; ++j) {
6363 m_qplane[2][i] += real(m_sigmat[i][j]) * vw;
6370 for (
unsigned int i = 0; i < m_nWires; ++i) {
6372 vw = -(m_coplan[2] - m_w[i].y) / (m_coplan[2] - m_coplan[3]);
6373 }
else if (m_pery) {
6374 vw = -(m_w[i].y - m_coplan[3] + m_sy) / m_sy;
6379 for (
unsigned int j = 0; j < m_nWires; ++j) {
6380 m_qplane[3][i] += real(m_sigmat[i][j]) * vw;
6386 for (
unsigned int i = 0; i < m_nWires; ++i) {
6387 for (
unsigned int j = 0; j < m_nWires; ++j) {
6388 m_qplane[4][i] -= real(m_sigmat[i][j]);
6403 if (m_ynplan[0] && m_ynplan[1]) {
6404 m_planes[0].ewxcor = 1. / (m_coplan[1] - m_coplan[0]);
6405 m_planes[1].ewxcor = 1. / (m_coplan[0] - m_coplan[1]);
6406 }
else if (m_ynplan[0] && m_perx) {
6407 m_planes[0].ewxcor = 1. / m_sx;
6408 m_planes[1].ewxcor = 0.;
6409 }
else if (m_ynplan[1] && m_perx) {
6410 m_planes[0].ewxcor = 0.;
6411 m_planes[1].ewxcor = -1. / m_sx;
6413 m_planes[0].ewxcor = m_planes[1].ewxcor = 0.;
6415 m_planes[2].ewxcor = m_planes[3].ewxcor = m_planes[4].ewxcor = 0.;
6417 m_planes[0].ewycor = m_planes[1].ewycor = 0.;
6418 if (m_ynplan[2] && m_ynplan[3]) {
6419 m_planes[2].ewycor = 1. / (m_coplan[3] - m_coplan[2]);
6420 m_planes[3].ewycor = 1. / (m_coplan[2] - m_coplan[3]);
6421 }
else if (m_ynplan[2] && m_pery) {
6422 m_planes[2].ewycor = 1. / m_sy;
6423 m_planes[3].ewycor = 0.;
6424 }
else if (m_ynplan[3] && m_pery) {
6425 m_planes[2].ewycor = 0.;
6426 m_planes[3].ewycor = -1. / m_sy;
6428 m_planes[2].ewycor = m_planes[3].ewycor = 0.;
6431 m_planes[4].ewycor = 0.;
6435 std::cout <<
m_className <<
"::SetupPlaneSignals:\n";
6436 std::cout <<
" Charges for currents induced in the planes:\n";
6437 std::cout <<
" Wire x-Plane 1 x-Plane 2"
6438 <<
" y-Plane 1 y-Plane 2"
6440 for (
unsigned int i = 0; i < m_nWires; ++i) {
6441 std::cout <<
" " << i <<
" " << m_qplane[0][i] <<
" "
6442 << m_qplane[1][i] <<
" " << m_qplane[2][i] <<
" "
6443 << m_qplane[3][i] <<
" " << m_qplane[4][i] <<
"\n";
6445 std::cout <<
m_className <<
"::SetupPlaneSignals:\n";
6446 std::cout <<
" Bias fields:\n";
6447 std::cout <<
" Plane x-Bias [1/cm] y-Bias [1/cm]\n";
6448 for (
int i = 0; i < 4; ++i) {
6449 std::cout <<
" " << i <<
" " << m_planes[i].ewxcor <<
" "
6450 << m_planes[i].ewycor <<
"\n";
6457bool ComponentAnalyticField::IprA00(
const int mx,
const int my) {
6463 const double dx = mx * m_sx;
6464 const double dy = my * m_sy;
6467 for (
unsigned int i = 0; i < m_nWires; ++i) {
6469 if (dx != 0. || dy != 0.) {
6470 aa = dx * dx + dy * dy;
6472 aa = m_w[i].r * m_w[i].r;
6475 if (m_ynplax) aa /= 2. *
pow(m_w[i].x - m_coplax, 2) + dy * dy;
6476 if (m_ynplay) aa /= 2. *
pow(m_w[i].y - m_coplay, 2) + dx * dx;
6478 if (m_ynplax && m_ynplay)
6479 aa *= 4. * (
pow(m_w[i].x - m_coplax, 2) +
pow(m_w[i].y - m_coplay, 2));
6481 m_sigmat[i][i] = -0.5 * log(aa);
6482 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6483 aa =
pow(m_w[i].x + dx - m_w[j].x, 2) +
pow(m_w[i].y + dy - m_w[j].y, 2);
6486 aa /=
pow(2. * m_coplax - m_w[i].x - dx - m_w[j].x, 2) +
6487 pow(m_w[i].y + dy - m_w[j].y, 2);
6489 aa /=
pow(m_w[i].x + dx - m_w[j].x, 2) +
6490 pow(2. * m_coplay - m_w[i].y - dy - m_w[j].y, 2);
6492 if (m_ynplax && m_ynplay) {
6493 aa *=
pow(2. * m_coplax - m_w[i].x - dx - m_w[j].x, 2) +
6494 pow(2. * m_coplay - m_w[i].y - dy - m_w[j].y, 2);
6497 m_sigmat[i][j] = -0.5 * log(aa);
6498 m_sigmat[j][i] = m_sigmat[i][j];
6504bool ComponentAnalyticField::IprB2X(
const int my) {
6511 m_b2sin.resize(m_nWires);
6513 const double dy = my * m_sy;
6518 for (
unsigned int i = 0; i < m_nWires; ++i) {
6519 double xx = (Pi / m_sx) * (m_w[i].x - m_coplan[0]);
6521 aa =
pow(sinh(Pi * dy / m_sx) /
sin(xx), 2);
6523 aa =
pow((0.5 * m_w[i].r * Pi / m_sx) /
sin(xx), 2);
6527 const double yymirr = (Pi / m_sx) * (m_w[i].y - m_coplay);
6528 if (
fabs(yymirr) <= 20.) {
6529 const double sinhy = sinh(yymirr);
6530 const double sinxx =
sin(xx);
6531 aa *= (sinhy * sinhy + sinxx * sinxx) / (sinhy * sinhy);
6535 m_sigmat[i][i] = -0.5 * log(aa);
6537 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6538 const double yy = HalfPi * (m_w[i].y + dy - m_w[j].y) / m_sx;
6539 xx = HalfPi * (m_w[i].x - m_w[j].x) / m_sx;
6540 xxneg = HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplan[0]) / m_sx;
6541 if (
fabs(yy) <= 20.) {
6542 const double sinhy = sinh(yy);
6543 const double sinxx =
sin(xx);
6544 const double sinxxneg =
sin(xxneg);
6545 aa = (sinhy * sinhy + sinxx * sinxx) /
6546 (sinhy * sinhy + sinxxneg * sinxxneg);
6552 const double yymirr =
6553 HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplay) / m_sx;
6554 if (
fabs(yymirr) <= 20.) {
6555 const double sinhy = sinh(yymirr);
6556 const double sinxx =
sin(xx);
6557 const double sinxxneg =
sin(xxneg);
6558 aa *= (sinhy * sinhy + sinxxneg * sinxxneg) /
6559 (sinhy * sinhy + sinxx * sinxx);
6563 m_sigmat[i][j] = -0.5 * log(aa);
6564 m_sigmat[j][i] = m_sigmat[i][j];
6567 m_b2sin[i] =
sin(Pi * (m_coplan[0] - m_w[i].x) / m_sx);
6573bool ComponentAnalyticField::IprB2Y(
const int mx) {
6580 m_b2sin.resize(m_nWires);
6582 const double dx = mx * m_sx;
6584 double xx, yy, xxmirr, yyneg;
6587 for (
unsigned int i = 0; i < m_nWires; ++i) {
6588 yy = (Pi / m_sy) * (m_w[i].y - m_coplan[2]);
6590 aa =
pow(sinh(Pi * dx / m_sy) /
sin(yy), 2);
6592 aa =
pow((0.5 * m_w[i].r * Pi / m_sy) /
sin(yy), 2);
6596 xxmirr = (Pi / m_sy) * (m_w[i].x - m_coplax);
6597 if (
fabs(xxmirr) <= 20.) {
6598 aa *= (
pow(sinh(xxmirr), 2) +
pow(
sin(yy), 2)) /
pow(sinh(xxmirr), 2);
6602 m_sigmat[i][i] = -0.5 * log(aa);
6604 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6605 xx = HalfPi * (m_w[i].x + dx - m_w[j].x) / m_sy;
6606 yy = HalfPi * (m_w[i].y - m_w[j].y) / m_sy;
6607 yyneg = HalfPi * (m_w[i].y + m_w[j].y - 2. * m_coplan[2]) / m_sy;
6608 if (
fabs(xx) <= 20.) {
6609 aa = (
pow(sinh(xx), 2) +
pow(
sin(yy), 2)) /
6610 (
pow(sinh(xx), 2) +
pow(
sin(yyneg), 2));
6616 xxmirr = HalfPi * (m_w[i].x + m_w[j].x - 2. * m_coplax) / m_sy;
6617 if (
fabs(xxmirr) <= 20.) {
6618 aa *= (
pow(sinh(xxmirr), 2) +
pow(
sin(yyneg), 2)) /
6619 (
pow(sinh(xxmirr), 2) +
pow(
sin(yy), 2));
6623 m_sigmat[i][j] = -0.5 * log(aa);
6624 m_sigmat[j][i] = m_sigmat[i][j];
6627 m_b2sin[i] =
sin(Pi * (m_coplan[2] - m_w[i].y) / m_sy);
6632bool ComponentAnalyticField::IprC2X() {
6643 for (
unsigned int i = 0; i < m_nWires; ++i) {
6644 double cx = m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
6645 for (
unsigned int j = 0; j < m_nWires; ++j) {
6648 temp = (m_w[i].x - cx) * (m_w[j].x - cx) * TwoPi / (m_sx * m_sy);
6652 Ph2Lim(m_w[i].r) - Ph2(2. * (m_w[j].x - cx), 0.) - temp;
6655 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
6656 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) - temp;
6663bool ComponentAnalyticField::IprC2Y() {
6674 for (
unsigned int i = 0; i < m_nWires; ++i) {
6676 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
6677 for (
unsigned int j = 0; j < m_nWires; ++j) {
6680 temp = (m_w[i].y - cy) * (m_w[j].y - cy) * TwoPi / (m_sx * m_sy);
6684 Ph2Lim(m_w[i].r) - Ph2(0., 2. * (m_w[j].y - cy)) - temp;
6687 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
6688 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) - temp;
6695bool ComponentAnalyticField::IprC30() {
6705 for (
unsigned int i = 0; i < m_nWires; ++i) {
6707 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
6709 m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
6710 for (
unsigned int j = 0; j < m_nWires; ++j) {
6712 m_sigmat[i][i] = Ph2Lim(m_w[i].r) -
6713 Ph2(0., 2. * (m_w[i].y - cy)) -
6714 Ph2(2. * (m_w[i].x - cx), 0.) +
6715 Ph2(2. * (m_w[i].x - cx), 2. * (m_w[i].y - cy));
6718 Ph2(m_w[i].x - m_w[j].x, m_w[i].y - m_w[j].y) -
6719 Ph2(m_w[i].x - m_w[j].x, m_w[i].y + m_w[j].y - 2. * cy) -
6720 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y - m_w[j].y) +
6721 Ph2(m_w[i].x + m_w[j].x - 2. * cx, m_w[i].y + m_w[j].y - 2. * cy);
6728bool ComponentAnalyticField::IprD10() {
6736 for (
unsigned int i = 0; i < m_nWires; ++i) {
6738 m_sigmat[i][i] = -log(
6740 (m_cotube - (m_w[i].x * m_w[i].x + m_w[i].y * m_w[i].y) / m_cotube));
6742 std::complex<double> zi(m_w[i].x, m_w[i].y);
6744 for (
unsigned int j = i + 1; j < m_nWires; ++j) {
6746 std::complex<double> zj(m_w[j].x, m_w[j].y);
6747 m_sigmat[i][j] = -log(
6748 abs((1. / m_cotube) * (zi - zj) / (1. - conj(zi) * zj / m_cotube2)));
6750 m_sigmat[j][i] = m_sigmat[i][j];
6756bool ComponentAnalyticField::IprD30() {
6763 wmap.resize(m_nWires);
6765 std::complex<double> wd;
6768 for (
int i = 0; i < int(m_nWires); ++i) {
6770 ConformalMap(std::complex<double>(m_w[i].x, m_w[i].y) / m_cotube, wmap[i],
6773 m_sigmat[i][i] = -log(
6774 abs((m_w[i].r / m_cotube) * wd / (1. -
pow(abs(wmap[i]), 2))));
6776 for (
int j = 0; j < i - 1; ++j) {
6778 -log(abs((wmap[i] - wmap[j]) / (1. - conj(wmap[i]) * wmap[j])));
6780 m_sigmat[j][i] = m_sigmat[i][j];
6786bool ComponentAnalyticField::Wfield(
const double xin,
const double yin,
6787 const double zpos,
double& exsum,
6788 double& eysum,
double& ezsum,
double& vsum,
6789 const std::string& label,
6790 const bool opt)
const {
6797 exsum = eysum = ezsum = vsum = 0.;
6798 double ex = 0., ey = 0., ez = 0.;
6801 double xpos = xin, ypos = yin;
6802 if (m_polar) Cartesian2Internal(xin, yin, xpos, ypos);
6804 if (m_readout.empty())
return false;
6806 std::cerr <<
m_className <<
"::Wfield: No weighting fields available.\n";
6810 if (label.empty())
return volt;
6811 const auto it = std::find(m_readout.cbegin(), m_readout.cend(), label);
6812 if (it == m_readout.end())
return false;
6813 const auto isw = it - m_readout.begin();
6816 for (
int mx = m_mxmin; mx <= m_mxmax; ++mx) {
6817 for (
int my = m_mymin; my <= m_mymax; ++my) {
6828 for (
int iw = m_nWires; iw--;) {
6830 if (m_w[iw].ind != isw)
continue;
6832 if (m_cellTypeFourier ==
A00) {
6833 WfieldWireA00(xpos, ypos, ex, ey, volt, mx, my, iw, opt);
6834 }
else if (m_cellTypeFourier ==
B2X) {
6835 WfieldWireB2X(xpos, ypos, ex, ey, volt, my, iw, opt);
6836 }
else if (m_cellTypeFourier ==
B2Y) {
6837 WfieldWireB2Y(xpos, ypos, ex, ey, volt, mx, iw, opt);
6838 }
else if (m_cellTypeFourier ==
C2X) {
6839 WfieldWireC2X(xpos, ypos, ex, ey, volt, iw, opt);
6840 }
else if (m_cellTypeFourier ==
C2Y) {
6841 WfieldWireC2Y(xpos, ypos, ex, ey, volt, iw, opt);
6842 }
else if (m_cellTypeFourier ==
C30) {
6843 WfieldWireC30(xpos, ypos, ex, ey, volt, iw, opt);
6844 }
else if (m_cellTypeFourier ==
D10) {
6845 WfieldWireD10(xpos, ypos, ex, ey, volt, iw, opt);
6846 }
else if (m_cellTypeFourier ==
D30) {
6847 WfieldWireD30(xpos, ypos, ex, ey, volt, iw, opt);
6850 std::cerr <<
" Unknown signal field type " << m_cellTypeFourier
6851 <<
" received. Program error!\n";
6852 std::cerr <<
" Encountered for wire " << iw
6853 <<
", readout group = " << m_w[iw].ind <<
"\n";
6854 exsum = eysum = ezsum = vsum = 0.;
6860 if (opt) vsum += volt;
6872 for (
int ip = 0; ip < 5; ++ip) {
6874 if (m_planes[ip].ind != isw)
continue;
6876 if (m_cellTypeFourier ==
A00) {
6877 WfieldPlaneA00(xpos, ypos, ex, ey, volt, mx, my, ip, opt);
6878 }
else if (m_cellTypeFourier ==
B2X) {
6879 WfieldPlaneB2X(xpos, ypos, ex, ey, volt, my, ip, opt);
6880 }
else if (m_cellTypeFourier ==
B2Y) {
6881 WfieldPlaneB2Y(xpos, ypos, ex, ey, volt, mx, ip, opt);
6882 }
else if (m_cellTypeFourier ==
C2X) {
6883 WfieldPlaneC2X(xpos, ypos, ex, ey, volt, ip, opt);
6884 }
else if (m_cellTypeFourier ==
C2Y) {
6885 WfieldPlaneC2Y(xpos, ypos, ex, ey, volt, ip, opt);
6886 }
else if (m_cellTypeFourier ==
D10) {
6887 WfieldPlaneD10(xpos, ypos, ex, ey, volt, ip, opt);
6888 }
else if (m_cellTypeFourier ==
D30) {
6889 WfieldPlaneD30(xpos, ypos, ex, ey, volt, ip, opt);
6892 std::cerr <<
" Unkown field type " << m_cellTypeFourier
6893 <<
" received. Program error!\n";
6894 std::cerr <<
" Encountered for plane " << ip
6895 <<
", readout group = " << m_planes[ip].ind <<
"\n";
6896 exsum = eysum = ezsum = 0.;
6902 if (opt) vsum += volt;
6908 for (
int ip = 0; ip < 5; ++ip) {
6909 if (m_planes[ip].ind != isw)
continue;
6910 exsum += m_planes[ip].ewxcor;
6911 eysum += m_planes[ip].ewycor;
6913 if (ip == 0 || ip == 1) {
6916 xx -= m_sx * int(round(xpos / m_sx));
6917 if (m_ynplan[0] && xx <= m_coplan[0]) xx += m_sx;
6918 if (m_ynplan[1] && xx >= m_coplan[1]) xx -= m_sx;
6920 vsum += 1. - m_planes[ip].ewxcor * (xx - m_coplan[ip]);
6921 }
else if (ip == 2 || ip == 3) {
6924 yy -= m_sy * int(round(ypos / m_sy));
6925 if (m_ynplan[2] && yy <= m_coplan[2]) yy += m_sy;
6926 if (m_ynplan[3] && yy >= m_coplan[3]) yy -= m_sy;
6928 vsum += 1. - m_planes[ip].ewycor * (yy - m_coplan[ip]);
6933 for (
unsigned int ip = 0; ip < 5; ++ip) {
6934 for (
const auto& strip : m_planes[ip].strips1) {
6935 if (strip.ind != isw)
continue;
6936 WfieldStripXy(xpos, ypos, zpos, ex, ey, ez, volt, ip, strip, opt);
6940 if (opt) vsum += volt;
6942 for (
const auto& strip : m_planes[ip].strips2) {
6943 if (strip.ind != isw)
continue;
6944 WfieldStripZ(xpos, ypos, ex, ey, volt, ip, strip, opt);
6947 if (opt) vsum += volt;
6949 for (
const auto& pixel : m_planes[ip].pixels) {
6950 if (pixel.ind != isw)
continue;
6951 WfieldPixel(xpos, ypos, zpos, ex, ey, ez, volt, ip, pixel, opt);
6955 if (opt) vsum += volt;
6959 const double r =
exp(xpos);
6960 const double er = exsum / r;
6961 const double ep = eysum / r;
6962 const double theta = atan2(yin, xin);
6963 const double ct =
cos(theta);
6964 const double st =
sin(theta);
6965 exsum = +ct * er -
st * ep;
6966 eysum = +
st * er + ct * ep;
6971void ComponentAnalyticField::WfieldWireA00(
const double xpos,
const double ypos,
6972 double& ex,
double& ey,
double& volt,
6973 const int mx,
const int my,
6975 const bool opt)
const {
6988 ex = ey = volt = 0.;
6990 double xxmirr = 0., yymirr = 0.;
6992 for (
int i = m_nWires; i--;) {
6994 const double xx = xpos - m_w[i].x - mx * m_sx;
6995 const double yy = ypos - m_w[i].y - my * m_sy;
6997 double r2 = xx * xx + yy * yy;
6998 if (r2 <= 0.)
continue;
6999 double exhelp = xx / r2;
7000 double eyhelp = yy / r2;
7003 xxmirr = xpos + m_w[i].x - 2. * m_coplax;
7004 const double r2plan = xxmirr * xxmirr + yy * yy;
7005 if (r2plan <= 0.)
continue;
7006 exhelp -= xxmirr / r2plan;
7007 eyhelp -= yy / r2plan;
7012 yymirr = ypos + m_w[i].y - 2. * m_coplay;
7013 const double r2plan = xx * xx + yymirr * yymirr;
7014 if (r2plan <= 0.)
continue;
7015 exhelp -= xx / r2plan;
7016 eyhelp -= yymirr / r2plan;
7020 if (m_ynplax && m_ynplay) {
7021 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
7022 if (r2plan <= 0.)
continue;
7023 exhelp += xxmirr / r2plan;
7024 eyhelp += yymirr / r2plan;
7028 if (opt) volt -= 0.5 * real(m_sigmat[isw][i]) * log(r2);
7029 ex += real(m_sigmat[isw][i]) * exhelp;
7030 ey += real(m_sigmat[isw][i]) * eyhelp;
7034void ComponentAnalyticField::WfieldWireB2X(
const double xpos,
const double ypos,
7035 double& ex,
double& ey,
double& volt,
7036 const int my,
const int isw,
7037 const bool opt)
const {
7048 ex = ey = volt = 0.;
7050 const double tx = HalfPi / m_sx;
7052 for (
unsigned int i = 0; i < m_nWires; ++i) {
7053 const double xx = tx * (xpos - m_w[i].x);
7054 const double yy = tx * (ypos - m_w[i].y - my * m_sy);
7055 const double xxneg = tx * (xpos + m_w[i].x - 2 * m_coplan[0]);
7056 const std::complex<double> zz(xx, yy);
7057 const std::complex<double> zzneg(xxneg, yy);
7059 std::complex<double> ecompl(0., 0.);
7061 if (
fabs(yy) <= 20.) {
7062 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
7064 const double sinhy = sinh(yy);
7065 const double sinxx =
sin(xx);
7066 const double sinxxneg =
sin(xxneg);
7067 r2 = (sinhy * sinhy + sinxx * sinxx) /
7068 (sinhy * sinhy + sinxxneg * sinxxneg);
7073 const double yymirr = tx * (ypos + m_w[i].y - 2. * m_coplay);
7074 const std::complex<double> zzmirr(xx, yymirr);
7075 const std::complex<double> zznmirr(xxneg, yymirr);
7076 if (
fabs(yymirr) <= 20.) {
7077 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
7079 const double sinhy = sinh(yymirr);
7080 const double sinxx =
sin(xx);
7081 const double sinxxneg =
sin(xxneg);
7082 const double r2plan = (sinhy * sinhy + sinxx * sinxx) /
7083 (sinhy * sinhy + sinxxneg * sinxxneg);
7089 ex += real(m_sigmat[isw][i]) * real(ecompl);
7090 ey -= real(m_sigmat[isw][i]) * imag(ecompl);
7091 if (opt) volt -= 0.5 * real(m_sigmat[isw][i]) * log(r2);
7097void ComponentAnalyticField::WfieldWireB2Y(
const double xpos,
const double ypos,
7098 double& ex,
double& ey,
double& volt,
7099 const int mx,
const int isw,
7100 const bool opt)
const {
7110 constexpr std::complex<double> icons(0., 1.);
7113 ex = ey = volt = 0.;
7115 const double ty = HalfPi / m_sy;
7117 for (
unsigned int i = 0; i < m_nWires; ++i) {
7118 const double xx = ty * (xpos - m_w[i].x - mx * m_sx);
7119 const double yy = ty * (ypos - m_w[i].y);
7120 const double yyneg = ty * (ypos + m_w[i].y - 2. * m_coplan[2]);
7121 const std::complex<double> zz(xx, yy);
7122 const std::complex<double> zzneg(xx, yyneg);
7124 std::complex<double> ecompl(0., 0.);
7126 if (
fabs(xx) <= 20.) {
7127 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
7129 const double sinhx = sinh(xx);
7130 const double sinyy =
sin(yy);
7131 const double sinyyneg =
sin(yyneg);
7132 r2 = (sinhx * sinhx + sinyy * sinyy) /
7133 (sinhx * sinhx + sinyyneg * sinyyneg);
7138 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
7139 const std::complex<double> zzmirr(xxmirr, yy);
7140 const std::complex<double> zznmirr(xxmirr, yyneg);
7141 if (
fabs(xxmirr) <= 20.) {
7143 icons * m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
7145 const double sinhx = sinh(xxmirr);
7146 const double sinyy =
sin(yy);
7147 const double sinyyneg =
sin(yyneg);
7148 const double r2plan = (sinhx * sinhx + sinyy * sinyy) /
7149 (sinhx * sinhx + sinyyneg * sinyyneg);
7155 ex += real(m_sigmat[isw][i]) * real(ecompl);
7156 ey -= real(m_sigmat[isw][i]) * imag(ecompl);
7157 if (opt) volt -= 0.5 * real(m_sigmat[isw][i]) * log(r2);
7163void ComponentAnalyticField::WfieldWireC2X(
const double xpos,
const double ypos,
7164 double& ex,
double& ey,
double& volt,
7166 const bool opt)
const {
7174 constexpr std::complex<double> icons(0., 1.);
7177 std::complex<double> wsum1 = 0.;
7178 std::complex<double> wsum2 = 0.;
7183 for (
unsigned int i = 0; i < m_nWires; ++i) {
7186 m_zmult * std::complex<double>(xpos - m_w[i].x, ypos - m_w[i].y);
7187 if (imag(zeta) > 15.) {
7188 wsum1 -= real(m_sigmat[isw][i]) * icons;
7189 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7190 }
else if (imag(zeta) < -15.) {
7191 wsum1 += real(m_sigmat[isw][i]) * icons;
7192 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7194 const auto zterm = Th1(zeta, m_p1, m_p2);
7195 wsum1 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7196 if (opt) volt -= real(m_sigmat[isw][i]) * log(abs(zterm.first));
7200 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
7202 s += real(m_sigmat[isw][i]) * (m_w[i].x - cx);
7205 std::complex<double>(2. * cx - xpos - m_w[i].x, ypos - m_w[i].y);
7206 if (imag(zeta) > +15.) {
7207 wsum2 -= real(m_sigmat[isw][i]) * icons;
7208 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7209 }
else if (imag(zeta) < -15.) {
7210 wsum2 += real(m_sigmat[isw][i]) * icons;
7211 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7213 const auto zterm = Th1(zeta, m_p1, m_p2);
7214 wsum2 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7215 if (opt) volt += real(m_sigmat[isw][i]) * log(abs(zterm.first));
7218 if (opt && m_mode == 0) {
7219 volt -= TwoPi * real(m_sigmat[isw][i]) * (xpos - cx) * (m_w[i].x - cx) /
7224 ex = real(m_zmult * (wsum1 + wsum2));
7225 ey = -imag(m_zmult * (wsum1 - wsum2));
7227 if (m_mode == 0) ex += s * TwoPi / (m_sx * m_sy);
7230void ComponentAnalyticField::WfieldWireC2Y(
const double xpos,
const double ypos,
7231 double& ex,
double& ey,
double& volt,
7233 const bool opt)
const {
7241 constexpr std::complex<double> icons(0., 1.);
7244 std::complex<double> wsum1 = 0.;
7245 std::complex<double> wsum2 = 0.;
7250 for (
unsigned int i = 0; i < m_nWires; ++i) {
7253 m_zmult * std::complex<double>(xpos - m_w[i].x, ypos - m_w[i].y);
7254 if (imag(zeta) > +15.) {
7255 wsum1 -= real(m_sigmat[isw][i]) * icons;
7256 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7257 }
else if (imag(zeta) < -15.) {
7258 wsum1 += real(m_sigmat[isw][i]) * icons;
7259 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7261 const auto zterm = Th1(zeta, m_p1, m_p2);
7262 wsum1 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7263 if (opt) volt -= real(m_sigmat[isw][i]) * log(abs(zterm.first));
7266 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
7268 s += real(m_sigmat[isw][i]) * (m_w[i].y - cy);
7271 std::complex<double>(xpos - m_w[i].x, 2. * cy - ypos - m_w[i].y);
7272 if (imag(zeta) > +15.) {
7273 wsum2 -= real(m_sigmat[isw][i]) * icons;
7274 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7275 }
else if (imag(zeta) < -15.) {
7276 wsum2 += real(m_sigmat[isw][i]) * icons;
7277 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7279 const auto zterm = Th1(zeta, m_p1, m_p2);
7280 wsum2 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7281 if (opt) volt += real(m_sigmat[isw][i]) * log(abs(zterm.first));
7284 if (opt && m_mode == 1) {
7285 volt -= TwoPi * real(m_sigmat[isw][i]) * (ypos - cy) * (m_w[i].y - cy) /
7290 ex = real(m_zmult * (wsum1 - wsum2));
7291 ey = -imag(m_zmult * (wsum1 + wsum2));
7293 if (m_mode == 1) ey += s * TwoPi / (m_sx * m_sy);
7296void ComponentAnalyticField::WfieldWireC30(
const double xpos,
const double ypos,
7297 double& ex,
double& ey,
double& volt,
7299 const bool opt)
const {
7307 constexpr std::complex<double> icons(0., 1.);
7310 std::complex<double> wsum1 = 0.;
7311 std::complex<double> wsum2 = 0.;
7312 std::complex<double> wsum3 = 0.;
7313 std::complex<double> wsum4 = 0.;
7317 for (
unsigned int i = 0; i < m_nWires; ++i) {
7320 m_zmult * std::complex<double>(xpos - m_w[i].x, ypos - m_w[i].y);
7321 if (imag(zeta) > +15.) {
7322 wsum1 -= real(m_sigmat[isw][i]) * icons;
7323 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7324 }
else if (imag(zeta) < -15.) {
7325 wsum1 += real(m_sigmat[isw][i]) * icons;
7326 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7328 const auto zterm = Th1(zeta, m_p1, m_p2);
7329 wsum1 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7330 if (opt) volt -= real(m_sigmat[isw][i]) * log(abs(zterm.first));
7334 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
7337 std::complex<double>(2. * cx - xpos - m_w[i].x, ypos - m_w[i].y);
7338 if (imag(zeta) > +15.) {
7339 wsum2 -= real(m_sigmat[isw][i]) * icons;
7340 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7341 }
else if (imag(zeta) < -15.) {
7342 wsum2 += real(m_sigmat[isw][i]) * icons;
7343 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7345 const auto zterm = Th1(zeta, m_p1, m_p2);
7346 wsum2 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7347 if (opt) volt += real(m_sigmat[isw][i]) * log(abs(zterm.first));
7350 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
7353 std::complex<double>(xpos - m_w[i].x, 2. * cy - ypos - m_w[i].y);
7354 if (imag(zeta) > +15.) {
7355 wsum3 -= real(m_sigmat[isw][i]) * icons;
7356 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7357 }
else if (imag(zeta) < -15.) {
7358 wsum3 += real(m_sigmat[isw][i]) * icons;
7359 if (opt) volt += real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7361 const auto zterm = Th1(zeta, m_p1, m_p2);
7362 wsum3 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7363 if (opt) volt += real(m_sigmat[isw][i]) * log(abs(zterm.first));
7366 zeta = m_zmult * std::complex<double>(2. * cx - xpos - m_w[i].x,
7367 2. * cy - ypos - m_w[i].y);
7368 if (imag(zeta) > +15.) {
7369 wsum4 -= real(m_sigmat[isw][i]) * icons;
7370 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7371 }
else if (imag(zeta) < -15.) {
7372 wsum4 += real(m_sigmat[isw][i]) * icons;
7373 if (opt) volt -= real(m_sigmat[isw][i]) * (
fabs(imag(zeta)) - CLog2);
7375 const auto zterm = Th1(zeta, m_p1, m_p2);
7376 wsum4 += real(m_sigmat[isw][i]) * (zterm.second / zterm.first);
7377 if (opt) volt -= real(m_sigmat[isw][i]) * log(abs(zterm.first));
7381 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
7382 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
7385void ComponentAnalyticField::WfieldWireD10(
const double xpos,
const double ypos,
7386 double& ex,
double& ey,
double& volt,
7388 const bool opt)
const {
7400 ex = ey = volt = 0.;
7403 std::complex<double> zpos = std::complex<double>(xpos, ypos);
7404 std::complex<double> zi;
7405 std::complex<double> wi;
7407 for (
int i = m_nWires; i--;) {
7409 zi = std::complex<double>(m_w[i].x, m_w[i].y);
7412 volt -= real(m_sigmat[isw][i]) *
7413 log(abs(m_cotube * (zpos - zi) / (m_cotube2 - zpos * conj(zi))));
7416 wi = 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
7417 ex += real(m_sigmat[isw][i]) * real(wi);
7418 ey += real(m_sigmat[isw][i]) * imag(wi);
7422void ComponentAnalyticField::WfieldWireD30(
const double xpos,
const double ypos,
7423 double& ex,
double& ey,
double& volt,
7425 const bool opt)
const {
7436 ex = ey = volt = 0.;
7438 std::complex<double> whelp;
7441 std::complex<double> wpos, wdpos;
7442 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
7444 for (
int i = m_nWires; i--;) {
7447 volt -= real(m_sigmat[isw][i]) *
7448 log(abs((wpos - wmap[i]) / (1. - wpos * conj(wmap[i]))));
7451 whelp = wdpos * (1. -
pow(abs(wmap[i]), 2)) /
7452 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
7453 ex += real(m_sigmat[isw][i]) * real(whelp);
7454 ey -= real(m_sigmat[isw][i]) * imag(whelp);
7460void ComponentAnalyticField::WfieldPlaneA00(
7461 const double xpos,
const double ypos,
double& ex,
double& ey,
double& volt,
7462 const int mx,
const int my,
const int iplane,
const bool opt)
const {
7473 ex = ey = volt = 0.;
7475 double xxmirr = 0., yymirr = 0.;
7477 for (
int i = m_nWires; i--;) {
7479 const double xx = xpos - m_w[i].x - mx * m_sx;
7480 const double yy = ypos - m_w[i].y - my * m_sy;
7482 double r2 = xx * xx + yy * yy;
7483 if (r2 <= 0.)
continue;
7484 double exhelp = xx / r2;
7485 double eyhelp = yy / r2;
7488 xxmirr = xpos + m_w[i].x - 2 * m_coplax;
7489 const double r2plan = xxmirr * xxmirr + yy * yy;
7490 if (r2plan <= 0.)
continue;
7491 exhelp -= xxmirr / r2plan;
7492 eyhelp -= yy / r2plan;
7497 yymirr = ypos + m_w[i].y - 2 * m_coplay;
7498 const double r2plan = xx * xx + yymirr * yymirr;
7499 if (r2plan <= 0.)
continue;
7500 exhelp -= xx / r2plan;
7501 eyhelp -= yymirr / r2plan;
7505 if (m_ynplax && m_ynplay) {
7506 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
7507 if (r2plan <= 0.)
continue;
7508 exhelp += xxmirr / r2plan;
7509 eyhelp += yymirr / r2plan;
7513 if (opt) volt -= 0.5 * m_qplane[iplane][i] * log(r2);
7514 ex += m_qplane[iplane][i] * exhelp;
7515 ey += m_qplane[iplane][i] * eyhelp;
7519void ComponentAnalyticField::WfieldPlaneB2X(
const double xpos,
7520 const double ypos,
double& ex,
7521 double& ey,
double& volt,
7522 const int my,
const int iplane,
7523 const bool opt)
const {
7534 ex = ey = volt = 0.;
7536 const double tx = HalfPi / m_sx;
7538 for (
unsigned int i = 0; i < m_nWires; ++i) {
7539 const double xx = tx * (xpos - m_w[i].x);
7540 const double yy = tx * (ypos - m_w[i].y - my * m_sy);
7541 const double xxneg = tx * (xpos + m_w[i].x - 2 * m_coplan[0]);
7542 const std::complex<double> zz(xx, yy);
7543 const std::complex<double> zzneg(xxneg, yy);
7545 std::complex<double> ecompl(0., 0.);
7547 if (
fabs(yy) <= 20.) {
7548 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
7550 const double sinhy = sinh(yy);
7551 const double sinxx =
sin(xx);
7552 const double sinxxneg =
sin(xxneg);
7553 r2 = (sinhy * sinhy + sinxx * sinxx) /
7554 (sinhy * sinhy + sinxxneg * sinxxneg);
7559 const double yymirr = tx * (ypos + m_w[i].y - 2 * m_coplay);
7560 const std::complex<double> zzmirr(yy, yymirr);
7561 const std::complex<double> zznmirr(xxneg, yymirr);
7562 if (
fabs(yymirr) <= 20.) {
7563 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
7565 const double sinhy = sinh(yymirr);
7566 const double sinxx =
sin(xx);
7567 const double sinxxneg =
sin(xxneg);
7568 const double r2plan = (sinhy * sinhy + sinxx * sinxx) /
7569 (sinhy * sinhy + sinxxneg * sinxxneg);
7575 ex += m_qplane[iplane][i] * real(ecompl);
7576 ey -= m_qplane[iplane][i] * imag(ecompl);
7577 if (opt) volt -= 0.5 * m_qplane[iplane][i] * log(r2);
7583void ComponentAnalyticField::WfieldPlaneB2Y(
const double xpos,
7584 const double ypos,
double& ex,
7585 double& ey,
double& volt,
7586 const int mx,
const int iplane,
7587 const bool opt)
const {
7597 constexpr std::complex<double> icons(0., 1.);
7600 ex = ey = volt = 0.;
7602 const double ty = HalfPi / m_sy;
7604 for (
unsigned int i = 0; i < m_nWires; ++i) {
7605 const double xx = ty * (xpos - m_w[i].x - mx * m_sx);
7606 const double yy = ty * (ypos - m_w[i].y);
7607 const double yyneg = ty * (ypos + m_w[i].y - 2 * m_coplan[2]);
7608 const std::complex<double> zz(xx, yy);
7609 const std::complex<double> zzneg(xx, yyneg);
7611 std::complex<double> ecompl(0., 0.);
7613 if (
fabs(xx) <= 20.) {
7614 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
7616 const double sinhx = sinh(xx);
7617 const double sinyy =
sin(yy);
7618 const double sinyyneg =
sin(yyneg);
7619 r2 = (sinhx * sinhx + sinyy * sinyy) /
7620 (sinhx * sinhx + sinyyneg * sinyyneg);
7625 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
7626 const std::complex<double> zzmirr(xxmirr, yy);
7627 const std::complex<double> zznmirr(xxmirr, yyneg);
7628 if (
fabs(xxmirr) <= 20.) {
7629 ecompl -= m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
7631 const double sinhx = sinh(xxmirr);
7632 const double sinyy =
sin(yy);
7633 const double sinyyneg =
sin(yyneg);
7634 const double r2plan = (sinhx * sinhx + sinyy * sinyy) /
7635 (sinhx * sinhx + sinyyneg * sinyyneg);
7641 ex += m_qplane[iplane][i] * real(ecompl);
7642 ey -= m_qplane[iplane][i] * imag(ecompl);
7643 if (opt) volt -= 0.5 * m_qplane[iplane][i] * log(r2);
7649void ComponentAnalyticField::WfieldPlaneC2X(
const double xpos,
7650 const double ypos,
double& ex,
7651 double& ey,
double& volt,
7653 const bool opt)
const {
7661 constexpr std::complex<double> icons(0., 1.);
7663 std::complex<double> wsum1 = 0.;
7664 std::complex<double> wsum2 = 0.;
7669 for (
unsigned int i = 0; i < m_nWires; ++i) {
7672 m_zmult * std::complex<double>(xpos - m_w[i].x, ypos - m_w[i].y);
7673 if (imag(zeta) > +15.) {
7674 wsum1 -= m_qplane[iplane][i] * icons;
7675 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7676 }
else if (imag(zeta) < -15.) {
7677 wsum1 += m_qplane[iplane][i] * icons;
7678 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7680 const auto zterm = Th1(zeta, m_p1, m_p2);
7681 wsum1 += m_qplane[iplane][i] * (zterm.second / zterm.first);
7682 if (opt) volt -= m_qplane[iplane][i] * log(abs(zterm.first));
7686 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
7688 s += m_qplane[iplane][i] * (m_w[i].x - cx);
7691 std::complex<double>(2. * cx - xpos - m_w[i].x, ypos - m_w[i].y);
7692 if (imag(zeta) > 15.) {
7693 wsum2 -= m_qplane[iplane][i] * icons;
7694 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7695 }
else if (imag(zeta) < -15.) {
7696 wsum2 += m_qplane[iplane][i] * icons;
7697 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7699 const auto zterm = Th1(zeta, m_p1, m_p2);
7700 wsum2 += m_qplane[iplane][i] * (zterm.second / zterm.first);
7701 if (opt) volt += m_qplane[iplane][i] * log(abs(zterm.first));
7703 if (opt && m_mode == 0) {
7704 volt -= TwoPi * m_qplane[iplane][i] * (xpos - cx) * (m_w[i].x - cx) /
7709 ex = real(m_zmult * (wsum1 + wsum2));
7710 ey = -imag(m_zmult * (wsum1 - wsum2));
7712 if (m_mode == 0) ex += s * TwoPi / (m_sx * m_sy);
7715void ComponentAnalyticField::WfieldPlaneC2Y(
const double xpos,
7716 const double ypos,
double& ex,
7717 double& ey,
double& volt,
7719 const bool opt)
const {
7727 constexpr std::complex<double> icons(0., 1.);
7730 std::complex<double> wsum1 = 0.;
7731 std::complex<double> wsum2 = 0.;
7736 for (
unsigned int i = 0; i < m_nWires; ++i) {
7739 m_zmult * std::complex<double>(xpos - m_w[i].x, ypos - m_w[i].y);
7740 if (imag(zeta) > +15.) {
7741 wsum1 -= m_qplane[iplane][i] * icons;
7742 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7743 }
else if (imag(zeta) < -15.) {
7744 wsum1 += m_qplane[iplane][i] * icons;
7745 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7747 const auto zterm = Th1(zeta, m_p1, m_p2);
7748 wsum1 += m_qplane[iplane][i] * (zterm.second / zterm.first);
7749 if (opt) volt -= m_qplane[iplane][i] * log(abs(zterm.first));
7752 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
7754 s += m_qplane[iplane][i] * (m_w[i].y - cy);
7757 std::complex<double>(xpos - m_w[i].x, 2. * cy - ypos - m_w[i].y);
7758 if (imag(zeta) > 15.) {
7759 wsum2 -= m_qplane[iplane][i] * icons;
7760 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7761 }
else if (imag(zeta) < -15.) {
7762 wsum2 += m_qplane[iplane][i] * icons;
7763 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7765 const auto zterm = Th1(zeta, m_p1, m_p2);
7766 wsum2 += m_qplane[iplane][i] * (zterm.second / zterm.first);
7767 if (opt) volt += m_qplane[iplane][i] * log(abs(zterm.first));
7770 if (opt && m_mode == 1) {
7771 volt -= TwoPi * m_qplane[iplane][i] * (ypos - cy) * (m_w[i].y - cy) /
7776 ex = real(m_zmult * (wsum1 - wsum2));
7777 ey = -imag(m_zmult * (wsum1 + wsum2));
7779 if (m_mode == 1) ey += s * TwoPi / (m_sx * m_sy);
7782void ComponentAnalyticField::WfieldPlaneC30(
const double xpos,
7783 const double ypos,
double& ex,
7784 double& ey,
double& volt,
7786 const bool opt)
const {
7794 constexpr std::complex<double> icons(0., 1.);
7797 std::complex<double> wsum1 = 0.;
7798 std::complex<double> wsum2 = 0.;
7799 std::complex<double> wsum3 = 0.;
7800 std::complex<double> wsum4 = 0.;
7804 for (
unsigned int i = 0; i < m_nWires; ++i) {
7807 m_zmult * std::complex<double>(xpos - m_w[i].x, ypos - m_w[i].y);
7808 if (imag(zeta) > +15.) {
7809 wsum1 -= m_qplane[iplane][i] * icons;
7810 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7811 }
else if (imag(zeta) < -15.) {
7812 wsum1 += m_qplane[iplane][i] * icons;
7813 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7815 const auto zterm = Th1(zeta, m_p1, m_p2);
7816 wsum1 += m_qplane[iplane][i] * zterm.second / zterm.first;
7817 if (opt) volt -= m_qplane[iplane][i] * log(abs(zterm.first));
7821 m_coplax - m_sx * int(round((m_coplax - m_w[i].x) / m_sx));
7824 std::complex<double>(2. * cx - xpos - m_w[i].x, ypos - m_w[i].y);
7825 if (imag(zeta) > 15.) {
7826 wsum2 -= m_qplane[iplane][i] * icons;
7827 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7828 }
else if (imag(zeta) < -15.) {
7829 wsum2 += m_qplane[iplane][i] * icons;
7830 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7832 const auto zterm = Th1(zeta, m_p1, m_p2);
7833 wsum2 += m_qplane[iplane][i] * zterm.second / zterm.first;
7834 if (opt) volt += m_qplane[iplane][i] * log(abs(zterm.first));
7837 double cy = m_coplay - m_sy * int(round((m_coplay - m_w[i].y) / m_sy));
7840 std::complex<double>(xpos - m_w[i].x, 2. * cy - ypos - m_w[i].y);
7841 if (imag(zeta) > 15.) {
7842 wsum3 -= m_qplane[iplane][i] * icons;
7843 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7844 }
else if (imag(zeta) < -15.) {
7845 wsum3 += m_qplane[iplane][i] * icons;
7846 if (opt) volt += m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7848 const auto zterm = Th1(zeta, m_p1, m_p2);
7849 wsum3 += m_qplane[iplane][i] * zterm.second / zterm.first;
7850 if (opt) volt += m_qplane[iplane][i] * log(abs(zterm.first));
7853 zeta = m_zmult * std::complex<double>(2. * cx - xpos - m_w[i].x,
7854 2. * cy - ypos - m_w[i].y);
7855 if (imag(zeta) > 15.) {
7856 wsum4 -= m_qplane[iplane][i] * icons;
7857 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7858 }
else if (imag(zeta) < -15.) {
7859 wsum4 += m_qplane[iplane][i] * icons;
7860 if (opt) volt -= m_qplane[iplane][i] * (
fabs(imag(zeta)) - CLog2);
7862 const auto zterm = Th1(zeta, m_p1, m_p2);
7863 wsum4 += m_qplane[iplane][i] * zterm.second / zterm.first;
7864 if (opt) volt -= m_qplane[iplane][i] * log(abs(zterm.first));
7867 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
7868 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
7871void ComponentAnalyticField::WfieldPlaneD10(
const double xpos,
7872 const double ypos,
double& ex,
7873 double& ey,
double& volt,
7875 const bool opt)
const {
7886 ex = ey = volt = 0.;
7889 std::complex<double> zpos = std::complex<double>(xpos, ypos);
7890 std::complex<double> zi;
7891 std::complex<double> wi;
7893 for (
int i = m_nWires; i--;) {
7895 zi = std::complex<double>(m_w[i].x, m_w[i].y);
7898 volt -= m_qplane[iplane][i] *
7899 log(abs(m_cotube * (zpos - zi) / (m_cotube2 - zpos * conj(zi))));
7902 wi = 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
7903 ex += m_qplane[iplane][i] * real(wi);
7904 ey += m_qplane[iplane][i] * imag(wi);
7908void ComponentAnalyticField::WfieldPlaneD30(
const double xpos,
7909 const double ypos,
double& ex,
7910 double& ey,
double& volt,
7912 const bool opt)
const {
7923 ex = ey = volt = 0.;
7925 std::complex<double> whelp;
7928 std::complex<double> wpos, wdpos;
7929 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
7931 for (
unsigned int i = 0; i < m_nWires; ++i) {
7934 volt -= m_qplane[iplane][i] *
7935 log(abs((wpos - wmap[i]) / (1. - wpos * conj(wmap[i]))));
7938 whelp = wdpos * (1. -
pow(abs(wmap[i]), 2)) /
7939 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
7940 ex += m_qplane[iplane][i] * real(whelp);
7941 ey -= m_qplane[iplane][i] * imag(whelp);
7947void ComponentAnalyticField::WfieldStripZ(
7948 const double xpos,
const double ypos,
double& ex,
double& ey,
double& volt,
7949 const int ip,
const Strip& strip,
7951 const bool opt)
const {
7958 ex = ey = volt = 0.;
7961 double xw = 0., yw = 0.;
7964 xw = -ypos + 0.5 * (strip.smin + strip.smax);
7965 yw = xpos - m_coplan[ip];
7968 xw = ypos - 0.5 * (strip.smin + strip.smax);
7969 yw = m_coplan[ip] - xpos;
7972 xw = xpos - 0.5 * (strip.smin + strip.smax);
7973 yw = ypos - m_coplan[ip];
7976 xw = -xpos + 0.5 * (strip.smin + strip.smax);
7977 yw = m_coplan[ip] - ypos;
7983 const double w = 0.5 *
fabs(strip.smax - strip.smin);
7984 const double g = strip.gap;
7987 if (yw <= 0. || yw > g)
return;
7990 const double s =
sin(Pi * yw / g);
7991 const double c =
cos(Pi * yw / g);
7992 const double e1 =
exp(Pi * (w - xw) / g);
7993 const double e2 =
exp(-Pi * (w + xw) / g);
7994 const double ce12 =
pow(c - e1, 2);
7995 const double ce22 =
pow(c - e2, 2);
7997 if (c == e1 || c == e2)
return;
8000 volt = atan((c - e2) / s) - atan((c - e1) / s);
8004 const double s2 = s * s;
8005 const double ewx = (s / g) * (e1 / (ce12 + s2) - e2 / (ce22 + s2));
8006 const double ewy = ((c / (c - e2) + s2 / ce22) / (1. + s2 / ce22) -
8007 (c / (c - e1) + s2 / ce12) / (1. + s2 / ce12)) / g;
8030void ComponentAnalyticField::WfieldStripXy(
const double xpos,
const double ypos,
8031 const double zpos,
double& ex,
8032 double& ey,
double& ez,
double& volt,
8033 const int ip,
const Strip& strip,
8034 const bool opt)
const {
8041 ex = ey = ez = volt = 0.;
8044 double xw = 0., yw = 0.;
8047 xw = -zpos + 0.5 * (strip.smin + strip.smax);
8048 yw = xpos - m_coplan[ip];
8051 xw = zpos - 0.5 * (strip.smin + strip.smax);
8052 yw = m_coplan[ip] - xpos;
8055 xw = zpos - 0.5 * (strip.smin + strip.smax);
8056 yw = ypos - m_coplan[ip];
8059 xw = -zpos + 0.5 * (strip.smin + strip.smax);
8060 yw = m_coplan[ip] - ypos;
8067 const double w = 0.5 *
fabs(strip.smax - strip.smin);
8068 const double g = strip.gap;
8071 if (yw <= 0. || yw > g)
return;
8074 const double s =
sin(Pi * yw / g);
8075 const double c =
cos(Pi * yw / g);
8076 const double e1 =
exp(Pi * (w - xw) / g);
8077 const double e2 =
exp(-Pi * (w + xw) / g);
8078 const double ce12 =
pow(c - e1, 2);
8079 const double ce22 =
pow(c - e2, 2);
8081 if (c == e1 || c == e2)
return;
8084 volt = atan((c - e2) / s) - atan((c - e1) / s);
8088 const double s2 = s * s;
8089 const double ewx = (s / g) * (e1 / (ce12 + s2) - e2 / (ce22 + s2));
8090 const double ewy = ((c / (c - e2) + s2 / ce22) / (1. + s2 / ce22) -
8091 (c / (c - e1) + s2 / ce12) / (1. + s2 / ce12)) / g;
8118void ComponentAnalyticField::WfieldPixel(
const double xpos,
const double ypos,
8119 const double zpos,
double& ex,
8120 double& ey,
double& ez,
double& volt,
8121 const int ip,
const Pixel& pixel,
8122 const bool opt)
const {
8133 ex = ey = ez = volt = 0.;
8135 const double d = pixel.gap;
8137 double x = 0.,
y = 0.,
z = 0.;
8140 const double ps = 0.5 * (pixel.smin + pixel.smax);
8141 const double pz = 0.5 * (pixel.zmin + pixel.zmax);
8142 const double wx = pixel.smax - pixel.smin;
8143 const double wy = pixel.zmax - pixel.zmin;
8148 z = xpos - m_coplan[ip];
8153 z = -xpos + m_coplan[ip];
8158 z = ypos - m_coplan[ip];
8163 z = -ypos + m_coplan[ip];
8175 const double x1 =
x - 0.5 *
wx;
8176 const double x2 =
x + 0.5 *
wx;
8177 const double y1 =
y - 0.5 *
wy;
8178 const double y2 =
y + 0.5 *
wy;
8179 const double x1s = x1 * x1;
8180 const double x2s = x2 * x2;
8181 const double y1s = y1 * y1;
8182 const double y2s = y2 * y2;
8185 const double maxError = 1.e-5;
8186 const double d3 = d * d * d;
8187 const unsigned int nz = std::ceil(
sqrt(wx * wy / (8 * Pi * d3 * maxError)));
8188 const unsigned int nx = std::ceil(
sqrt(wy * z / (4 * Pi * d3 * maxError)));
8189 const unsigned int ny = std::ceil(
sqrt(wx * z / (4 * Pi * d3 * maxError)));
8190 const unsigned int nn = std::max(ny, std::max(nx, nz));
8191 for (
unsigned int i = 1; i <= nn; ++i) {
8192 const double u1 = 2 * i * d -
z;
8193 const double u2 = 2 * i * d +
z;
8194 const double u1s = u1 * u1;
8195 const double u2s = u2 * u2;
8196 const double u1x1y1 =
sqrt(x1s + y1s + u1s);
8197 const double u1x1y2 =
sqrt(x1s + y2s + u1s);
8198 const double u1x2y1 =
sqrt(x2s + y1s + u1s);
8199 const double u1x2y2 =
sqrt(x2s + y2s + u1s);
8200 const double u2x1y1 =
sqrt(x1s + y1s + u2s);
8201 const double u2x1y2 =
sqrt(x1s + y2s + u2s);
8202 const double u2x2y1 =
sqrt(x2s + y1s + u2s);
8203 const double u2x2y2 =
sqrt(x2s + y2s + u2s);
8207 ex -= u1 * y1 / ((u1s + x2s) * u1x2y1) -
8208 u1 * y1 / ((u1s + x1s) * u1x1y1) +
8209 u1 * y2 / ((u1s + x1s) * u1x1y2) - u1 * y2 / ((u1s + x2s) * u1x2y2);
8212 ex += u2 * y1 / ((u2s + x2s) * u2x2y1) -
8213 u2 * y1 / ((u2s + x1s) * u2x1y1) +
8214 u2 * y2 / ((u2s + x1s) * u2x1y2) - u2 * y2 / ((u2s + x2s) * u2x2y2);
8218 ey -= u1 * x1 / ((u1s + y2s) * u1x1y2) -
8219 u1 * x1 / ((u1s + y1s) * u1x1y1) +
8220 u1 * x2 / ((u1s + y1s) * u1x2y1) - u1 * x2 / ((u1s + y2s) * u1x2y2);
8223 ey += u2 * x1 / ((u2s + y2s) * u2x1y2) -
8224 u2 * x1 / ((u2s + y1s) * u2x1y1) +
8225 u2 * x2 / ((u2s + y1s) * u2x2y1) - u2 * x2 / ((u2s + y2s) * u2x2y2);
8229 ez += x1 * y1 * (x1s + y1s + 2 * u1s) /
8230 ((x1s + u1s) * (y1s + u1s) * u1x1y1) +
8231 x2 * y2 * (x2s + y2s + 2 * u1s) /
8232 ((x2s + u1s) * (y2s + u1s) * u1x2y2) -
8233 x1 * y2 * (x1s + y2s + 2 * u1s) /
8234 ((x1s + u1s) * (y2s + u1s) * u1x1y2) -
8235 x2 * y1 * (x2s + y1s + 2 * u1s) /
8236 ((x2s + u1s) * (y1s + u1s) * u1x2y1);
8239 ez += x1 * y1 * (x1s + y1s + 2 * u2s) /
8240 ((x1s + u2s) * (y1s + u2s) * u2x1y1) +
8241 x2 * y2 * (x2s + y2s + 2 * u2s) /
8242 ((x2s + u2s) * (y2s + u2s) * u2x2y2) -
8243 x1 * y2 * (x1s + y2s + 2 * u2s) /
8244 ((x1s + u2s) * (y2s + u2s) * u2x1y2) -
8245 x2 * y1 * (x2s + y1s + 2 * u2s) /
8246 ((x2s + u2s) * (y1s + u2s) * u2x2y1);
8249 volt -= atan(x1 * y1 / (u1 * u1x1y1)) + atan(x2 * y2 / (u1 * u1x2y2)) -
8250 atan(x1 * y2 / (u1 * u1x1y2)) - atan(x2 * y1 / (u1 * u1x2y1));
8251 volt += atan(x1 * y1 / (u2 * u2x1y1)) + atan(x2 * y2 / (u2 * u2x2y2)) -
8252 atan(x1 * y2 / (u2 * u2x1y2)) - atan(x2 * y1 / (u2 * u2x2y1));
8255 const double zs =
z *
z;
8256 const double x1y1 =
sqrt(x1s + y1s + zs);
8257 const double x1y2 =
sqrt(x1s + y2s + zs);
8258 const double x2y1 =
sqrt(x2s + y1s + zs);
8259 const double x2y2 =
sqrt(x2s + y2s + zs);
8261 ex +=
z * y1 / ((zs + x2s) * x2y1) -
z * y1 / ((zs + x1s) * x1y1) +
8262 z * y2 / ((zs + x1s) * x1y2) -
z * y2 / ((zs + x2s) * x2y2);
8265 ey +=
z * x1 / ((zs + y2s) * x1y2) -
z * x1 / ((zs + y1s) * x1y1) +
8266 z * x2 / ((zs + y1s) * x2y1) -
z * x2 / ((zs + y2s) * x2y2);
8269 ez += x1 * y1 * (x1s + y1s + 2 * zs) / ((x1s + zs) * (y1s + zs) * x1y1) +
8270 x2 * y2 * (x2s + y2s + 2 * zs) / ((x2s + zs) * (y2s + zs) * x2y2) -
8271 x1 * y2 * (x1s + y2s + 2 * zs) / ((x1s + zs) * (y2s + zs) * x1y2) -
8272 x2 * y1 * (x2s + y1s + 2 * zs) / ((x2s + zs) * (y1s + zs) * x2y1);
8274 constexpr double invTwoPi = 1. / TwoPi;
8280 volt += atan(x1 * y1 / (z * x1y1)) + atan(x2 * y2 / (z * x2y2)) -
8281 atan(x1 * y2 / (z * x1y2)) - atan(x2 * y1 / (z * x2y1));
8286 const double fx = ex;
8287 const double fy = ey;
8288 const double fz = ez;
8313void ComponentAnalyticField::FieldAtWireA00(
8314 const double xpos,
const double ypos,
double& ex,
double& ey,
8315 const std::vector<bool>& cnalso)
const {
8326 for (
unsigned int i = 0; i < m_nWires; ++i) {
8327 const auto& wire = m_w[i];
8331 const double xx = xpos - wire.x;
8332 const double yy = ypos - wire.y;
8334 const double r2 = xx * xx + yy * yy;
8341 xxmirr = wire.x + xpos - 2 * m_coplax;
8342 const double r2plan = xxmirr * xxmirr + yy * yy;
8343 exhelp -= xxmirr / r2plan;
8344 eyhelp -= yy / r2plan;
8349 yymirr = wire.y + ypos - 2 * m_coplay;
8350 const double r2plan = xx * xx + yymirr * yymirr;
8351 exhelp -= xx / r2plan;
8352 eyhelp -= yymirr / r2plan;
8355 if (m_ynplax && m_ynplay) {
8356 const double r2plan = xxmirr * xxmirr + yymirr * yymirr;
8357 exhelp += xxmirr / r2plan;
8358 eyhelp += yymirr / r2plan;
8360 ex += wire.e * exhelp;
8361 ey += wire.e * eyhelp;
8365void ComponentAnalyticField::FieldAtWireB1X(
8366 const double xpos,
const double ypos,
double& ex,
double& ey,
8367 const std::vector<bool>& cnalso)
const {
8373 constexpr std::complex<double> icons(0., 1.);
8374 std::complex<double> ecompl;
8376 const double tx = Pi / m_sx;
8379 for (
unsigned int i = 0; i < m_nWires; ++i) {
8380 const auto& wire = m_w[i];
8381 const double xx = tx * (xpos - wire.x);
8382 const double yy = tx * (ypos - wire.y);
8385 }
else if (yy > 20.) {
8387 }
else if (yy < -20.) {
8390 const std::complex<double> zz(xx, yy);
8391 const auto expzz =
exp(2. * icons * zz);
8392 ecompl = icons * (expzz + 1.) / (expzz - 1.);
8394 const double yymirr = tx * (ypos + wire.y - 2. * m_coplay);
8397 }
else if (yymirr < -20.) {
8400 const std::complex<double> zzmirr(xx, yymirr);
8401 const auto expzzmirr =
exp(2. * icons * zzmirr);
8402 ecompl += -icons * (expzzmirr + 1.) / (expzzmirr - 1.);
8405 ex += wire.e * real(ecompl);
8406 ey -= wire.e * imag(ecompl);
8410 for (
unsigned int i = 0; i < m_nWires; ++i) {
8411 if (!cnalso[i])
continue;
8412 const auto& wire = m_w[i];
8413 const double xx = tx * (xpos - wire.x);
8414 const double yy = tx * (ypos - wire.y);
8417 }
else if (yy < -20.) {
8420 const std::complex<double> zz(xx, yy);
8421 const auto expzz =
exp(2. * icons * zz);
8422 ecompl = icons * (expzz + 1.) / (expzz - 1.);
8424 ex += wire.e * real(ecompl);
8425 ey -= wire.e * imag(ecompl);
8432void ComponentAnalyticField::FieldAtWireB1Y(
8433 const double xpos,
const double ypos,
double& ex,
double& ey,
8434 const std::vector<bool>& cnalso)
const {
8440 std::complex<double> ecompl;
8442 const double ty = Pi / m_sy;
8445 for (
unsigned int i = 0; i < m_nWires; ++i) {
8446 const auto& wire = m_w[i];
8447 const double xx = ty * (xpos - wire.x);
8448 const double yy = ty * (ypos - wire.y);
8451 }
else if (xx > 20.) {
8453 }
else if (xx < -20.) {
8456 const std::complex<double> zz(xx, yy);
8457 const auto expzz =
exp(2. * zz);
8458 ecompl = (expzz + 1.) / (expzz - 1.);
8460 const double xxmirr = ty * (xpos + wire.x - 2. * m_coplax);
8463 }
else if (xxmirr < -20.) {
8466 const std::complex<double> zzmirr(xxmirr, yy);
8467 const auto expzzmirr =
exp(2. * zzmirr);
8468 ecompl -= (expzzmirr + 1.) / (expzzmirr - 1.);
8470 ex += wire.e * real(ecompl);
8471 ey -= wire.e * imag(ecompl);
8475 for (
unsigned int i = 0; i < m_nWires; ++i) {
8476 if (!cnalso[i])
continue;
8477 const auto& wire = m_w[i];
8478 const double xx = ty * (xpos - wire.x);
8479 const double yy = ty * (ypos - wire.y);
8482 }
else if (xx < -20.) {
8485 const std::complex<double> zz(xx, yy);
8486 const auto expzz =
exp(2. * zz);
8487 ecompl = (expzz + 1.) / (expzz - 1.);
8489 ex += wire.e * real(ecompl);
8490 ey -= wire.e * imag(ecompl);
8497void ComponentAnalyticField::FieldAtWireB2X(
8498 const double xpos,
const double ypos,
double& ex,
double& ey,
8499 const std::vector<bool>& cnalso)
const {
8504 constexpr std::complex<double> icons(0., 1.);
8506 const double tx = HalfPi / m_sx;
8508 for (
unsigned int i = 0; i < m_nWires; ++i) {
8509 const double xx = tx * (xpos - m_w[i].x);
8510 const double yy = tx * (ypos - m_w[i].y);
8511 const double xxneg = tx * (xpos - m_w[i].x - 2 * m_coplax);
8513 std::complex<double> ecompl(0., 0.);
8514 if (cnalso[i] &&
fabs(yy) <= 20.) {
8515 const std::complex<double> zz(xx, yy);
8516 const std::complex<double> zzneg(xxneg, yy);
8517 ecompl = -m_b2sin[i] / (
sin(zz) *
sin(zzneg));
8518 }
else if (
fabs(yy) <= 20.) {
8519 const std::complex<double> zzneg(xxneg, yy);
8520 const auto expzzneg =
exp(2. * icons * zzneg);
8521 ecompl = -icons * (expzzneg + 1.) / (expzzneg - 1.);
8525 const double yymirr = tx * (ypos + m_w[i].y - 2 * m_coplay);
8526 if (
fabs(yymirr) <= 20.) {
8527 const std::complex<double> zzmirr(xx, yymirr);
8528 const std::complex<double> zznmirr(xxneg, yymirr);
8529 ecompl += m_b2sin[i] / (
sin(zzmirr) *
sin(zznmirr));
8532 ex += m_w[i].e * real(ecompl);
8533 ey -= m_w[i].e * imag(ecompl);
8539void ComponentAnalyticField::FieldAtWireB2Y(
8540 const double xpos,
const double ypos,
double& ex,
double& ey,
8541 const std::vector<bool>& cnalso)
const {
8546 constexpr std::complex<double> icons(0., 1.);
8548 const double ty = HalfPi / m_sy;
8550 for (
unsigned int i = 0; i < m_nWires; ++i) {
8551 const double xx = ty * (xpos - m_w[i].x);
8552 const double yy = ty * (ypos - m_w[i].y);
8553 const double yyneg = ty * (ypos + m_w[i].y - 2 * m_coplay);
8555 std::complex<double> ecompl(0., 0.);
8556 if (cnalso[i] &&
fabs(xx) <= 20.) {
8557 const std::complex<double> zz(xx, yy);
8558 const std::complex<double> zzneg(xx, yyneg);
8559 ecompl = icons * m_b2sin[i] / (
sin(icons * zz) *
sin(icons * zzneg));
8560 }
else if (
fabs(xx) <= 20.) {
8561 const std::complex<double> zzneg(xx, yyneg);
8562 const auto expzzneg =
exp(2. * zzneg);
8563 ecompl = -(expzzneg + 1.) / (expzzneg - 1.);
8567 const double xxmirr = ty * (xpos + m_w[i].x - 2 * m_coplax);
8568 if (
fabs(xxmirr) <= 20.) {
8569 const std::complex<double> zzmirr(xxmirr, yy);
8570 const std::complex<double> zznmirr(xxmirr, yyneg);
8572 icons * m_b2sin[i] / (
sin(icons * zzmirr) *
sin(icons * zznmirr));
8575 ex += m_w[i].e * real(ecompl);
8576 ey -= m_w[i].e * imag(ecompl);
8582void ComponentAnalyticField::FieldAtWireC10(
8583 const double xpos,
const double ypos,
double& ex,
double& ey,
8584 const std::vector<bool>& cnalso)
const {
8589 constexpr std::complex<double> icons(0., 1.);
8590 std::complex<double> wsum(0., 0.);
8592 for (
unsigned int j = 0; j < m_nWires; ++j) {
8593 if (!cnalso[j])
continue;
8594 const auto& wire = m_w[j];
8595 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
8596 if (imag(zeta) > 15.) {
8597 wsum -= wire.e * icons;
8598 }
else if (imag(zeta) < -15.) {
8599 wsum += wire.e * icons;
8601 const auto zterm = Th1(zeta, m_p1, m_p2);
8602 wsum += wire.e * (zterm.second / zterm.first);
8605 ex = -real(-m_zmult * wsum);
8606 ey = imag(-m_zmult * wsum);
8607 if (m_mode == 0) ex -= m_c1;
8608 if (m_mode == 1) ey -= m_c1;
8611void ComponentAnalyticField::FieldAtWireC2X(
8612 const double xpos,
const double ypos,
double& ex,
double& ey,
8613 const std::vector<bool>& cnalso)
const {
8618 constexpr std::complex<double> icons(0., 1.);
8620 std::complex<double> wsum1 = 0.;
8621 std::complex<double> wsum2 = 0.;
8622 for (
unsigned int i = 0; i < m_nWires; ++i) {
8623 const auto& wire = m_w[i];
8625 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
8626 if (imag(zeta) > 15.) {
8627 wsum1 -= wire.e * icons;
8628 }
else if (imag(zeta) < -15.) {
8629 wsum1 += wire.e * icons;
8631 const auto zterm = Th1(zeta, m_p1, m_p2);
8632 wsum1 += wire.e * (zterm.second / zterm.first);
8636 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
8639 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
8640 if (imag(zeta) > 15.) {
8641 wsum2 -= wire.e * icons;
8642 }
else if (imag(zeta) < -15.) {
8643 wsum2 += wire.e * icons;
8645 const auto zterm = Th1(zeta, m_p1, m_p2);
8646 wsum2 += wire.e * (zterm.second / zterm.first);
8650 ex = real(m_zmult * (wsum1 + wsum2));
8651 ey = -imag(m_zmult * (wsum1 - wsum2));
8653 if (m_mode == 0) ex -= m_c1;
8656void ComponentAnalyticField::FieldAtWireC2Y(
8657 const double xpos,
const double ypos,
double& ex,
double& ey,
8658 const std::vector<bool>& cnalso)
const {
8663 const std::complex<double> icons(0., 1.);
8665 std::complex<double> wsum1 = 0.;
8666 std::complex<double> wsum2 = 0.;
8667 for (
unsigned int i = 0; i < m_nWires; ++i) {
8668 const auto& wire = m_w[i];
8671 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
8672 if (imag(zeta) > 15.) {
8673 wsum1 -= wire.e * icons;
8674 }
else if (imag(zeta) < -15.) {
8675 wsum1 += wire.e * icons;
8677 const auto zterm = Th1(zeta, m_p1, m_p2);
8678 wsum1 += wire.e * (zterm.second / zterm.first);
8682 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
8685 m_zmult * std::complex<double>(xpos - wire.x, 2 * cy - ypos - wire.y);
8686 if (imag(zeta) > 15.) {
8687 wsum2 -= wire.e * icons;
8688 }
else if (imag(zeta) < -15.) {
8689 wsum2 += wire.e * icons;
8691 const auto zterm = Th1(zeta, m_p1, m_p2);
8692 wsum2 += wire.e * (zterm.second / zterm.first);
8696 ex = real(m_zmult * (wsum1 - wsum2));
8697 ey = -imag(m_zmult * (wsum1 + wsum2));
8699 if (m_mode == 1) ey -= m_c1;
8702void ComponentAnalyticField::FieldAtWireC30(
8703 const double xpos,
const double ypos,
double& ex,
double& ey,
8704 const std::vector<bool>& cnalso)
const {
8709 constexpr std::complex<double> icons(0., 1.);
8711 std::complex<double> wsum1 = 0.;
8712 std::complex<double> wsum2 = 0.;
8713 std::complex<double> wsum3 = 0.;
8714 std::complex<double> wsum4 = 0.;
8715 for (
unsigned int i = 0; i < m_nWires; ++i) {
8716 const auto& wire = m_w[i];
8718 auto zeta = m_zmult * std::complex<double>(xpos - wire.x, ypos - wire.y);
8719 if (imag(zeta) > 15.) {
8720 wsum1 -= wire.e * icons;
8721 }
else if (imag(zeta) < -15.) {
8722 wsum1 += wire.e * icons;
8724 const auto zterm = Th1(zeta, m_p1, m_p2);
8725 wsum1 += wire.e * (zterm.second / zterm.first);
8729 const double cx = m_coplax - m_sx * int(round((m_coplax - wire.x) / m_sx));
8732 m_zmult * std::complex<double>(2. * cx - xpos - wire.x, ypos - wire.y);
8733 if (imag(zeta) > 15.) {
8734 wsum2 -= wire.e * icons;
8735 }
else if (imag(zeta) < -15.) {
8736 wsum2 += wire.e * icons;
8738 const auto zterm = Th1(zeta, m_p1, m_p2);
8739 wsum2 += wire.e * (zterm.second / zterm.first);
8742 const double cy = m_coplay - m_sy * int(round((m_coplay - wire.y) / m_sy));
8745 m_zmult * std::complex<double>(xpos - wire.x, 2. * cy - ypos - wire.y);
8746 if (imag(zeta) > 15.) {
8747 wsum3 -= wire.e * icons;
8748 }
else if (imag(zeta) < -15.) {
8749 wsum3 += wire.e * icons;
8751 const auto zterm = Th1(zeta, m_p1, m_p2);
8752 wsum3 += wire.e * (zterm.second / zterm.first);
8755 zeta = m_zmult * std::complex<double>(2. * cx - xpos - wire.x,
8756 2. * cy - ypos - wire.y);
8757 if (imag(zeta) > 15.) {
8758 wsum4 -= wire.e * icons;
8759 }
else if (imag(zeta) < -15.) {
8760 wsum4 += wire.e * icons;
8762 const auto zterm = Th1(zeta, m_p1, m_p2);
8763 wsum4 += wire.e * (zterm.second / zterm.first);
8767 ex = real(m_zmult * (wsum1 + wsum2 - wsum3 - wsum4));
8768 ey = -imag(m_zmult * (wsum1 - wsum2 + wsum3 - wsum4));
8771void ComponentAnalyticField::FieldAtWireD10(
8772 const double xpos,
const double ypos,
double& ex,
double& ey,
8773 const std::vector<bool>& cnalso)
const {
8780 const std::complex<double> zpos(xpos, ypos);
8782 for (
unsigned int i = 0; i < m_nWires; ++i) {
8783 const auto& wire = m_w[i];
8785 const std::complex<double> zi(wire.x, wire.y);
8788 const std::complex<double> wi =
8789 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
8790 ex += wire.e * real(wi);
8791 ey += wire.e * imag(wi);
8793 const std::complex<double> wi = zi / (m_cotube2 - conj(zpos) * zi);
8794 ex += wire.e * real(wi);
8795 ey += wire.e * imag(wi);
8800void ComponentAnalyticField::FieldAtWireD20(
8801 const double xpos,
const double ypos,
double& ex,
double& ey,
8802 const std::vector<bool>& cnalso)
const {
8809 const std::complex<double> zpos(xpos, ypos);
8810 for (
unsigned int i = 0; i < m_nWires; ++i) {
8811 const auto& wire = m_w[i];
8813 const std::complex<double> zi(wire.x, wire.y);
8816 if (std::abs(zi) > wire.r) {
8817 const std::complex<double> wi =
8818 double(m_mtube) *
pow(conj(zpos), m_mtube - 1) *
8819 (1. / conj(
pow(zpos, m_mtube) -
pow(zi, m_mtube)) +
8821 (
pow(m_cotube, 2 * m_mtube) -
pow(conj(zpos) * zi, m_mtube)));
8822 ex += wire.e * real(wi);
8823 ey += wire.e * imag(wi);
8825 const std::complex<double> wi =
8826 1. / conj(zpos - zi) + zi / (m_cotube2 - conj(zpos) * zi);
8827 ex += wire.e * real(wi);
8828 ey += wire.e * imag(wi);
8831 if (abs(zi) > wire.r) {
8832 const std::complex<double> wi =
8833 double(m_mtube) *
pow(conj(zpos), m_mtube - 1) *
8835 (
pow(m_cotube, 2 * m_mtube) -
pow(conj(zpos) * zi, m_mtube)));
8836 ex += wire.e * real(wi);
8837 ey += wire.e * imag(wi);
8839 const std::complex<double> wi = zi / (m_cotube2 - conj(zpos) * zi);
8840 ex += wire.e * real(wi);
8841 ey += wire.e * imag(wi);
8847void ComponentAnalyticField::FieldAtWireD30(
8848 const double xpos,
const double ypos,
double& ex,
double& ey,
8849 const std::vector<bool>& cnalso)
const {
8856 std::complex<double> wpos, wdpos;
8857 ConformalMap(std::complex<double>(xpos, ypos) / m_cotube, wpos, wdpos);
8859 for (
unsigned int i = 0; i < m_nWires; ++i) {
8862 const std::complex<double> whelp =
8863 wdpos * (1. -
pow(abs(wmap[i]), 2)) /
8864 ((wpos - wmap[i]) * (1. - conj(wmap[i]) * wpos));
8865 ex += m_w[i].e * real(whelp);
8866 ey -= m_w[i].e * imag(whelp);
8869 const std::complex<double> whelp =
8870 wdpos * conj(wmap[i]) / (1. - conj(wmap[i]) * wpos);
8871 ex += m_w[i].e * real(whelp);
8872 ey -= m_w[i].e * imag(whelp);
8879bool ComponentAnalyticField::SagDetailed(
8880 const Wire& wire,
const std::vector<double>& xMap,
8881 const std::vector<double>& yMap,
8882 const std::vector<std::vector<double> >& fxMap,
8883 const std::vector<std::vector<double> >& fyMap, std::vector<double>& csag,
8884 std::vector<double>& xsag, std::vector<double>& ysag)
const {
8895 const unsigned int np = m_nSteps * (m_nShots + 1);
8897 const double h = wire.u / np;
8899 std::array<double, 2> xst = {0., 0.};
8900 std::array<double, 2> dxst = {0., 0.};
8904 for (
unsigned int i = 0; i <= np; ++i) {
8905 const double z = i * h;
8906 std::array<double, 2> force = {0., 0.};
8907 if (!GetForceRatio(wire, z, xst, dxst, force, xMap, yMap, fxMap, fyMap)) {
8909 <<
" Wire at nominal position outside scanning area.\n";
8915 const double u2 = wire.u * wire.u;
8917 const double s = u2 / (8. * (1. + np));
8918 double sagx0 = -fxmean * s;
8919 double sagy0 = -fymean * s;
8921 std::cout <<
m_className <<
"::SagDetailed: Parabolic sag.\n";
8922 std::printf(
" dx = %12.5e, dy = %12.5e [cm]\n", sagx0, sagy0);
8925 std::vector<double> xx(4 * m_nShots + 2);
8927 xx[0] = 4 * sagx0 / wire.u;
8928 xx[1] = 4 * sagy0 / wire.u;
8930 for (
unsigned int i = 1; i <= m_nShots; ++i) {
8932 const double z = -0.5 * wire.u + i * m_nSteps * h;
8933 const unsigned int k = 4 * i - 2;
8935 const double f = 1. - 4 *
z *
z / u2;
8937 xx[k + 1] = sagy0 * f;
8939 const double fp = -8 *
z / u2;
8940 xx[k + 2] = sagx0 * fp;
8941 xx[k + 3] = sagy0 * fp;
8944 if (!FindZeroes(wire, h, xx, xMap, yMap, fxMap, fyMap)) {
8946 <<
" Failed to solve the differential equation for the sag.\n";
8950 csag.assign(np + 1, 0.);
8951 xsag.assign(np + 1, 0.);
8952 ysag.assign(np + 1, 0.);
8953 csag[0] = -0.5 * wire.u;
8954 double coor = -0.5 * wire.u;
8955 for (
unsigned int i = 0; i <= m_nShots; ++i) {
8963 xst[0] = xx[4 * i - 2];
8964 xst[1] = xx[4 * i - 1];
8965 dxst[0] = xx[4 * i];
8966 dxst[1] = xx[4 * i + 1];
8969 for (
unsigned int j = 1; j <= m_nSteps; ++j) {
8970 StepRKN(wire, h, coor, xst, dxst, xMap, yMap, fxMap, fyMap);
8971 csag[i * m_nSteps + j] = coor;
8972 xsag[i * m_nSteps + j] = xst[0];
8973 ysag[i * m_nSteps + j] = xst[1];
8980bool ComponentAnalyticField::GetForceRatio(
8981 const Wire& wire,
const double ,
const std::array<double, 2>& bend,
8982 const std::array<double, 2>& , std::array<double, 2>& f,
8983 const std::vector<double>& xMap,
const std::vector<double>& yMap,
8984 const std::vector<std::vector<double> >& fxMap,
8985 const std::vector<std::vector<double> >& fyMap)
const {
8997 const double xw = wire.x + bend[0];
8998 const double yw = wire.y + bend[1];
8999 if (m_useElectrostaticForce) {
9001 if (xMap.empty() || yMap.empty() || fxMap.empty() || fyMap.empty()) {
9005 if (!m_extrapolateForces) {
9006 if ((xMap.front() - xw) * (xw - xMap.back()) < 0 ||
9007 (yMap.front() - yw) * (yw - yMap.back()) < 0) {
9012 constexpr int order = 2;
9014 const unsigned int nX = xMap.size();
9015 const unsigned int nY = yMap.size();
9016 std::vector<double> xaux(nX, 0.);
9017 std::vector<double> yaux(nX, 0.);
9018 for (
unsigned int i = 0; i < nX; ++i) {
9027 if (m_useGravitationalForce) {
9029 const double m = 1.e-3 * wire.density * Pi * wire.r * wire.r;
9030 f[0] -= m_down[0] * m * GravitationalAcceleration;
9031 f[1] -= m_down[1] * m * GravitationalAcceleration;
9034 const double s = 1000. / (GravitationalAcceleration * wire.tension);
9043bool ComponentAnalyticField::StepRKN(
9044 const Wire& wire,
const double h,
double& x, std::array<double, 2>& y,
9045 std::array<double, 2>& yp,
const std::vector<double>& xMap,
9046 const std::vector<double>& yMap,
9047 const std::vector<std::vector<double> >& fxMap,
9048 const std::vector<std::vector<double> >& fyMap)
const {
9049 constexpr double r2 = 1. / 2.;
9050 constexpr double r6 = 1. / 6.;
9051 constexpr double r8 = 1. / 8.;
9052 if (h == 0)
return true;
9053 const double h2 = r2 * h;
9054 const double h6 = r6 * h;
9055 const double hh2 = h * h2;
9056 const double hh6 = h * h6;
9057 const double hh8 = r8 * h * h;
9059 constexpr unsigned int n = 2;
9060 std::array<std::array<double, n>, 6> w;
9061 if (!GetForceRatio(wire, x, y, yp, w[0], xMap, yMap, fxMap, fyMap)) {
9064 for (
unsigned int j = 0; j < n; ++j) {
9065 w[3][j] =
y[j] + h2 * yp[j];
9066 w[4][j] = w[3][j] + hh8 * w[0][j];
9067 w[5][j] = yp[j] + h2 * w[0][j];
9069 const double xh2 =
x + h2;
9070 if (!GetForceRatio(wire, xh2, w[4], w[5], w[1], xMap, yMap, fxMap, fyMap)) {
9073 for (
unsigned int j = 0; j < n; ++j) {
9074 w[5][j] = yp[j] + h2 * w[1][j];
9075 w[0][j] = w[0][j] + w[1][j];
9076 w[1][j] = w[0][j] + w[1][j];
9078 if (!GetForceRatio(wire, xh2, w[4], w[5], w[2], xMap, yMap, fxMap, fyMap)) {
9081 for (
unsigned int j = 0; j < n; ++j) {
9082 w[3][j] = w[3][j] + h2 * yp[j];
9083 w[4][j] = w[3][j] + hh2 * w[2][j];
9084 w[5][j] = yp[j] + h * w[2][j];
9085 w[0][j] = w[0][j] + w[2][j];
9086 w[1][j] = w[1][j] + 2 * w[2][j];
9088 const double xh =
x + h;
9089 if (!GetForceRatio(wire, xh, w[4], w[5], w[2], xMap, yMap, fxMap, fyMap)) {
9092 for (
unsigned int j = 0; j < n; ++j) {
9093 y[j] = w[3][j] + hh6 * w[0][j];
9094 yp[j] += h6 * (w[1][j] + w[2][j]);
9100bool ComponentAnalyticField::FindZeroes(
9101 const Wire& wire,
const double h, std::vector<double>& x,
9102 const std::vector<double>& xMap,
const std::vector<double>& yMap,
9103 const std::vector<std::vector<double> >& fxMap,
9104 const std::vector<std::vector<double> >& fyMap)
const {
9114 std::cerr <<
m_className <<
"::FindZeroes: Empty vector.\n";
9117 const unsigned int n =
x.size();
9119 std::vector<double> fold(n, 0.);
9120 if (!Trace(wire, h, x, fold, xMap, yMap, fxMap, fyMap)) {
9121 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9122 <<
"Initial position outside scanning area.\n";
9126 std::inner_product(fold.begin(), fold.end(), fold.begin(), 0.);
9128 constexpr unsigned int nbsmax = 10;
9129 constexpr unsigned int nitmax = 20;
9130 constexpr double eps = 1.e-4;
9131 constexpr double epsx = 1.e-4;
9132 constexpr double epsf = 1.e-4;
9134 std::cout <<
m_className <<
"::FindZeroes: Start of zero search.\n"
9135 <<
" Number of parameters: " << n <<
"\n"
9136 <<
" Maximum bisections: " << nbsmax <<
"\n"
9137 <<
" Maximum iterations: " << nitmax <<
"\n"
9138 <<
" Epsilon differentiation: " << eps <<
"\n"
9139 <<
" Required location change: " << epsx <<
"\n"
9140 <<
" Required function norm: " << epsf <<
"\n"
9141 <<
" Initial function norm: " <<
sqrt(fnorml) <<
"\n"
9142 <<
" Parameter Value Function\n";
9143 for (
unsigned int i = 0; i < n; ++i) {
9144 std::printf(
" %9d %12.5e %12.5e\n", i, x[i], fold[i]);
9148 std::vector<std::vector<double> > b(n, std::vector<double>(n, 0.));
9149 std::vector<std::vector<double> > bb(n, std::vector<double>(n, 0.));
9151 bool updateMatrix =
true;
9153 unsigned int nCalls = 0;
9154 bool converged =
false;
9155 for (
unsigned int iter = 0; iter < nitmax; ++iter) {
9158 std::vector<double> f1(n, 0.);
9159 std::vector<double> f2(n, 0.);
9160 for (
unsigned int i = 0; i < n; ++i) {
9161 const double epsdif = eps * (1. + std::abs(x[i]));
9162 x[i] += 0.5 * epsdif;
9163 if (!Trace(wire, h, x, f1, xMap, yMap, fxMap, fyMap)) {
9164 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9165 <<
"Differential matrix requires a point "
9166 <<
"outside scanning area.\n";
9170 if (!Trace(wire, h, x, f2, xMap, yMap, fxMap, fyMap)) {
9171 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9172 <<
"Differential matrix requires a point "
9173 <<
"outside scanning area.\n";
9176 x[i] += 0.5 * epsdif;
9177 for (
unsigned int j = 0; j < n; ++j) {
9178 b[j][i] = (f1[j] - f2[j]) / epsdif;
9182 updateMatrix =
false;
9185 std::cout <<
" Start of iteration " << iter <<
"\n";
9186 for (
unsigned int i = 0; i < m_nShots; ++i) {
9187 const unsigned int k = 4 * i + 2;
9188 std::printf(
" x = %12.5e, y = %12.5e\n", x[k], x[k + 1]);
9192 std::vector<double> dx = fold;
9195 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n"
9196 <<
" Solving the update equation failed.\n";
9200 for (
unsigned int i = 0; i < m_nShots; ++i) {
9201 const unsigned int k = 4 * i + 2;
9202 std::printf(
" dx = %12.5e, dy = %12.5e\n", dx[k], dx[k + 1]);
9207 double fnorm = 2 * fnorml;
9208 std::vector<double> xnew(n, 0.);
9209 std::vector<double> fnew(n, 0.);
9210 for (
unsigned int kbs = 0; kbs < nbsmax; ++kbs) {
9211 for (
unsigned int i = 0; i < n; ++i) {
9212 xnew[i] =
x[i] - scale * dx[i];
9214 if (!Trace(wire, h, xnew, fnew, xMap, yMap, fxMap, fyMap)) {
9216 <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9217 <<
"Step update leads to a point outside the scanning area.\n";
9221 fnorm = std::inner_product(fnew.begin(), fnew.end(), fnew.begin(), 0.);
9222 if (fnorm <= fnorml) {
9223 if (
m_debug) std::cout <<
" Scaling factor: " << scale <<
"\n";
9228 if (fnorm > fnorml) {
9229 std::cerr <<
m_className <<
"::FindZeroes: Zero search stopped.\n "
9230 <<
"Bisection search for scaling factor did not converge.\n";
9234 std::vector<double> df(n, 0.);
9235 for (
unsigned int i = 0; i < n; ++i) {
9236 dx[i] = xnew[i] -
x[i];
9238 df[i] = fnew[i] - fold[i];
9241 double xnorm = std::inner_product(
x.begin(),
x.end(),
x.begin(), 0.);
9242 double dxnorm = std::inner_product(dx.begin(), dx.end(), dx.begin(), 0.);
9243 double dfnorm = std::inner_product(df.begin(), df.end(), df.begin(), 0.);
9246 std::cout <<
" After this iteration...\n";
9247 std::printf(
" Norm and change of position: %12.5e %12.5e\n",
9249 std::printf(
" Norm and change of function: %12.5e %12.5e\n",
9253 if (
sqrt(dxnorm) < epsx *
sqrt(xnorm)) {
9255 std::cout <<
" Positional convergence criterion is satisfied.\n";
9259 }
else if (
sqrt(fnorm) < epsf) {
9261 std::cout <<
" Function value convergence criterion is satisfied.\n";
9268 if (scale > 0.4 && iter != 5 * (iter / 5)) {
9270 if (
m_debug) std::cout <<
" Performing a Broyden rank-1 update.\n";
9272 std::vector<double> corr(n, 0.);
9273 for (
unsigned int i = 0; i < n; ++i) {
9275 for (
unsigned int j = 0; j < n; ++j) {
9276 corr[i] -= b[i][j] * dx[j];
9280 for (
unsigned int i = 0; i < n; ++i) {
9281 for (
unsigned int j = 0; j < n; ++j) {
9282 b[i][j] += corr[i] * dx[j] / dxnorm;
9287 if (
m_debug) std::cout <<
" Recomputing the covariance matrix.\n";
9288 updateMatrix =
true;
9292 std::cerr <<
m_className <<
"::FindZeroes: Search did not converge.\n";
9295 std::vector<double> f(n, 0.);
9296 Trace(wire, h, x, f, xMap, yMap, fxMap, fyMap);
9298 std::cout <<
" Final values:\n"
9299 <<
" Parameter Value Function\n";
9300 for (
unsigned int i = 0; i < n; ++i) {
9301 std::printf(
" %9d %12.5e %12.5e\n", i, x[i], f[i]);
9303 std::cout <<
" Total number of function calls: " << nCalls <<
"\n";
9308bool ComponentAnalyticField::Trace(
9309 const Wire& wire,
const double h,
const std::vector<double>& xx,
9310 std::vector<double>& delta,
const std::vector<double>& xMap,
9311 const std::vector<double>& yMap,
9312 const std::vector<std::vector<double> >& fxMap,
9313 const std::vector<std::vector<double> >& fyMap)
const {
9321 delta.assign(xx.size(), 0.);
9323 double z = -0.5 * wire.u;
9324 std::array<double, 2> xst = {0., 0.};
9325 std::array<double, 2> dxst = {xx[0], xx[1]};
9326 for (
unsigned int i = 0; i <= m_nShots; ++i) {
9327 const unsigned int k = 4 * i;
9330 xst = {xx[k - 2], xx[k - 1]};
9331 dxst = {xx[k], xx[k + 1]};
9334 for (
unsigned int j = 0; j < m_nSteps; ++j) {
9335 if (!StepRKN(wire, h, z, xst, dxst, xMap, yMap, fxMap, fyMap)) {
9341 delta[k] = xst[0] - xx[k + 2];
9342 delta[k + 1] = xst[1] - xx[k + 3];
9343 delta[k + 2] = dxst[0] - xx[k + 4];
9344 delta[k + 3] = dxst[1] - xx[k + 5];
9347 delta[k + 1] = xst[1];
9353bool ComponentAnalyticField::SetupDipoleTerms() {
9361 constexpr double epsp = 1.e-3;
9362 constexpr double epsa = 1.e-3;
9364 const unsigned int nWires = m_w.size();
9366 std::vector<double> phi2(nWires, 0.);
9367 m_cosph2.assign(nWires, 1.);
9368 m_sinph2.assign(nWires, 0.);
9369 m_amp2.assign(nWires, 0.);
9372 std::vector<double> phit2(nWires, 0.);
9373 std::vector<double> ampt2(nWires, 0.);
9374 constexpr unsigned int nMaxIter = 10;
9375 for (
unsigned int iter = 0; iter < nMaxIter; ++iter) {
9377 std::cout <<
"Iteration " << iter <<
"/" << nMaxIter <<
"\n"
9378 <<
" Wire correction angle [deg] amplitude\n";
9381 for (
unsigned int iw = 0; iw < nWires; ++iw) {
9382 const double xw = m_w[iw].x;
9383 const double yw = m_w[iw].y;
9384 const double rw = m_w[iw].r;
9388 constexpr unsigned int nAngles = 20;
9389 std::vector<double> angle(nAngles, 0.);
9390 std::vector<double> volt(nAngles, 0.);
9391 constexpr double rmult = 1.;
9392 const double r = rw * rmult;
9394 for (
unsigned int i = 0; i < nAngles; ++i) {
9395 angle[i] = TwoPi * (i + 1.) / nAngles;
9396 const double x = xw + r *
cos(angle[i]);
9397 const double y = yw + r *
sin(angle[i]);
9398 double ex = 0., ey = 0., ez = 0.;
9399 status = Field(x, y, 0., ex, ey, ez, volt[i],
true);
9401 std::cerr <<
"Unexpected status code; computation stopped.\n";
9404 volt[i] -= m_w[iw].v;
9408 if (status != 0)
continue;
9410 double ampdip = 0., phidip = 0.;
9411 FitDipoleMoment(angle, volt, ampdip, phidip,
false);
9414 ampt2[iw] = ampdip * r;
9416 std::printf(
" %3d %10.3f %12.5e\n",
9417 iw, RadToDegree * phit2[iw], ampt2[iw]);
9421 bool reiter =
false;
9422 if (
m_debug) std::cout <<
" Wire new angle [deg] amplitude\n";
9423 for (
unsigned int iw = 0; iw < nWires; ++iw) {
9425 bool converged =
true;
9426 if (std::abs(phi2[iw]) > epsp * (1. + std::abs(phi2[iw])) ||
9427 std::abs(m_amp2[iw]) > epsa * (1. + std::abs(m_amp2[iw]))) {
9432 const double s0 = m_sinph2[iw] * m_amp2[iw] +
sin(phit2[iw]) * ampt2[iw];
9433 const double c0 = m_cosph2[iw] * m_amp2[iw] +
cos(phit2[iw]) * ampt2[iw];
9434 phi2[iw] = atan2(s0, c0);
9435 m_cosph2[iw] =
cos(phi2[iw]);
9436 m_sinph2[iw] =
sin(phi2[iw]);
9437 const double s1 = m_sinph2[iw] * m_amp2[iw] +
sin(phit2[iw]) * ampt2[iw];
9438 const double c1 = m_cosph2[iw] * m_amp2[iw] +
cos(phit2[iw]) * ampt2[iw];
9439 m_amp2[iw] =
sqrt(s1 * s1 + c1 * c1);
9441 std::printf(
" %3d %10.3f %12.5e %s\n",
9442 iw, RadToDegree * phi2[iw], m_amp2[iw],
9443 converged ?
"CONVERGED" :
"");
9447 if (!reiter)
return true;
9450 std::cerr <<
m_className <<
"::SetupDipoleTerms:\n"
9451 <<
" Maximum number of dipole iterations exceeded "
9452 <<
"without convergence; abandoned.\n";
9456void ComponentAnalyticField::DipoleFieldA00(
9457 const double xpos,
const double ypos,
9458 double& ex,
double& ey,
double& volt,
const bool opt)
const {
9471 for (
unsigned int i = 0; i < m_nWires; ++i) {
9472 const auto& wire = m_w[i];
9473 const double dx = xpos - wire.x;
9474 const double dy = ypos - wire.y;
9475 const double dxm = xpos + wire.x - 2. * m_coplax;
9476 const double dym = ypos + wire.y - 2. * m_coplay;
9478 const double a = dx * dx - dy * dy;
9479 const double b = 2 * dx * dy;
9480 const double d2 = dx * dx + dy * dy;
9481 const double d4 = d2 * d2;
9482 double fx = (a * m_cosph2[i] + b * m_sinph2[i]) / d4;
9483 double fy = (b * m_cosph2[i] - a * m_sinph2[i]) / d4;
9484 if (opt) v = (dx * m_cosph2[i] + dy * m_sinph2[i]) / d2;
9487 const double am = dxm * dxm - dy * dy;
9488 const double bm = 2 * dxm * dy;
9489 const double d2m = dxm * dxm + dy * dy;
9490 const double d4m = d2m * d2m;
9491 fx -= (am * m_cosph2[i] + bm * m_sinph2[i]) / d4m;
9492 fy -= (bm * m_cosph2[i] - am * m_sinph2[i]) / d4m;
9493 if (opt) v -= (dxm * m_cosph2[i] + dy * m_sinph2[i]) / d2m;
9497 const double am = dx * dx - dym * dym;
9498 const double bm = 2 * dx * dym;
9499 const double d2m = dx * dx + dym * dym;
9500 const double d4m = d2m * d2m;
9501 fx -= (am * m_cosph2[i] + bm * m_sinph2[i]) / d4m;
9502 fy -= (bm * m_cosph2[i] - am * m_sinph2[i]) / d4m;
9503 if (opt) v -= (dx * m_cosph2[i] + dym * m_sinph2[i]) / d2m;
9506 if (m_ynplax && m_ynplay) {
9507 const double am = dxm * dxm - dym * dym;
9508 const double bm = 2 * dxm * dym;
9509 const double d2m = dxm * dxm + dym * dym;
9510 const double d4m = d2m * d2m;
9511 fx += (am * m_cosph2[i] + bm * m_sinph2[i]) / d4m;
9512 fy += (bm * m_cosph2[i] - am * m_sinph2[i]) / d4m;
9513 if (opt) v += (dxm * m_cosph2[i] + dym * m_sinph2[i]) / d2m;
9516 volt -= m_amp2[i] * v;
9517 ex -= m_amp2[i] * fx;
9518 ey -= m_amp2[i] * fy;
9522void ComponentAnalyticField::DipoleFieldB1X(
9523 const double xpos,
const double ypos,
9524 double& ex,
double& ey,
double& volt,
const bool opt)
const {
9536 const double tx = Pi / m_sx;
9537 const double tx2 = tx * tx;
9540 for (
unsigned int i = 0; i < m_nWires; ++i) {
9541 const auto& wire = m_w[i];
9543 const double dx = tx * (xpos - wire.x);
9544 const double dy = tx * (ypos - wire.y);
9545 const double a = 1 -
cos(2 * dx) * cosh(2 * dy);
9546 const double b =
sin(2 * dx) * sinh(2 * dy);
9547 const double sx =
sin(dx);
9548 const double shy = sinh(dy);
9549 const double d2 = sx * sx + shy * shy;
9550 const double d4 = d2 * d2;
9551 double fx = ( m_cosph2[i] * a + m_sinph2[i] * b) / d4;
9552 double fy = (-m_sinph2[i] * a + m_cosph2[i] * b) / d4;
9554 v = (m_cosph2[i] *
sin(2 * dx) + m_sinph2[i] * sinh(2 * dy)) / d2;
9558 const double dym = tx * (ypos + wire.y - 2. * m_coplay);
9559 const double am = 1 -
cos(2 * dx) * cosh(2 * dym);
9560 const double bm =
sin(2 * dx) * sinh(2 * dym);
9561 const double shym = sinh(dym);
9562 const double d2m = sx * sx + shym * shym;
9563 const double d4m = d2m * d2m;
9564 fx -= (m_cosph2[i] * am - m_sinph2[i] * bm) / d4m;
9565 fy -= (m_sinph2[i] * am + m_cosph2[i] * bm) / d4m;
9567 v -= (m_cosph2[i] *
sin(2 * dx) - m_sinph2[i] * sinh(2 * dym)) / d2m;
9571 ex -= m_amp2[i] * 0.5 * tx2 * fx;
9572 ey -= m_amp2[i] * 0.5 * tx2 * fy;
9573 if (opt) volt -= 0.5 * tx * m_amp2[i] * v;
9577void ComponentAnalyticField::DipoleFieldB1Y(
9578 const double xpos,
const double ypos,
9579 double& ex,
double& ey,
double& volt,
const bool opt)
const {
9591 const double ty = Pi / m_sy;
9592 const double ty2 = ty * ty;
9595 for (
unsigned int i = 0; i < m_nWires; ++i) {
9596 const auto& wire = m_w[i];
9598 const double dx = ty * (xpos - wire.x);
9599 const double dy = ty * (ypos - wire.y);
9600 const double a = 1 - cosh(2 * dx) *
cos(2 * dy);
9601 const double b = sinh(2 * dx) *
sin(2 * dy);
9602 const double shx = sinh(dx);
9603 const double sy =
sin(dy);
9604 const double d2 = shx * shx + sy * sy;
9605 const double d4 = d2 * d2;
9606 double fx = (-m_cosph2[i] * a + m_sinph2[i] * b) / d4;
9607 double fy = ( m_sinph2[i] * a + m_cosph2[i] * b) / d4;
9609 v = (m_cosph2[i] * sinh(2 * dx) + m_sinph2[i] *
sin(2 * dy)) / d2;
9613 const double dxm = ty * (xpos + wire.x - 2. * m_coplax);
9614 const double am = 1 - cosh(2 * dxm) *
cos(2 * dy);
9615 const double bm = sinh(2 * dxm) *
sin(2 * dy);
9616 const double shxm = sinh(dxm);
9617 const double d2m = shxm * shxm + sy * sy;
9618 const double d4m = d2m * d2m;
9619 fx -= (m_cosph2[i] * am + m_sinph2[i] * bm) / d4m;
9620 fy -= (m_sinph2[i] * am - m_cosph2[i] * bm) / d4m;
9622 v -= (-m_cosph2[i] * sinh(2 * dxm) + m_sinph2[i] *
sin(2 * dy)) / d2m;
9626 ex -= m_amp2[i] * 0.5 * ty2 * fx;
9627 ey -= m_amp2[i] * 0.5 * ty2 * fy;
9628 if (opt) volt -= 0.5 * ty * m_amp2[i] * v;
9632void ComponentAnalyticField::DipoleFieldB2X(
9633 const double xpos,
const double ypos,
9634 double& ex,
double& ey,
double& volt,
const bool opt)
const {
9646 const double tx = HalfPi / m_sx;
9647 const double tx2 = tx * tx;
9650 for (
unsigned int i = 0; i < m_nWires; ++i) {
9651 const auto& wire = m_w[i];
9652 const double dx = tx * (xpos - wire.x);
9653 const double dy = tx * (ypos - wire.y);
9655 const double a = 1 -
cos(2 * dx) * cosh(2 * dy);
9656 const double b =
sin(2 * dx) * sinh(2 * dy);
9657 const double sx =
sin(dx);
9658 const double shy = sinh(dy);
9659 const double d2 = sx * sx + shy * shy;
9660 const double d4 = d2 * d2;
9661 double fx = ( m_cosph2[i] * a + m_sinph2[i] * b) / d4;
9662 double fy = (-m_sinph2[i] * a + m_cosph2[i] * b) / d4;
9663 const double dxn = tx * (xpos + wire.x - 2. * m_coplax);
9664 const double an = 1 -
cos(2 * dxn) * cosh(2 * dy);
9665 const double bn =
sin(2 * dxn) * sinh(2 * dy);
9666 const double sxn =
sin(dxn);
9667 const double d2n = sxn * sxn + shy * shy;
9668 const double d4n = d2n * d2n;
9669 fx += (m_cosph2[i] *
an - m_sinph2[i] * bn) / d4n;
9670 fy += (m_sinph2[i] *
an + m_cosph2[i] * bn) / d4n;
9672 v = -
sin(dx + dxn) * (-2 * m_cosph2[i] * (
9673 (1 + shy * shy) * sx * sxn +
cos(dx) *
cos(dxn) * shy * shy) +
9674 m_sinph2[i] * m_b2sin[i] * sinh(2 * dy)) / (d2 * d2n);
9678 const double dym = tx * (ypos + wire.y - 2. * m_coplay);
9679 const double am = 1 -
cos(2 * dx) * cosh(2 * dym);
9680 const double bm =
sin(2 * dx) * sinh(2 * dym);
9681 const double shym = sinh(dym);
9682 const double d2m = sx * sx + shym * shym;
9683 const double d4m = d2m * d2m;
9684 fx -= (m_cosph2[i] * am - m_sinph2[i] * bm) / d4m;
9685 fy -= (m_sinph2[i] * am + m_cosph2[i] * bm) / d4m;
9686 const double amn = 1 -
cos(2 * dxn) * cosh(2 * dym);
9687 const double bmn =
sin(2 * dxn) * sinh(2 * dym);
9688 const double d2mn = sxn * sxn + shym * shym;
9689 const double d4mn = d2mn * d2mn;
9690 fx -= ( m_cosph2[i] * amn + m_sinph2[i] * bmn) / d4mn;
9691 fy -= (-m_sinph2[i] * amn + m_cosph2[i] * bmn) / d4mn;
9693 v +=
sin(dx + dxn) * (-2 * m_cosph2[i] * (
9694 (1 + shym * shym) * sx * sxn +
cos(dx) *
cos(dxn) * shym * shym) -
9695 m_sinph2[i] * m_b2sin[i] * sinh(2 * dym)) / (d2m * d2mn);
9699 ex -= m_amp2[i] * 0.5 * tx2 * fx;
9700 ey -= m_amp2[i] * 0.5 * tx2 * fy;
9701 if (opt) volt -= 0.5 * tx * m_amp2[i] * v;
9705void ComponentAnalyticField::DipoleFieldB2Y(
9706 const double xpos,
const double ypos,
9707 double& ex,
double& ey,
double& volt,
const bool opt)
const {
9719 const double ty = HalfPi / m_sy;
9720 const double ty2 = ty * ty;
9723 for (
unsigned int i = 0; i < m_nWires; ++i) {
9724 const auto& wire = m_w[i];
9725 const double dx = ty * (xpos - wire.x);
9726 const double dy = ty * (ypos - wire.y);
9728 const double a = 1 - cosh(2 * dx) *
cos(2 * dy);
9729 const double b = sinh(2 * dx) *
sin(2 * dy);
9730 const double shx = sinh(dx);
9731 const double sy =
sin(dy);
9732 const double d2 = shx * shx + sy * sy;
9733 const double d4 = d2 * d2;
9734 double fx = (-m_cosph2[i] * a + m_sinph2[i] * b) / d4;
9735 double fy = ( m_sinph2[i] * a + m_cosph2[i] * b) / d4;
9736 const double dyn = ty * (ypos + wire.y - 2. * m_coplay);
9737 const double an = 1 - cosh(2 * dx) *
sin(2 * dyn);
9738 const double bn = sinh(2 * dx) *
sin(2 * dyn);
9739 const double syn =
sin(dyn);
9740 const double d2n = shx * shx + syn * syn;
9741 const double d4n = d2n * d2n;
9742 fx += (m_cosph2[i] *
an + m_sinph2[i] * bn) / d4n;
9743 fy += (m_sinph2[i] *
an - m_cosph2[i] * bn) / d4n;
9746 v =
sin(dy + dyn) * (
9747 m_sinph2[i] * (-
cos(dy + dyn) +
cos(dy - dyn) * cosh(2 * dx)) -
9748 m_cosph2[i] * sinh(2 * dx) * (
cos(dyn) * sy +
cos(dy) * syn)) /
9753 const double dxm = ty * (xpos + wire.x - 2. * m_coplax);
9754 const double am = 1 - cosh(2 * dxm) *
cos(2 * dy);
9755 const double bm = sinh(2 * dxm) *
sin(2 * dy);
9756 const double shxm = sinh(dxm);
9757 const double d2m = shxm * shxm + sy * sy;
9758 const double d4m = d2m * d2m;
9759 fx -= (m_cosph2[i] * am + m_sinph2[i] * bm) / d4m;
9760 fy -= (m_sinph2[i] * am - m_cosph2[i] * bm) / d4m;
9761 const double amn = 1 - cosh(2 * dxm) *
cos(2 * dyn);
9762 const double bmn = sinh(2 * dxm) *
sin(2 * dyn);
9763 const double d2mn = shxm * shxm + syn * syn;
9764 const double d4mn = d2mn * d2mn;
9765 fx -= (-m_cosph2[i] * amn + m_sinph2[i] * bmn) / d4mn;
9766 fy -= ( m_sinph2[i] * amn + m_cosph2[i] * bmn) / d4mn;
9769 v -=
sin(dy + dyn) * (
9770 m_sinph2[i] * (-
cos(dy + dyn) +
cos(dy - dyn) * cosh(2 * dxm)) +
9771 m_cosph2[i] * sinh(2 * dxm) * (
cos(dyn) * sy -
cos(dy) * syn)) /
9777 ex -= m_amp2[i] * 0.5 * ty2 * fx;
9778 ey -= m_amp2[i] * 0.5 * ty2 * fy;
9779 if (opt) volt -= 0.5 * ty * m_amp2[i] * v;
9784 const unsigned int nPoles,
const bool print,
const bool plot,
9785 const double rmult,
const double eps,
9786 const unsigned int nMaxIter) {
9791 if (!m_cellset && !Prepare())
return false;
9793 if (iw >= m_nWires) {
9794 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
9795 <<
" Wire index out of range.\n";
9799 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
9800 <<
" Epsilon must be positive.\n";
9804 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
9805 <<
" Multipole order out of range.\n";
9809 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
9810 <<
" Radius multiplication factor out of range.\n";
9814 const double xw = m_w[iw].x;
9815 const double yw = m_w[iw].y;
9817 const double rw = m_w[iw].r;
9821 constexpr unsigned int nPoints = 20000;
9822 std::vector<double> angle(nPoints, 0.);
9823 std::vector<double> volt(nPoints, 0.);
9824 std::vector<double> weight(nPoints, 1.);
9825 for (
unsigned int i = 0; i < nPoints; ++i) {
9827 angle[i] = TwoPi * (i + 1.) / nPoints;
9829 const double x = xw + rmult * rw * cos(angle[i]);
9830 const double y = yw + rmult * rw * sin(angle[i]);
9831 double ex = 0., ey = 0., ez = 0., v = 0.;
9832 if (Field(x, y, 0., ex, ey, ez, v,
true) != 0) {
9833 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
9834 <<
" Unexpected location code. Computation stopped.\n";
9845 double vmin = *std::min_element(volt.cbegin(), volt.cend());
9846 double vmax = *std::max_element(volt.cbegin(), volt.cend());
9847 double vave = std::accumulate(volt.cbegin(), volt.cend(), 0.) / nPoints;
9849 for (
unsigned int i = 0; i < nPoints; ++i) volt[i] -= vave;
9854 const double vm = 0.5 * fabs(vmin) + fabs(vmax);
9855 double chi2 = 1.e-6 * nPoints * vm * vm;
9856 const double dist = 1.e-3 * (1. + vm);
9857 const unsigned int nPar = 2 * nPoles + 1;
9858 std::vector<double> pars(nPar, 0.);
9859 std::vector<double> epar(nPar, 0.);
9860 pars[0] = 0.5 * (vmax + vmin);
9861 for (
unsigned int i = 1; i <= nPoles; ++i) {
9862 pars[2 * i - 1] = 0.5 * (vmax - vmin);
9866 auto f = [nPoles](
const double x,
const std::vector<double>& par) {
9869 double sum = par[0];
9870 for (
unsigned int k = 1; k <= nPoles; ++k) {
9872 const float cphi = cos(x - par[2 * k]);
9879 nMaxIter, dist, chi2, eps,
m_debug, print)) {
9880 std::cerr <<
m_className <<
"::MultipoleMoments:\n"
9881 <<
" Fitting the multipoles failed; computation stopped.\n";
9885 TCanvas* cfit =
new TCanvas();
9888 cfit->DrawFrame(0., vmin, TwoPi, vmax,
9889 ";Angle around the wire [rad]; Potential - average [V]");
9891 graph.SetLineWidth(2);
9892 graph.SetLineColor(kBlack);
9893 graph.DrawGraph(angle.size(), angle.data(), volt.data(),
"lsame");
9895 constexpr unsigned int nP = 1000;
9896 std::array<double, nP> xp;
9897 std::array<double, nP> yp;
9898 for (
unsigned int i = 0; i < nP; ++i) {
9899 xp[i] = TwoPi * (i + 1.) / nP;
9900 yp[i] = f(xp[i], pars);
9902 graph.SetLineColor(kViolet + 3);
9903 graph.DrawGraph(nP, xp.data(), yp.data(),
"lsame");
9905 std::vector<double> parres = pars;
9906 for (
unsigned int i = 1; i <= nPoles; ++i) parres[2 * i - 1] = 0.;
9907 for (
unsigned int j = 1; j <= nPoles; ++j) {
9908 parres[2 * j - 1] = pars[2 * j - 1];
9909 for (
unsigned int i = 0; i < nP; ++i) {
9910 yp[i] = f(xp[i], parres);
9912 parres[2 * j - 1] = 0.;
9913 graph.SetLineColor(kAzure + j);
9914 graph.DrawGraph(nP, xp.data(), yp.data(),
"lsame");
9919 std::cout <<
m_className <<
"::MultipoleMoments:\n"
9920 <<
" Multipole moments for wire " << iw <<
":\n"
9921 <<
" Moment Value Angle [degree]\n";
9922 std::printf(
" %6u %15.8f Arbitrary\n", 0, vave);
9923 for (
unsigned int i = 1; i <= nPoles; ++i) {
9925 const double val = pow(rmult * rw, i) * pars[2 * i - 1];
9926 const double phi = RadToDegree * fmod(pars[2 * i], Pi);
9927 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 AddPixelOnPlaneY(const double y, const double xmin, const double xmax, const double zmin, const double zmax, const std::string &label, const double gap=-1.)
Add a pixel on an existing plane at constant y.
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.)
Add a strip in the y or z direction on an existing plane at constant x.
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.
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.)
Add a pixel on an existing plane at constant x.
bool IsInTrapRadius(const double q0, const double x0, const double y0, const double z0, double &xw, double &yx, double &rw) override
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 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_periodic
Simple periodicity in x, y, z.
std::array< bool, 3 > m_rotationSymmetric
Rotation symmetry around x-axis, y-axis, z-axis.
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
GeometryBase * m_geometry
Pointer to the geometry.
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
std::string m_className
Class name.
bool m_debug
Switch on/off debugging messages.
virtual Medium * GetMedium(const double x, const double y, const double z) const =0
Retrieve the medium at a given point.
virtual bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)=0
Get the bounding box (envelope of the geometry).
Abstract base class for media.
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)