1268 const auto totalWeight = weightPhi * weightR * weightZ;
1269 sum +=
val * totalWeight;
1270 sumW += totalWeight;
1276 const int iZ = (
side ==
Side::A) ? (iBinZ - mParamGrid.NZVertices - 1) : (mParamGrid.NZVertices - iBinZ);
1277 mDensity[
side](iZ, iBinR - 1, iBinPhi - 1) =
sum;
1283template <
typename DataT>
1284template <
typename ElectricFields>
1287 const Side side = formulaStruct.getSide();
1288 if (
type == Type::Distortions) {
1289 initContainer(mLocalDistdR[
side],
true);
1290 initContainer(mLocalDistdZ[
side],
true);
1291 initContainer(mLocalDistdRPhi[
side],
true);
1293 initContainer(mLocalCorrdR[
side],
true);
1294 initContainer(mLocalCorrdZ[
side],
true);
1295 initContainer(mLocalCorrdRPhi[
side],
true);
1299#pragma omp parallel for num_threads(sNThreads)
1300 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1302 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1304 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1313 const DataT stepSize = (z1 - z0) / sSteps;
1314 for (
int iter = 0; iter < sSteps; ++iter) {
1315 const DataT z0Tmp = (z0 + iter * stepSize + dzTmp);
1316 const DataT z1Tmp = (z0Tmp + stepSize);
1322 const DataT radiusTmp = regulateR(radius + drTmp,
side);
1323 const DataT phiTmp = regulatePhi(phi + dPhiTmp,
side);
1326 calcDistCorr(radiusTmp, phiTmp, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct,
true,
side);
1336 case Type::Corrections:
1337 mLocalCorrdR[
side](iZ + 1, iR, iPhi) = drTmp;
1338 mLocalCorrdRPhi[
side](iZ + 1, iR, iPhi) = dPhiTmp * radius;
1339 mLocalCorrdZ[
side](iZ + 1, iR, iPhi) = dzTmp;
1342 case Type::Distortions:
1343 mLocalDistdR[
side](iZ, iR, iPhi) = drTmp;
1344 mLocalDistdRPhi[
side](iZ, iR, iPhi) = dPhiTmp * radius;
1345 mLocalDistdZ[
side](iZ, iR, iPhi) = dzTmp;
1351 case Type::Corrections:
1352 mLocalCorrdR[
side](0, iR, iPhi) = 3 * (mLocalCorrdR[
side](1, iR, iPhi) - mLocalCorrdR[
side](2, iR, iPhi)) + mLocalCorrdR[
side](3, iR, iPhi);
1353 mLocalCorrdRPhi[
side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[
side](1, iR, iPhi) - mLocalCorrdRPhi[
side](2, iR, iPhi)) + mLocalCorrdRPhi[
side](3, iR, iPhi);
1354 mLocalCorrdZ[
side](0, iR, iPhi) = 3 * (mLocalCorrdZ[
side](1, iR, iPhi) - mLocalCorrdZ[
side](2, iR, iPhi)) + mLocalCorrdZ[
side](3, iR, iPhi);
1357 case Type::Distortions:
1358 mLocalDistdR[
side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdR[
side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdR[
side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdR[
side](mParamGrid.NZVertices - 4, iR, iPhi);
1359 mLocalDistdRPhi[
side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdRPhi[
side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdRPhi[
side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdRPhi[
side](mParamGrid.NZVertices - 4, iR, iPhi);
1360 mLocalDistdZ[
side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdZ[
side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdZ[
side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdZ[
side](mParamGrid.NZVertices - 4, iR, iPhi);
1367template <
typename DataT>
1368template <
typename ElectricFields>
1371 const Side side = formulaStruct.getSide();
1372 initContainer(mLocalVecDistdR[
side],
true);
1373 initContainer(mLocalVecDistdZ[
side],
true);
1374 initContainer(mLocalVecDistdRPhi[
side],
true);
1375 initContainer(mElectricFieldEr[
side],
true);
1376 initContainer(mElectricFieldEz[
side],
true);
1377 initContainer(mElectricFieldEphi[
side],
true);
1379#pragma omp parallel for num_threads(sNThreads)
1380 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1381 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1382 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
1383 const DataT ezField = getEzField(formulaStruct.getSide());
1384 const DataT er = mElectricFieldEr[
side](iZ, iR, iPhi);
1385 const DataT ez0 = mElectricFieldEz[
side](iZ, iR, iPhi);
1386 const DataT ephi = mElectricFieldEphi[
side](iZ, iR, iPhi);
1387 const DataT ez = getSign(formulaStruct.getSide()) * 1. / (ezField + ez0);
1388 const DataT erez = er * ez;
1389 const DataT ephiez = ephi * ez;
1391 const DataT vecdR = mC0 * erez + mC1 * ephiez;
1392 const DataT vecdRPhi = mC0 * ephiez - mC1 * erez;
1395 mLocalVecDistdR[
side](iZ, iR, iPhi) = vecdR;
1396 mLocalVecDistdRPhi[
side](iZ, iR, iPhi) = vecdRPhi;
1397 mLocalVecDistdZ[
side](iZ, iR, iPhi) = vecdZ;
1403template <
typename DataT>
1404template <
typename ElectricFields>
1407 if (
type == Type::Distortions) {
1408 initContainer(mLocalDistdR[
side],
true);
1409 initContainer(mLocalDistdZ[
side],
true);
1410 initContainer(mLocalDistdRPhi[
side],
true);
1412 initContainer(mLocalCorrdR[
side],
true);
1413 initContainer(mLocalCorrdZ[
side],
true);
1414 initContainer(mLocalCorrdRPhi[
side],
true);
1418#pragma omp parallel for num_threads(sNThreads)
1419 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1421 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1423 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1425 const size_t iZ0 =
type == Type::Corrections ? iZ + 1 : iZ;
1426 const size_t iZ1 =
type == Type::Corrections ? iZ : iZ + 1;
1431 const DataT stepSize = z1 - z0;
1432 const DataT absstepSize = std::abs(stepSize);
1434 const DataT stepSizeHalf = 0.5 * stepSize;
1435 const DataT absstepSizeHalf = std::abs(stepSizeHalf);
1438 const DataT zk1 = z0;
1439 const DataT rk1 = radius;
1440 const DataT phik1 = phi;
1448 case Type::Corrections:
1449 k1dR = getLocalVecCorrR(iZ0, iR, iPhi,
side);
1450 k1dZ = getLocalVecCorrZ(iZ0, iR, iPhi,
side);
1451 k1dRPhi = getLocalVecCorrRPhi(iZ0, iR, iPhi,
side);
1454 case Type::Distortions:
1455 k1dR = getLocalVecDistR(iZ0, iR, iPhi,
side);
1456 k1dZ = getLocalVecDistZ(iZ0, iR, iPhi,
side);
1457 k1dRPhi = getLocalVecDistRPhi(iZ0, iR, iPhi,
side);
1462 const DataT zk2 = zk1 + stepSizeHalf + absstepSizeHalf * k1dZ;
1463 const DataT rk2 = rk1 + absstepSizeHalf * k1dR;
1464 const DataT k1dPhi = k1dRPhi / rk1;
1465 const DataT phik2 = phik1 + absstepSizeHalf * k1dPhi;
1471 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk2, rk2, phik2,
side, k2dZ, k2dR, k2dRPhi) : getLocalDistortionVectorCyl(zk2, rk2, phik2,
side, k2dZ, k2dR, k2dRPhi);
1474 const DataT zk3 = zk1 + stepSizeHalf + absstepSizeHalf * k2dZ;
1475 const DataT rk3 = rk1 + absstepSizeHalf * k2dR;
1476 const DataT k2dPhi = k2dRPhi / rk2;
1477 const DataT phik3 = phik1 + absstepSizeHalf * k2dPhi;
1482 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk3, rk3, phik3,
side, k3dZ, k3dR, k3dRPhi) : getLocalDistortionVectorCyl(zk3, rk3, phik3,
side, k3dZ, k3dR, k3dRPhi);
1484 const DataT zk4 = zk1 + stepSize + absstepSize * k3dZ;
1485 const DataT rk4 = rk1 + absstepSize * k3dR;
1486 const DataT k3dPhi = k3dRPhi / rk3;
1487 const DataT phik4 = phik1 + absstepSize * k3dPhi;
1492 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk4, rk4, phik4,
side, k4dZ, k4dR, k4dRPhi) : getLocalDistortionVectorCyl(zk4, rk4, phik4,
side, k4dZ, k4dR, k4dRPhi);
1493 const DataT k4dPhi = k4dRPhi / rk4;
1496 const DataT stepsizeSixth = absstepSize / 6;
1497 const DataT drRK = stepsizeSixth * (k1dR + 2 * k2dR + 2 * k3dR + k4dR);
1498 const DataT dzRK = stepsizeSixth * (k1dZ + 2 * k2dZ + 2 * k3dZ + k4dZ);
1499 const DataT dphiRK = stepsizeSixth * (k1dPhi + 2 * k2dPhi + 2 * k3dPhi + k4dPhi);
1503 case Type::Corrections:
1504 mLocalCorrdR[
side](iZ + 1, iR, iPhi) = drRK;
1505 mLocalCorrdRPhi[
side](iZ + 1, iR, iPhi) = dphiRK * radius;
1506 mLocalCorrdZ[
side](iZ + 1, iR, iPhi) = dzRK;
1509 case Type::Distortions:
1510 mLocalDistdR[
side](iZ, iR, iPhi) = drRK;
1511 mLocalDistdRPhi[
side](iZ, iR, iPhi) = dphiRK * radius;
1512 mLocalDistdZ[
side](iZ, iR, iPhi) = dzRK;
1518 case Type::Corrections:
1519 mLocalCorrdR[
side](0, iR, iPhi) = 3 * (mLocalCorrdR[
side](1, iR, iPhi) - mLocalCorrdR[
side](2, iR, iPhi)) + mLocalCorrdR[
side](3, iR, iPhi);
1520 mLocalCorrdRPhi[
side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[
side](1, iR, iPhi) - mLocalCorrdRPhi[
side](2, iR, iPhi)) + mLocalCorrdRPhi[
side](3, iR, iPhi);
1521 mLocalCorrdZ[
side](0, iR, iPhi) = 3 * (mLocalCorrdZ[
side](1, iR, iPhi) - mLocalCorrdZ[
side](2, iR, iPhi)) + mLocalCorrdZ[
side](3, iR, iPhi);
1524 case Type::Distortions:
1525 mLocalDistdR[
side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdR[
side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdR[
side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdR[
side](mParamGrid.NZVertices - 4, iR, iPhi);
1526 mLocalDistdRPhi[
side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdRPhi[
side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdRPhi[
side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdRPhi[
side](mParamGrid.NZVertices - 4, iR, iPhi);
1527 mLocalDistdZ[
side](mParamGrid.NZVertices - 1, iR, iPhi) = 3 * (mLocalDistdZ[
side](mParamGrid.NZVertices - 2, iR, iPhi) - mLocalDistdZ[
side](mParamGrid.NZVertices - 3, iR, iPhi)) + mLocalDistdZ[
side](mParamGrid.NZVertices - 4, iR, iPhi);
1534template <
typename DataT>
1535template <
typename Fields>
1538 const Side side = formulaStruct.getSide();
1539 initContainer(mGlobalDistdR[
side],
true);
1540 initContainer(mGlobalDistdZ[
side],
true);
1541 initContainer(mGlobalDistdRPhi[
side],
true);
1542 const DataT stepSize = formulaStruct.getID() == 2 ? getGridSpacingZ(
side) : getGridSpacingZ(
side) / sSteps;
1544#pragma omp parallel for num_threads(sNThreads)
1545 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1547 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1549 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1552 DataT dPhiDist = 0.0;
1557 if (iter > maxIterations) {
1558 LOGP(error,
"Aborting calculation of distortions for iZ: {}, iR: {}, iPhi: {} due to iteration '{}' > maxIterations '{}'!", iZ, iR, iPhi, iter, maxIterations);
1561 const DataT z0Tmp = z0 + dzDist + iter * stepSize;
1564 if ((getSide(z0Tmp) !=
side) && iter) {
1565 LOGP(error,
"Aborting calculation of distortions for iZ: {}, iR: {}, iPhi: {} due to change in the sides!", iZ, iR, iPhi);
1569 const DataT z1Tmp = z0Tmp + stepSize;
1570 const DataT radius = regulateR(r0 + drDist,
side);
1571 const DataT phi = regulatePhi(phi0 + dPhiDist,
side);
1578 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct);
1582 const bool checkReached =
side ==
Side::A ? z1Tmp >= getZMax(
side) : z1Tmp <= getZMax(
side);
1583 if (formulaStruct.getID() == 2 && checkReached) {
1584 const DataT fac = std::abs((getZMax(
side) - z0Tmp) * getInvSpacingZ(
side));
1598 const DataT endPoint = z1Tmp + ddZ;
1599 const DataT deltaZ = getZMax(
side) - endPoint;
1600 const DataT diff = endPoint - z0Tmp;
1601 const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0;
1602 drDist += ddR * fac;
1603 dPhiDist += ddPhi * fac;
1604 dzDist += ddZ * fac;
1610 mGlobalDistdR[
side](iZ, iR, iPhi) = drDist;
1611 mGlobalDistdRPhi[
side](iZ, iR, iPhi) = dPhiDist * r0;
1612 mGlobalDistdZ[
side](iZ, iR, iPhi) = dzDist;
1618template <
typename DataT>
1619template <
typename Formulas>
1622 using timer = std::chrono::high_resolution_clock;
1623 auto start = timer::now();
1624 const Side side = formulaStruct.getSide();
1625 initContainer(mGlobalCorrdR[
side],
true);
1626 initContainer(mGlobalCorrdZ[
side],
true);
1627 initContainer(mGlobalCorrdRPhi[
side],
true);
1629 const int iSteps = formulaStruct.getID() == 2 ? 1 : sSteps;
1630 const DataT stepSize = -getGridSpacingZ(
side) / iSteps;
1632#pragma omp parallel for num_threads(sNThreads)
1633 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1635 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1641 bool isOutOfVolume =
false;
1644 for (
size_t iZ = mParamGrid.NZVertices - 1; iZ >= 1; --iZ) {
1647 bool centralElectrodeReached =
false;
1648 for (
int iter = 0; iter < iSteps; ++iter) {
1649 if ((
type != 3) && (centralElectrodeReached || isOutOfVolume)) {
1652 DataT radius = r0 + drCorr;
1653 DataT phi = phi0 + dPhiCorr;
1654 const DataT z0Tmp = z0 + dzCorr + iter * stepSize;
1655 DataT z1Tmp = z0Tmp + stepSize;
1659 radius = regulateR(radius,
side);
1660 phi = regulatePhi(phi,
side);
1661 z1Tmp = regulateZ(z1Tmp,
side);
1669 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct);
1673 centralElectrodeReached = getSign(
side) * z1Tmp <= getZMin(
side);
1674 if (formulaStruct.getID() == 2 && centralElectrodeReached) {
1675 const DataT fac = (z0Tmp - getZMin(
side)) * getInvSpacingZ(
side);
1682 const DataT rCurr = r0 + drCorr + ddR;
1683 const DataT zCurr = z0Tmp + dzCorr + ddZ + stepSize;
1686 if ((
type != 3) && (rCurr <= getRMinSim(
side) || rCurr >= getRMaxSim(
side) || (std::abs(zCurr) > 1.2 * std::abs(getZMax(
side))))) {
1687 isOutOfVolume =
true;
1698 if ((
type != 3) && centralElectrodeReached) {
1699 const DataT endPoint = z1Tmp + ddZ;
1700 const DataT deltaZ = endPoint - getZMin(
side);
1701 const DataT diff = z0Tmp - endPoint;
1702 const DataT fac = diff != 0 ? deltaZ / diff : 0;
1703 drCorr += ddR * fac;
1704 dPhiCorr += ddPhi * fac;
1705 dzCorr += ddZ * fac;
1710 if ((
type == 1 ||
type == 2) && (centralElectrodeReached || isOutOfVolume)) {
1711 mGlobalCorrdR[
side](iZ - 1, iR, iPhi) = -1;
1712 mGlobalCorrdRPhi[
side](iZ - 1, iR, iPhi) = -1;
1713 mGlobalCorrdZ[
side](iZ - 1, iR, iPhi) = -1;
1715 mGlobalCorrdR[
side](iZ - 1, iR, iPhi) = drCorr;
1716 mGlobalCorrdRPhi[
side](iZ - 1, iR, iPhi) = dPhiCorr * r0;
1717 mGlobalCorrdZ[
side](iZ - 1, iR, iPhi) = dzCorr;
1724 for (
int iZ = mParamGrid.NZVertices - 1; iZ >= 0; --iZ) {
1726 for (
int iR = (mParamGrid.NRVertices / 2); iR >= 0; --iR) {
1727 if ((mGlobalCorrdR[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdRPhi[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdZ[
side](iZ, iR, iPhi) == -1)) {
1728 const size_t iRUp = iR + 1;
1731 mGlobalCorrdR[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1732 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1733 mGlobalCorrdZ[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1734 }
else if (
type == 2) {
1736 const size_t iRUpTwo = iR + 2;
1737 const size_t iRUpThree = iR + 3;
1738 mGlobalCorrdR[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdR[
side](iZ, iRUp, iPhi) - mGlobalCorrdR[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdR[
side](iZ, iRUpThree, iPhi);
1739 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdRPhi[
side](iZ, iRUp, iPhi) - mGlobalCorrdRPhi[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdRPhi[
side](iZ, iRUpThree, iPhi);
1740 mGlobalCorrdZ[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdZ[
side](iZ, iRUp, iPhi) - mGlobalCorrdZ[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdZ[
side](iZ, iRUpThree, iPhi);
1745 for (
int iR = (mParamGrid.NRVertices / 2); iR < mParamGrid.NRVertices; ++iR) {
1746 if ((mGlobalCorrdR[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdRPhi[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdZ[
side](iZ, iR, iPhi) == -1)) {
1747 const size_t iRUp = iR - 1;
1750 mGlobalCorrdR[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1751 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1752 mGlobalCorrdZ[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1753 }
else if (
type == 2) {
1755 const size_t iRUpTwo = iR - 2;
1756 const size_t iRUpThree = iR - 3;
1757 mGlobalCorrdR[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdR[
side](iZ, iRUp, iPhi) - mGlobalCorrdR[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdR[
side](iZ, iRUpThree, iPhi);
1758 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdRPhi[
side](iZ, iRUp, iPhi) - mGlobalCorrdRPhi[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdRPhi[
side](iZ, iRUpThree, iPhi);
1759 mGlobalCorrdZ[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdZ[
side](iZ, iRUp, iPhi) - mGlobalCorrdZ[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdZ[
side](iZ, iRUpThree, iPhi);
1767 auto stop = timer::now();
1768 std::chrono::duration<float>
time = stop -
start;
1769 const float totalTime =
time.count();
1770 LOGP(detail,
"calcGlobalCorrections took {}s", totalTime);
1773template <
typename DataT>
1779 const Side side = getSide(point.Z());
1782 getCorrections(point.X(), point.Y(), point.Z(),
side, corrX, corrY, corrZ);
1785 point.SetXYZ(point.X() + corrX, point.Y() + corrY, point.Y() + corrY);
1788template <
typename DataT>
1794 const Side side = getSide(point.Z());
1796 getDistortions(point.X(), point.Y(), point.Z(),
side, distX, distY, distZ);
1803 if (scSCale && scale != 0) {
1804 scSCale->
getDistortions(point.X() + distX, point.Y() + distY, point.Z() + distZ,
side, distXTmp, distYTmp, distZTmp);
1805 distX += distXTmp * scale;
1806 distY += distYTmp * scale;
1807 distZ += distZTmp * scale;
1812 float phi = std::atan2(
pos.Y(),
pos.X());
1816 unsigned char secNum = std::floor(phi /
SECPHIWIDTH);
1820 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_distortElectron",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_distortElectron").data()
1824 <<
"secNum=" << secNum
1825 <<
"distX=" << distX
1826 <<
"distY=" << distY
1827 <<
"distZ=" << distZ
1828 <<
"distXDer=" << distXTmp
1829 <<
"distYDer=" << distYTmp
1830 <<
"distZDer=" << distZTmp
1831 <<
"scale=" << scale
1836 point.SetXYZ(point.X() + distX, point.Y() + distY, point.Z() + distZ);
1839template <
typename DataT>
1842 return mInterpolatorDensity[
side](
z,
r, phi);
1845template <
typename DataT>
1848 const auto nPoints =
z.size();
1849 std::vector<float> density(nPoints);
1850#pragma omp parallel for num_threads(sNThreads)
1851 for (
size_t i = 0;
i < nPoints; ++
i) {
1852 density[
i] = getDensityCyl(
z[
i],
r[
i], phi[
i],
side);
1857template <
typename DataT>
1860 return mInterpolatorPotential[
side](
z,
r, phi);
1863template <
typename DataT>
1866 const auto nPoints =
z.size();
1867 std::vector<float> potential(nPoints);
1868#pragma omp parallel for num_threads(sNThreads)
1869 for (
size_t i = 0;
i < nPoints; ++
i) {
1870 potential[
i] = getPotentialCyl(
z[
i],
r[
i], phi[
i],
side);
1875template <
typename DataT>
1878 eZ = mInterpolatorEField[
side].evalFieldZ(
z,
r, phi);
1879 eR = mInterpolatorEField[
side].evalFieldR(
z,
r, phi);
1880 ePhi = mInterpolatorEField[
side].evalFieldPhi(
z,
r, phi);
1883template <
typename DataT>
1886 lcorrZ = mInterpolatorLocalCorr[
side].evaldZ(
z,
r, phi);
1887 lcorrR = mInterpolatorLocalCorr[
side].evaldR(
z,
r, phi);
1888 lcorrRPhi = mInterpolatorLocalCorr[
side].evaldRPhi(
z,
r, phi);
1891template <
typename DataT>
1894 const auto nPoints =
z.size();
1895 lcorrZ.resize(nPoints);
1896 lcorrR.resize(nPoints);
1897 lcorrRPhi.resize(nPoints);
1898#pragma omp parallel for num_threads(sNThreads)
1899 for (
size_t i = 0;
i < nPoints; ++
i) {
1900 getLocalCorrectionsCyl(
z[
i],
r[
i], phi[
i],
side, lcorrZ[
i], lcorrR[
i], lcorrRPhi[
i]);
1904template <
typename DataT>
1907 corrZ = mInterpolatorGlobalCorr[
side].evaldZ(
z,
r, phi);
1908 corrR = mInterpolatorGlobalCorr[
side].evaldR(
z,
r, phi);
1909 corrRPhi = mInterpolatorGlobalCorr[
side].evaldRPhi(
z,
r, phi);
1912template <
typename DataT>
1915 const auto nPoints =
z.size();
1916 corrZ.resize(nPoints);
1917 corrR.resize(nPoints);
1918 corrRPhi.resize(nPoints);
1919#pragma omp parallel for num_threads(sNThreads)
1920 for (
size_t i = 0;
i < nPoints; ++
i) {
1921 getCorrectionsCyl(
z[
i],
r[
i], phi[
i],
side, corrZ[
i], corrR[
i], corrRPhi[
i]);
1925template <
typename DataT>
1928 if (mUseAnaDistCorr) {
1929 getCorrectionsAnalytical(
x,
y,
z,
side, corrX, corrY, corrZ);
1932 const DataT radius = getRadiusFromCartesian(
x,
y);
1933 DataT phi = getPhiFromCartesian(
x,
y);
1938 getCorrectionsCyl(
z, radius, phi,
side, corrZ, corrR, corrRPhi);
1941 const DataT radiusCorr = radius + corrR;
1942 const DataT phiCorr = phi + corrRPhi / radius;
1944 corrX = getXFromPolar(radiusCorr, phiCorr) -
x;
1945 corrY = getYFromPolar(radiusCorr, phiCorr) -
y;
1949template <
typename DataT>
1952 ldistZ = mInterpolatorLocalDist[
side].evaldZ(
z,
r, phi);
1953 ldistR = mInterpolatorLocalDist[
side].evaldR(
z,
r, phi);
1954 ldistRPhi = mInterpolatorLocalDist[
side].evaldRPhi(
z,
r, phi);
1957template <
typename DataT>
1960 const auto nPoints =
z.size();
1961 ldistZ.resize(nPoints);
1962 ldistR.resize(nPoints);
1963 ldistRPhi.resize(nPoints);
1964#pragma omp parallel for num_threads(sNThreads)
1965 for (
size_t i = 0;
i < nPoints; ++
i) {
1966 getLocalDistortionsCyl(
z[
i],
r[
i], phi[
i],
side, ldistZ[
i], ldistR[
i], ldistRPhi[
i]);
1970template <
typename DataT>
1973 lvecdistZ = mInterpolatorLocalVecDist[
side].evaldZ(
z,
r, phi);
1974 lvecdistR = mInterpolatorLocalVecDist[
side].evaldR(
z,
r, phi);
1975 lvecdistRPhi = mInterpolatorLocalVecDist[
side].evaldRPhi(
z,
r, phi);
1978template <
typename DataT>
1981 const auto nPoints =
z.size();
1982 lvecdistZ.resize(nPoints);
1983 lvecdistR.resize(nPoints);
1984 lvecdistRPhi.resize(nPoints);
1985#pragma omp parallel for num_threads(sNThreads)
1986 for (
size_t i = 0;
i < nPoints; ++
i) {
1987 getLocalDistortionVectorCyl(
z[
i],
r[
i], phi[
i],
side, lvecdistZ[
i], lvecdistR[
i], lvecdistRPhi[
i]);
1991template <
typename DataT>
1994 lveccorrZ = -mInterpolatorLocalVecDist[
side].evaldZ(
z,
r, phi);
1995 lveccorrR = -mInterpolatorLocalVecDist[
side].evaldR(
z,
r, phi);
1996 lveccorrRPhi = -mInterpolatorLocalVecDist[
side].evaldRPhi(
z,
r, phi);
1999template <
typename DataT>
2002 const auto nPoints =
z.size();
2003 lveccorrZ.resize(nPoints);
2004 lveccorrR.resize(nPoints);
2005 lveccorrRPhi.resize(nPoints);
2006#pragma omp parallel for num_threads(sNThreads)
2007 for (
size_t i = 0;
i < nPoints; ++
i) {
2008 getLocalCorrectionVectorCyl(
z[
i],
r[
i], phi[
i],
side, lveccorrZ[
i], lveccorrR[
i], lveccorrRPhi[
i]);
2012template <
typename DataT>
2015 distZ = mInterpolatorGlobalDist[
side].evaldZ(
z,
r, phi);
2016 distR = mInterpolatorGlobalDist[
side].evaldR(
z,
r, phi);
2017 distRPhi = mInterpolatorGlobalDist[
side].evaldRPhi(
z,
r, phi);
2020template <
typename DataT>
2023 const auto nPoints =
z.size();
2024 distZ.resize(nPoints);
2025 distR.resize(nPoints);
2026 distRPhi.resize(nPoints);
2027#pragma omp parallel for num_threads(sNThreads)
2028 for (
size_t i = 0;
i < nPoints; ++
i) {
2029 getDistortionsCyl(
z[
i],
r[
i], phi[
i],
side, distZ[
i], distR[
i], distRPhi[
i]);
2033template <
typename DataT>
2038 if (mUseAnaDistCorr) {
2039 getDistortionsAnalytical(
x,
y, zClamped,
side, distX, distY, distZ);
2042 const DataT radius = getRadiusFromCartesian(
x,
y);
2043 const DataT phi = getPhiFromCartesian(
x,
y);
2047 DataT rClamped = regulateR(radius,
side);
2048 getDistortionsCyl(zClamped, rClamped, phi,
side, distZ, distR, distRPhi);
2051 const DataT radiusDist = rClamped + distR;
2052 const DataT phiDist = phi + distRPhi / rClamped;
2054 distX = getXFromPolar(radiusDist, phiDist) -
x;
2055 distY = getYFromPolar(radiusDist, phiDist) -
y;
2059template <
typename DataT>
2063 float phi = std::atan2(
pos.Y(),
pos.X());
2067 const unsigned char secNum = std::floor(phi /
SECPHIWIDTH);
2072 const DataT dlX = dist ? mAnaDistCorr.getDistortionsLX(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLX(lPos.X(), lPos.Y(), lPos.Z(),
side);
2073 const DataT dlY = dist ? mAnaDistCorr.getDistortionsLY(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLY(lPos.X(), lPos.Y(), lPos.Z(),
side);
2074 const DataT dlZ = dist ? mAnaDistCorr.getDistortionsLZ(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLZ(lPos.X(), lPos.Y(), lPos.Z(),
side);
2078 const LocalPosition3D lPosDist(lPos.X() + dlX, lPos.Y() + dlY, lPos.Z() + dlZ);
2082 distX = globalPosDist.X() -
x;
2083 distY = globalPosDist.Y() -
y;
2084 distZ = globalPosDist.Z() -
z;
2087 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_distortions_analytical",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_distortions_analytical").data()
2090 <<
"dlX=" << (*
const_cast<DataT*
>(&dlX))
2091 <<
"dlY=" << (*
const_cast<DataT*
>(&dlY))
2092 <<
"dlZ=" << (*
const_cast<DataT*
>(&dlZ))
2093 <<
"distX=" << distX
2094 <<
"distY=" << distY
2095 <<
"distZ=" << distZ
2100template <
typename DataT>
2103 using timer = std::chrono::high_resolution_clock;
2104 if (!mInitLookUpTables) {
2105 auto start = timer::now();
2110 float vDrift = gasParam.DriftV;
2112 const float t1 = 1.;
2113 const float t2 = 1.;
2115 const float omegaTau = -10. * bzField * vDrift / std::abs(getEzField(
Side::A));
2116 setOmegaTauT1T2(omegaTau,
t1, t2);
2117 if (mUseInitialSCDensity) {
2118 LOG(warning) <<
"mUseInitialSCDensity" << mUseInitialSCDensity;
2119 calculateDistortionsCorrections(
Side::A);
2120 calculateDistortionsCorrections(
Side::C);
2121 mInitLookUpTables =
true;
2123 auto stop = timer::now();
2124 std::chrono::duration<float>
time = stop -
start;
2125 LOGP(info,
"Total Time Distortions and Corrections for A and C Side: {}",
time.count());
2129template <
typename DataT>
2132 mGlobalDistdR[
side] = distdR;
2133 mGlobalDistdZ[
side] = distdZ;
2134 mGlobalDistdRPhi[
side] = distdRPhi;
2137template <
typename DataT>
2138template <
typename Fields>
2142 "fErOverEz", [&](
double*
x,
double* p) { (
void)p;
return static_cast<double>(formulaStruct.evalFieldR(
static_cast<DataT>(
x[0]), p1r, p1phi) / (formulaStruct.evalFieldZ(
static_cast<DataT>(
x[0]), p1r, p1phi) + ezField)); }, p1z, p2z, 1);
2143 localIntErOverEz =
static_cast<DataT>(fErOverEz.Integral(p1z, p2z));
2146 "fEPhiOverEz", [&](
double*
x,
double* p) { (
void)p;
return static_cast<double>(formulaStruct.evalFieldPhi(
static_cast<DataT>(
x[0]), p1r, p1phi) / (formulaStruct.evalFieldZ(
static_cast<DataT>(
x[0]), p1r, p1phi) + ezField)); }, p1z, p2z, 1);
2147 localIntEPhiOverEz =
static_cast<DataT>(fEphiOverEz.Integral(p1z, p2z));
2150 "fEZOverEz", [&](
double*
x,
double* p) { (
void)p;
return static_cast<double>(formulaStruct.evalFieldZ(
static_cast<DataT>(
x[0]), p1r, p1phi) - ezField); }, p1z, p2z, 1);
2151 localIntDeltaEz = getSign(
side) *
static_cast<DataT>(fEz.Integral(p1z, p2z));
2154template <
typename DataT>
2155template <
typename Fields>
2159 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2160 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2161 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2163 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p1r, p1phi);
2164 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p1r, p1phi);
2165 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p1r, p1phi);
2167 const DataT eZ0 = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2168 const DataT eZ1 = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2170 const DataT deltaX = 0.5 * (p2z - p1z);
2171 localIntErOverEz = deltaX * (fielder0 * eZ0 + fielder1 * eZ1);
2172 localIntEPhiOverEz = deltaX * (fieldephi0 * eZ0 + fieldephi1 * eZ1);
2173 localIntDeltaEz = getSign(
side) * deltaX * (fieldez0 + fieldez1);
2176template <
typename DataT>
2177template <
typename Fields>
2181 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2182 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2183 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2185 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p1r, p1phi);
2186 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p1r, p1phi);
2187 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p1r, p1phi);
2189 const DataT deltaX = p2z - p1z;
2190 const DataT xk2N = (p2z -
static_cast<DataT>(0.5) * deltaX);
2191 const DataT ezField2 = formulaStruct.evalFieldZ(xk2N, p1r, p1phi);
2192 const DataT ezField2Denominator = isCloseToZero(ezField, ezField2) ? 0 : 1. / (ezField + ezField2);
2193 const DataT fieldSum2ErOverEz = formulaStruct.evalFieldR(xk2N, p1r, p1phi) * ezField2Denominator;
2194 const DataT fieldSum2EphiOverEz = formulaStruct.evalFieldPhi(xk2N, p1r, p1phi) * ezField2Denominator;
2196 const DataT eZ0 = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2197 const DataT eZ1 = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2199 const DataT deltaXSimpsonSixth = deltaX / 6.;
2200 localIntErOverEz = deltaXSimpsonSixth * (4. * fieldSum2ErOverEz + fielder0 * eZ0 + fielder1 * eZ1);
2201 localIntEPhiOverEz = deltaXSimpsonSixth * (4. * fieldSum2EphiOverEz + fieldephi0 * eZ0 + fieldephi1 * eZ1);
2202 localIntDeltaEz = getSign(
side) * deltaXSimpsonSixth * (4. * ezField2 + fieldez0 + fieldez1);
2205template <
typename DataT>
2206template <
typename Fields>
2207void SpaceCharge<DataT>::integrateEFieldsSimpsonIterative(
const DataT p1r,
const DataT p2r,
const DataT p1phi,
const DataT p2phi,
const DataT p1z,
const DataT p2z,
DataT& localIntErOverEz,
DataT& localIntEPhiOverEz,
DataT& localIntDeltaEz,
const Fields& formulaStruct,
const DataT ezField,
const Side side)
const
2212 const DataT p2phiSave = regulatePhi(p2phi,
side);
2214 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2215 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2216 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2218 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p2r, p2phiSave);
2219 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p2r, p2phiSave);
2220 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p2r, p2phiSave);
2222 const DataT eZ0Inv = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2223 const DataT eZ1Inv = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2225 const DataT pHalfZ = 0.5 * (p1z + p2z);
2226 const DataT pHalfPhiSave = regulatePhi(0.5 * (p1phi + p2phi),
side);
2227 const DataT pHalfR = 0.5 * (p1r + p2r);
2229 const DataT ezField2 = formulaStruct.evalFieldZ(pHalfZ, pHalfR, pHalfPhiSave);
2230 const DataT eZHalfInv = (isCloseToZero(ezField, ezField2) | isCloseToZero(ezField, fieldez0) | isCloseToZero(ezField, fieldez1)) ? 0 : 1. / (ezField + ezField2);
2231 const DataT fieldSum2ErOverEz = formulaStruct.evalFieldR(pHalfZ, pHalfR, pHalfPhiSave);
2232 const DataT fieldSum2EphiOverEz = formulaStruct.evalFieldPhi(pHalfZ, pHalfR, pHalfPhiSave);
2234 const DataT deltaXSimpsonSixth = (p2z - p1z) / 6;
2235 localIntErOverEz = deltaXSimpsonSixth * (4 * fieldSum2ErOverEz * eZHalfInv + fielder0 * eZ0Inv + fielder1 * eZ1Inv);
2236 localIntEPhiOverEz = deltaXSimpsonSixth * (4 * fieldSum2EphiOverEz * eZHalfInv + fieldephi0 * eZ0Inv + fieldephi1 * eZ1Inv);
2237 localIntDeltaEz = getSign(
side) * deltaXSimpsonSixth * (4 * ezField2 + fieldez0 + fieldez1);
2240template <
typename DataT>
2241std::vector<std::pair<std::vector<o2::math_utils::Point3D<float>>, std::array<DataT, 3>>>
SpaceCharge<DataT>::calculateElectronDriftPath(
const std::vector<GlobalPosition3D>& elePos,
const int nSamplingPoints,
const std::string_view outFile)
const
2243 const unsigned int nElectrons = elePos.size();
2244 std::vector<std::pair<std::vector<o2::math_utils::Point3D<float>>, std::array<DataT, 3>>> electronTracks(nElectrons);
2246 for (
unsigned int i = 0;
i < nElectrons; ++
i) {
2247 electronTracks[
i].first.reserve(nSamplingPoints + 1);
2250 for (
unsigned int i = 0;
i < nElectrons; ++
i) {
2251 const DataT z0 = elePos[
i].Z();
2252 const DataT r0 = elePos[
i].Rho();
2253 const DataT phi0 = elePos[
i].Phi();
2255 if (!mElectricFieldEr[
side].getNDataPoints()) {
2256 LOGP(warning,
"E-Fields are not set! Calculation of drift path is not possible");
2260 const DataT stepSize = getZMax(
side) / nSamplingPoints;
2263 DataT dPhiDist = 0.0;
2267 const DataT z0Tmp = z0 + dzDist + iter * stepSize;
2268 const DataT z1Tmp = regulateZ(z0Tmp + stepSize,
side);
2269 const DataT radius = r0 + drDist;
2272 if (radius <= getRMin(
side) || radius >= getRMax(
side) || getSide(z0Tmp) !=
side) {
2276 const DataT phi = regulatePhi(phi0 + dPhiDist,
side);
2277 electronTracks[
i].first.emplace_back(
GlobalPosition3D(radius * std::cos(phi), radius * std::sin(phi), z0Tmp));
2284 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, numEFields);
2293 const bool checkReached =
side ==
Side::A ? z1Tmp >= getZMax(
side) : z1Tmp <= getZMax(
side);
2298 const DataT endPoint = z1Tmp + ddZ;
2299 const DataT deltaZ = getZMax(
side) - endPoint;
2300 const DataT diff = endPoint - z0Tmp;
2301 const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0;
2302 drDist += ddR * fac;
2303 dPhiDist += ddPhi * fac;
2304 dzDist += ddZ * fac;
2305 const DataT z1TmpEnd = regulateZ(z0Tmp + stepSize,
side);
2306 const DataT radiusEnd = regulateR(r0 + drDist,
side);
2307 const DataT phiEnd = regulatePhi(phi0 + dPhiDist,
side);
2308 electronTracks[
i].first.emplace_back(
GlobalPosition3D(radiusEnd * std::cos(phiEnd), radiusEnd * std::sin(phiEnd), z1TmpEnd));
2313 electronTracks[
i].second = std::array<DataT, 3>{drDist, dPhiDist * r0, dzDist};
2315 if (!outFile.empty()) {
2316 dumpElectronTracksToTree(electronTracks, nSamplingPoints, outFile.data());
2318 return electronTracks;
2321template <
typename DataT>
2325 pcstream.GetFile()->cd();
2330 for (
int i = 0;
i < electronTracks.size(); ++
i) {
2331 auto electronPath = electronTracks[
i].first;
2332 const int nPoints = electronPath.size();
2333 if (electronPath.empty()) {
2334 LOGP(warning,
"Track is empty. Continue to next track.");
2337 std::vector<float> relDriftVel;
2338 relDriftVel.reserve(nPoints);
2340 for (
int iPoint = 0; iPoint < (nPoints - 2); ++iPoint) {
2341 const DataT relDriftVelTmp = (electronPath[iPoint + 1].Z() - electronPath[iPoint].Z()) / getZMax(getSide(electronPath[iPoint].Z())) * nSamplingPoints;
2342 relDriftVel.emplace_back(std::abs(relDriftVelTmp));
2346 relDriftVel.emplace_back(relDriftVel.back());
2347 relDriftVel.emplace_back(relDriftVel.back());
2349 DataT distR = electronTracks[
i].second[0];
2350 DataT distRPhi = electronTracks[
i].second[1];
2351 DataT distZ = electronTracks[
i].second[2];
2353 DataT driftTime = std::abs(getZMax(getSide(electronPath.front().Z())) - (distZ + electronPath.front().Z())) / gasParam.DriftV;
2354 DataT timeBin = driftTime / eleParam.ZbinWidth;
2357 <<
"electronPath=" << electronPath
2358 <<
"relDriftVel.=" << relDriftVel
2359 <<
"distR=" << distR
2360 <<
"distRPhi=" << distRPhi
2361 <<
"distZ=" << distZ
2362 <<
"driftTime=" << driftTime
2363 <<
"timeBin=" << timeBin
2369template <
typename DataT>
2373 TFile fInp(inpFile,
"READ");
2374 TTree*
tree = (TTree*)fInp.Get(
"drift");
2375 std::vector<o2::tpc::GlobalPosition3D>* electronPathTree =
new std::vector<o2::tpc::GlobalPosition3D>;
2376 tree->SetBranchAddress(
"electronPath", &electronPathTree);
2378 std::vector<std::vector<o2::tpc::GlobalPosition3D>> electronPaths;
2379 std::vector<o2::tpc::GlobalPosition3D> elePosTmp;
2380 const int entries =
tree->GetEntriesFast();
2381 for (
int i = 0;
i < entries; ++
i) {
2383 electronPaths.emplace_back(*electronPathTree);
2385 delete electronPathTree;
2388 TCanvas can(
"canvas",
"canvas", 1000, 600);
2389 can.SetTopMargin(0.04f);
2390 can.SetRightMargin(0.04f);
2391 can.SetBottomMargin(0.12f);
2392 can.SetLeftMargin(0.11f);
2394 const int nElectrons = electronPaths.size();
2395 std::vector<int> indexStartEle(nElectrons);
2396 std::vector<int> countReadoutReached(nElectrons);
2399 const std::vector<int> colorsPalette{kViolet + 2, kViolet + 1, kViolet, kViolet - 1, kGreen + 3, kGreen + 2, kGreen + 1, kOrange - 1, kOrange, kOrange + 1, kOrange + 2, kRed - 1, kRed, kRed + 1, kRed + 2, kBlue - 1, kBlue, kBlue + 1, kBlue + 2};
2402 unsigned int maxPoints = 0;
2403 std::vector<TGraph> gr(nElectrons);
2404 for (
int i = 0;
i < nElectrons; ++
i) {
2405 gr[
i].SetMarkerColor(colorsPalette[
i % colorsPalette.size()]);
2407 if (electronPaths[
i].
size() > maxPoints) {
2408 maxPoints = electronPaths[
i].size();
2412 const DataT pointsPerIteration = maxPoints /
static_cast<DataT>(maxsamplingpoints);
2413 std::vector<DataT> zRemainder(nElectrons);
2416 for (
auto& graph : gr) {
2420 for (
int iEle = 0; iEle < nElectrons; ++iEle) {
2421 const int nSamplingPoints = electronPaths[iEle].size();
2422 const int nPoints = std::round(pointsPerIteration + zRemainder[iEle]);
2423 zRemainder[iEle] = pointsPerIteration - nPoints;
2424 const auto& electronPath = electronPaths[iEle];
2426 if (nPoints == 0 && countReadoutReached[iEle] == 0) {
2427 const int indexPoint = indexStartEle[iEle];
2428 const DataT radius = electronPath[indexPoint].Rho();
2429 const DataT z = electronPath[indexPoint].Z();
2430 const DataT phi = electronPath[indexPoint].Phi();
2431 type == 0 ? gr[iEle].AddPoint(
z, radius) : gr[iEle].AddPoint(phi, radius);
2434 for (
int iPoint = 0; iPoint < nPoints; ++iPoint) {
2435 const int indexPoint = indexStartEle[iEle];
2436 if (indexPoint >= nSamplingPoints) {
2437 countReadoutReached[iEle] = 1;
2441 const DataT radius = electronPath[indexPoint].Rho();
2442 const DataT z = electronPath[indexPoint].Z();
2443 const DataT phi = electronPath[indexPoint].Phi();
2444 if (iPoint == nPoints / 2) {
2445 type == 0 ? gr[iEle].AddPoint(
z, radius) : gr[iEle].AddPoint(phi, radius);
2447 ++indexStartEle[iEle];
2451 for (
auto& graph : gr) {
2452 if (graph.GetN() > 0) {
2453 graph.Draw(
"P SAME");
2456 can.Print(Form(
"%s.gif+%i", outName, gifSpeed));
2458 const int sumReadoutReached = std::accumulate(countReadoutReached.begin(), countReadoutReached.end(), 0);
2459 if (sumReadoutReached == nElectrons) {
2464 can.Print(Form(
"%s.gif++", outName));
2469template <
typename DataT>
2472 const auto deltaPhi = histoIonsPhiRZ.GetXaxis()->GetBinWidth(1);
2473 const auto deltaZ = histoIonsPhiRZ.GetZaxis()->GetBinWidth(1);
2475 for (
int ir = 1;
ir <= histoIonsPhiRZ.GetNbinsY(); ++
ir) {
2476 const auto r0 = histoIonsPhiRZ.GetYaxis()->GetBinLowEdge(
ir);
2477 const auto r1 = histoIonsPhiRZ.GetYaxis()->GetBinUpEdge(
ir);
2478 const auto norm = fac * (r1 * r1 - r0 * r0);
2479 for (
int iphi = 1; iphi <= histoIonsPhiRZ.GetNbinsX(); ++iphi) {
2480 for (
int iz = 1; iz <= histoIonsPhiRZ.GetNbinsZ(); ++iz) {
2481 const auto charge = histoIonsPhiRZ.GetBinContent(iphi,
ir, iz);
2482 histoIonsPhiRZ.SetBinContent(iphi,
ir, iz,
charge / norm);
2488template <
typename DataT>
2491 if (!mAnaDistCorr.isValid()) {
2492 LOGP(info,
"============== analytical functions are not set! returning ==============");
2495 bool isOK = outf.WriteObject(&mAnaDistCorr,
"analyticalDistCorr");
2499template <
typename DataT>
2502 TFile fIn(inpf.data(),
"READ");
2503 const bool containsFormulas = fIn.GetListOfKeys()->Contains(
"analyticalDistCorr");
2504 if (!containsFormulas) {
2505 LOGP(info,
"============== analytical functions are not stored! returning ==============");
2508 LOGP(info,
"Using analytical corrections and distortions");
2509 setUseAnalyticalDistCorr(
true);
2511 mAnaDistCorr = *form;
2515template <
typename DataT>
2519 ddR = mC0 * localIntErOverEz + mC1 * localIntEPhiOverEz;
2520 ddPhi = (mC0 * localIntEPhiOverEz - mC1 * localIntErOverEz) / radius;
2524template <
typename DataT>
2528 ddR = mC2 * localIntBrOverBz - mC1 * localIntBPhiOverBz;
2529 ddPhi = (mC2 * localIntBPhiOverBz + mC1 * localIntBrOverBz) / radius;
2532template <
typename DataT>
2535 const std::unordered_map<int, std::pair<int, int>> field_to_current = {{2, {12000, 6000}},
2537 {-2, {-12000, -6000}},
2538 {-5, {-30000, -6000}},
2540 auto currents_iter = field_to_current.find(field);
2541 if (currents_iter == field_to_current.end()) {
2542 LOG(error) <<
" Could not lookup currents for fieldvalue " << field;
2545 mBField.setBField(field);
2549 setBFields(magField);
2552template <
typename DataT>
2557 float vDrift = gasParam.DriftV;
2558 const float omegaTau = -10. * bzField * vDrift / std::abs(getEzField(
Side::A));
2559 LOGP(detail,
"Setting omegaTau to {} for {}kG", omegaTau, bzField);
2560 const float t1 = 1.;
2561 const float t2 = 1.;
2562 setOmegaTauT1T2(omegaTau,
t1, t2);
2565template <
typename DataT>
2566template <
typename Fields>
2571 DataT localIntErOverEz = 0;
2572 DataT localIntEPhiOverEz = 0;
2573 DataT localIntDeltaEz = 0;
2575 DataT localIntBrOverBz = 0;
2576 DataT localIntBPhiOverBz = 0;
2577 DataT localIntDeltaBz = 0;
2582 switch (sNumericalIntegrationStrategy) {
2583 case IntegrationStrategy::SimpsonIterative:
2584 for (
int i = 0;
i < sSimpsonNIteratives; ++
i) {
2585 const DataT tmpZ = localDistCorr ? (p2z + ddZ) : regulateZ(p2z + ddZ, formulaStruct.getSide());
2586 if (mSimEDistortions) {
2587 integrateEFieldsSimpsonIterative(p1r, p1r + ddR + ddRExB, p1phi, p1phi + ddPhi + ddPhiExB, p1z, tmpZ, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2588 langevinCylindricalE(ddR, ddPhi, ddZ, (p1r + 0.5 * (ddR + ddRExB)), localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2590 if (mSimExBMisalignment) {
2591 integrateEFieldsSimpsonIterative(p1r, p1r + ddR + ddRExB, p1phi, p1phi + ddPhi + ddPhiExB, p1z, tmpZ, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2592 langevinCylindricalB(ddRExB, ddPhiExB, (p1r + 0.5 * (ddR + ddRExB)), localIntBrOverBz, localIntBPhiOverBz);
2596 case IntegrationStrategy::Simpson:
2597 if (mSimEDistortions) {
2598 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2599 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2601 if (mSimExBMisalignment) {
2602 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2603 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2606 case IntegrationStrategy::Trapezoidal:
2607 if (mSimEDistortions) {
2608 integrateEFieldsTrapezoidal(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2609 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2611 if (mSimExBMisalignment) {
2612 integrateEFieldsTrapezoidal(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2613 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2616 case IntegrationStrategy::Root:
2617 if (mSimEDistortions) {
2618 integrateEFieldsRoot(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2619 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2621 if (mSimExBMisalignment) {
2622 integrateEFieldsRoot(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2623 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2627 if (mSimEDistortions) {
2628 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2629 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2631 if (mSimExBMisalignment) {
2632 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2633 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2638 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_calcDistCorr",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_calcDistCorr").data()
2639 <<
"p1r=" << (*
const_cast<DataT*
>(&p1r))
2640 <<
"p1phi=" << (*
const_cast<DataT*
>(&p1phi))
2641 <<
"p1z=" << (*
const_cast<DataT*
>(&p1z))
2642 <<
"p2z=" << (*
const_cast<DataT*
>(&p2z))
2643 <<
"localIntErOverEz=" << localIntErOverEz
2644 <<
"localIntEPhiOverEz=" << localIntEPhiOverEz
2645 <<
"localIntDeltaEz=" << localIntDeltaEz
2647 <<
"ddPhi=" << ddPhi
2649 <<
"localIntBrOverBz=" << localIntBrOverBz
2650 <<
"localIntBPhiOverBz=" << localIntBPhiOverBz
2651 <<
"localIntDeltaBz=" << localIntDeltaBz
2652 <<
"ddRExB=" << ddRExB
2653 <<
"ddPhiExB=" << ddPhiExB
2665template <
typename DataT>
2666template <
typename DataTIn>
2669 initContainer(mGlobalDistdR[
side],
false);
2670 initContainer(mGlobalDistdZ[
side],
false);
2671 initContainer(mGlobalDistdRPhi[
side],
false);
2672 const std::string sideName = getSideName(
side);
2673 mGlobalDistdR[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distR_side{}", sideName).
data());
2674 mGlobalDistdZ[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distZ_side{}", sideName).
data());
2675 mGlobalDistdRPhi[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distRphi_side{}", sideName).
data());
2680template <
typename DataT>
2681template <
typename DataTIn>
2684 initContainer(mGlobalCorrdR[
side],
false);
2685 initContainer(mGlobalCorrdZ[
side],
false);
2686 initContainer(mGlobalCorrdRPhi[
side],
false);
2687 const std::string sideName = getSideName(
side);
2688 mGlobalCorrdR[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrR_side{}", sideName).
data());
2689 mGlobalCorrdZ[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrZ_side{}", sideName).
data());
2690 mGlobalCorrdRPhi[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrRPhi_side{}", sideName).
data());
2702template <
typename DataT>
2705 unsigned short nr, nz, nphi;
2706 if (!DataContainer::getVertices(
tree, file, nr, nz, nphi)) {
2711 if ((mParamGrid.NRVertices != nr) || (mParamGrid.NZVertices != nz) || (mParamGrid.NPhiVertices != nphi)) {
2712 LOGP(info,
"Different number of vertices found in input file. Initializing new space charge object with nR {} nZ {} nPhi {} vertices", nr, nz, nphi);
2717 *
this = std::move(scTmp);
2723template <
typename DataT>
2726 if (!mGlobalCorrdR[
side].getNDataPoints()) {
2727 LOGP(info,
"============== global corrections are not set! returning ==============");
2730 const std::string sideName = getSideName(
side);
2731 const int er = mGlobalCorrdR[
side].template writeToFile<float>(outf, fmt::format(
"corrR_side{}", sideName).
data());
2732 const int ez = mGlobalCorrdZ[
side].template writeToFile<float>(outf, fmt::format(
"corrZ_side{}", sideName).
data());
2733 const int ephi = mGlobalCorrdRPhi[
side].template writeToFile<float>(outf, fmt::format(
"corrRPhi_side{}", sideName).
data());
2734 return er + ez + ephi;
2741template <
typename DataT>
2744 LOGP(warning,
"Use this feature only if you know what you are doing!");
2746 RegularGrid gridTmp[FNSIDES]{{GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(
Side::A) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) /
SECTORSPERSIDE * nSectors, mParamGrid},
2747 {GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(
Side::C) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) /
SECTORSPERSIDE * nSectors, mParamGrid}};
2748 mGrid3D[0] = gridTmp[0];
2749 mGrid3D[1] = gridTmp[1];
2752template <
typename DataT>
2760template <
typename DataT>
2763 if (!
data.getNDataPoints()) {
2764 data.setGrid(getNZVertices(), getNRVertices(), getNPhiVertices(), initMem);
2768template <
typename DataT>
2771 const DataT wt0 = t2 * omegaTau;
2772 const DataT wt02 = wt0 * wt0;
2773 mC0 = 1 / (1 + wt02);
2774 const DataT wt1 =
t1 * omegaTau;
2775 mC1 = wt1 / (1 + wt1 * wt1);
2776 mC2 = wt02 / (1 + wt02);
2779template <
typename DataT>
2784 LOGP(warning,
"Space charge objects have different grid definition");
2792template <
typename DataT>
2797 LOGP(warning,
"Space charge objects have different grid definition");
2801 mGlobalCorrdR[
side] += otherSC.mGlobalCorrdR[
side];
2802 mGlobalCorrdZ[
side] += otherSC.mGlobalCorrdZ[
side];
2803 mGlobalCorrdRPhi[
side] += otherSC.mGlobalCorrdRPhi[
side];
2806template <
typename DataT>
2809 TFile fInp(file,
"READ");
2810 TH3F* hSCA = (TH3F*)fInp.Get(nameA);
2811 TH3F* hSCC = (TH3F*)fInp.Get(nameC);
2813 LOGP(error,
"Histogram {} not found", nameA);
2816 LOGP(error,
"Histogram {} not found", nameC);
2818 fillChargeDensityFromHisto(*hSCA, *hSCC);
2821template <
typename DataT>
2824 const int nPhiBinsTmp = hisSCDensity3D_A.GetXaxis()->GetNbins();
2825 const int nRBinsTmp = hisSCDensity3D_A.GetYaxis()->GetNbins();
2826 const int nZBins = hisSCDensity3D_A.GetZaxis()->GetNbins();
2827 const auto phiLow = hisSCDensity3D_A.GetXaxis()->GetBinLowEdge(1);
2828 const auto phiUp = hisSCDensity3D_A.GetXaxis()->GetBinUpEdge(nPhiBinsTmp);
2829 const auto rLow = hisSCDensity3D_A.GetYaxis()->GetBinLowEdge(1);
2830 const auto rUp = hisSCDensity3D_A.GetYaxis()->GetBinUpEdge(nRBinsTmp);
2831 const auto zUp = hisSCDensity3D_A.GetZaxis()->GetBinUpEdge(
nZBins);
2833 TH3F hisSCMerged(
"hisMerged",
"hisMerged", nPhiBinsTmp, phiLow, phiUp, nRBinsTmp, rLow, rUp, 2 *
nZBins, -zUp, zUp);
2835 for (
int iside = 0; iside < FNSIDES; ++iside) {
2836 const auto& hSC = (iside == 0) ? hisSCDensity3D_A : hisSCDensity3D_C;
2837#pragma omp parallel for num_threads(sNThreads)
2838 for (
int iz = 1; iz <=
nZBins; ++iz) {
2839 const int izTmp = (iside == 0) ? (
nZBins + iz) : iz;
2840 for (
int ir = 1;
ir <= nRBinsTmp; ++
ir) {
2841 for (
int iphi = 1; iphi <= nPhiBinsTmp; ++iphi) {
2842 hisSCMerged.SetBinContent(iphi,
ir, izTmp, hSC.GetBinContent(iphi,
ir, iz));
2847 fillChargeDensityFromHisto(hisSCMerged);
2850template <
typename DataT>
2854 const int nOrbits = 12;
2860 const int nIDCSlices = idcZero.size();
2863 const float idcsPerMS = nTimeStampsPerIDCInterval / idcIntegrationTimeMS;
2866 const float lengthZSliceMS = ionDriftTimeMS / nIDCSlices;
2869 const float scaleToIonDrift = lengthZSliceMS * idcsPerMS;
2875 const float conversionFactor = scaleToIonDrift / conversionADCToEle;
2876 LOGP(info,
"Converting IDCs to space-charge density with conversion factor of {}", conversionFactor);
2878 for (
auto& calIDC : idcZero) {
2879 if (normToPadArea) {
2885 float idcTmp = calIDC.getValue(sector, globalPad);
2886 calIDC.setValue(sector, globalPad, conversionFactor * idcTmp /
Mapper::INVPADAREA[region]);
2892 calIDC *= conversionFactor;
2900template <
typename DataT>
2903 convertIDCsToCharge(idcZero, mapIBF, ionDriftTimeMS, normToPadArea);
2904 fillChargeFromCalDet(idcZero);
2907template <
typename DataT>
2912 const int iside =
static_cast<int>(
side);
2913 initContainer(mPotential[iside],
true);
2914 const int phiVerticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
2915 int phiVerticesEnd = phiVerticesPerSector;
2917 if (misalignmentType == MisalignmentType::RodShift) {
2918 const float rodDiameter = 1;
2919 const float rodRadius = rodDiameter / 2;
2921 int nPhiVerticesPerRod =
static_cast<int>(rodRadius * mParamGrid.NPhiVertices / (
TWOPI * radiusTmp) + 0.5);
2922 if (nPhiVerticesPerRod == 0) {
2923 nPhiVerticesPerRod = 1;
2925 phiVerticesEnd = nPhiVerticesPerRod;
2928 const int phiStart = sector * phiVerticesPerSector;
2929 const int phiEnd = phiStart + phiVerticesEnd;
2930 const int nRVertex = (fcType == FCType::IFC) ? 0 : (mParamGrid.NRVertices - 1);
2931 for (
size_t iPhi = phiStart; iPhi < phiEnd; ++iPhi) {
2932 const int iPhiSector = iPhi % phiVerticesPerSector;
2934 float potentialSector = 0;
2935 float potentialLastSector = 0;
2936 if ((misalignmentType == MisalignmentType::ShiftedClip) || (misalignmentType == MisalignmentType::RodShift)) {
2937 const float potentialShiftedClips = deltaPot - iPhiSector * deltaPot / phiVerticesEnd;
2938 potentialSector = potentialShiftedClips;
2939 potentialLastSector = potentialShiftedClips;
2940 }
else if (misalignmentType == MisalignmentType::RotatedClip) {
2942 if (iPhiSector == 0) {
2943 potentialSector = 0;
2944 potentialLastSector = 0;
2946 const float potentialRotatedClip = -deltaPot + (iPhiSector - 1) * deltaPot / (phiVerticesPerSector - 2);
2947 potentialSector = potentialRotatedClip;
2948 potentialLastSector = -potentialRotatedClip;
2952 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
2953 mPotential[iside](iZ, nRVertex, iPhi) += potentialSector;
2954 if (iPhiSector > 0) {
2955 const int iPhiMirror = ((phiStart - iPhiSector) + mParamGrid.NPhiVertices) % mParamGrid.NPhiVertices;
2956 mPotential[iside](iZ, nRVertex, iPhiMirror) += potentialLastSector;
2962template <
typename DataT>
2965 if (
other.mPotential[
side].getData().empty()) {
2966 LOGP(info,
"Other space-charge object is empty!");
2970 if ((mParamGrid.NRVertices !=
other.mParamGrid.NRVertices) || (mParamGrid.NZVertices !=
other.mParamGrid.NZVertices) || (mParamGrid.NPhiVertices !=
other.mParamGrid.NPhiVertices)) {
2971 LOGP(info,
"Different number of vertices found in input file. Initializing new space charge object with nR {} nZ {} nPhi {} vertices",
other.mParamGrid.NRVertices,
other.mParamGrid.NZVertices,
other.mParamGrid.NPhiVertices);
2976 *
this = std::move(scTmp);
2979 initContainer(mPotential[
side],
true);
2981 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
2982 for (
size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) {
2983 const size_t iRFirst = 0;
2984 mPotential[
side](iZ, iRFirst, iPhi) += scaling *
other.mPotential[
side](iZ, iRFirst, iPhi);
2986 const size_t iRLast = mParamGrid.NRVertices - 1;
2987 mPotential[
side](iZ, iRLast, iPhi) += scaling *
other.mPotential[
side](iZ, iRLast, iPhi);
2991 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
2992 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
2993 const size_t iZFirst = 0;
2994 mPotential[
side](iZFirst, iR, iPhi) += scaling *
other.mPotential[
side](iZFirst, iR, iPhi);
2996 const size_t iZLast = mParamGrid.NZVertices - 1;
2997 mPotential[
side](iZLast, iR, iPhi) += scaling *
other.mPotential[
side](iZLast, iR, iPhi);
3002template <
typename DataT>
3005 const float zMaxAbs = std::abs(
zMax);
3006 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3007 for (
size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) {
3010 const size_t iRFirst = 0;
3011 mPotential[
side](iZ, iRFirst, iPhi) = 0;
3013 const size_t iRLast = mParamGrid.NRVertices - 1;
3014 mPotential[
side](iZ, iRLast, iPhi) = 0;
3019 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3020 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3021 const size_t iZFirst = 0;
3023 if ((zFirst <
zMin) || (zFirst >
zMax)) {
3024 mPotential[
side](iZFirst, iR, iPhi) = 0;
3027 const size_t iZLast = mParamGrid.NZVertices - 1;
3029 if ((zLast <
zMin) || (zLast >
zMax)) {
3030 mPotential[
side](iZLast, iR, iPhi) = 0;
3036template <
typename DataT>
3039 std::function<
DataT(
DataT)> chargeUpIFCLinear = [zStart,
type, offs, deltaPot, zMaxDeltaPot](
const DataT z) {
3040 const float absZ = std::abs(
z);
3041 const float absZMaxDeltaPot = std::abs(zMaxDeltaPot);
3042 if ((absZ <= absZMaxDeltaPot) && (absZ >= zStart)) {
3045 const float offsZ = 1;
3046 const float zMaxDeltaPotTmp = zMaxDeltaPot - zStart + offsZ;
3047 const float p1 = deltaPot / (1 / offsZ - 1 / zMaxDeltaPotTmp);
3048 const float p2 = -
p1 / zMaxDeltaPotTmp;
3049 const float absZShifted = zMaxDeltaPotTmp - (absZ - zStart);
3052 }
else if (
type == 0 ||
type == 4) {
3054 return static_cast<DataT>(deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + offs);
3055 }
else if (
type == 2) {
3057 return DataT(deltaPot);
3058 }
else if (
type == 3) {
3060 return static_cast<DataT>(-deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + deltaPot);
3064 }
else if (
type == 4) {
3071 setPotentialBoundaryInnerRadius(chargeUpIFCLinear,
side);
3074template <
typename DataT>
3078 const float absZ = std::abs(
z);
3079 const float absZMaxDeltaPot = std::abs(zMaxDeltaPot);
3081 bool check = (absZ >= absZMaxDeltaPot);
3083 check = (absZ >= absZMaxDeltaPot);
3086 if (
check && (absZ <= zEnd)) {
3089 const float p1 = (deltaPot - offs) / (1 / zMaxDeltaPot - 1 / zEnd);
3090 const float p2 = offs -
p1 / zEnd;
3093 }
else if (
type == 2) {
3095 const float offsZ = 1 + offs;
3096 const float zEndTmp = zEnd - zMaxDeltaPot + offsZ;
3097 const float p1 = deltaPot / (1 / offsZ - 1 / zEndTmp);
3098 const float p2 = -
p1 / zEndTmp;
3099 const float absZShifted = absZ - zMaxDeltaPot + offsZ;
3102 }
else if (
type == 0 ||
type == 3) {
3104 const float zPos = absZ - zEnd;
3105 return static_cast<DataT>(deltaPot / (absZMaxDeltaPot - zEnd) * zPos + offs);
3109 }
else if (
type == 3) {
3115 setPotentialBoundaryInnerRadius(chargeUpIFCLinear,
side);
3118template <
typename DataT>
3121 setGlobalDistCorr(Type::Corrections, gCorr,
side);
3124template <
typename DataT>
3127 setGlobalDistCorr(Type::Distortions, gDist,
side);
3130template <
typename DataT>
3133 if (
type == Type::Distortions) {
3134 initContainer(mGlobalDistdR[
side],
true);
3135 initContainer(mGlobalDistdZ[
side],
true);
3136 initContainer(mGlobalDistdRPhi[
side],
true);
3138 initContainer(mGlobalCorrdR[
side],
true);
3139 initContainer(mGlobalCorrdZ[
side],
true);
3140 initContainer(mGlobalCorrdRPhi[
side],
true);
3143#pragma omp parallel for num_threads(sNThreads)
3144 for (
unsigned int iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3147 phi = o2::math_utils::detail::toPMPi(phi);
3149 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3151 const DataT x = getXFromPolar(radius, phi);
3152 const DataT y = getYFromPolar(radius, phi);
3154 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3161 gFunc(sector,
x,
y,
z, gCx, gCy, gCz);
3162 const DataT gCxCorr =
x + gCx;
3163 const DataT gCyCorr =
y + gCy;
3166 const DataT corrR = getRadiusFromCartesian(gCxCorr, gCyCorr) - radius;
3167 DataT phiDiff = getPhiFromCartesian(gCxCorr, gCyCorr) - phi;
3168 phiDiff = o2::math_utils::detail::toPMPi(phiDiff);
3169 const DataT corrRPhi = phiDiff * radius;
3172 if (
type == Type::Distortions) {
3173 mGlobalDistdR[
side](iZ, iR, iPhi) = corrR;
3174 mGlobalDistdZ[
side](iZ, iR, iPhi) = gCz;
3175 mGlobalDistdRPhi[
side](iZ, iR, iPhi) = corrRPhi;
3177 mGlobalCorrdR[
side](iZ, iR, iPhi) = corrR;
3178 mGlobalCorrdZ[
side](iZ, iR, iPhi) = gCz;
3179 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = corrRPhi;
3186template <
typename DataT>
3189 setROCMisalignment(
type, 2, sector, potential, potential);
3192template <
typename DataT>
3195 setROCMisalignment(
type, 0, sector, potentialMin, potentialMax);
3198template <
typename DataT>
3201 setROCMisalignment(
type, 1, sector, potentialMin, potentialMax);
3204template <
typename DataT>
3207 initContainer(mPotential[
Sector(sector).
side()],
true);
3208 const auto indPhiTopIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
false,
Side::A,
false,
true);
3210 const auto rotationPoints = [](
const int regStart,
const int regEnd,
int misalignmentType,
const float potMax,
const float potMin) {
3211 if (misalignmentType == 0) {
3213 const float radStart = mapper.getPadRegionInfo(regStart).getRadiusFirstRow();
3214 const auto& padReg = mapper.getPadRegionInfo(regEnd);
3215 const float radEnd = padReg.getRadiusFirstRow() + padReg.getPadHeight() * padReg.getNumberOfPadRows() - radStart;
3216 const float rotationPoint = radStart + radEnd / 2;
3217 const float slope = (potMax - potMin) / radEnd;
3218 return std::pair<float, float>{rotationPoint,
slope};
3219 }
else if (misalignmentType == 1) {
3220 return std::pair<float, float>{0, (potMax - potMin) / 100};
3222 return std::pair<float, float>{0, (potMax + potMin) / 2};
3226 if (stackType == 0) {
3227 const auto deltaPotPar = rotationPoints(0, 3, misalignmentType, potMax, potMin);
3228 const auto indPhiBottomIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
true,
Side::A,
false,
true);
3229 fillROCMisalignment(indPhiTopIROC, indPhiBottomIROC, sector, misalignmentType, deltaPotPar);
3230 }
else if (stackType == 1) {
3231 const auto deltaPotPar = rotationPoints(4, 9, misalignmentType, potMax, potMin);
3232 const auto indPhiTopOROC3 = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::OROC3gem,
false,
Side::A,
false,
true);
3233 fillROCMisalignment(indPhiTopOROC3, indPhiTopIROC, sector, misalignmentType, deltaPotPar);
3234 }
else if (stackType == 2) {
3235 const auto deltaPotPar = rotationPoints(0, 9, misalignmentType, potMax, potMin);
3236 const auto indPhiBottomIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
true,
Side::A,
false,
true);
3237 const auto indPhiTopOROC3 = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::OROC3gem,
false,
Side::A,
false,
true);
3238 fillROCMisalignment(indPhiTopIROC, indPhiBottomIROC, sector, misalignmentType, deltaPotPar);
3239 fillROCMisalignment(indPhiTopOROC3, indPhiTopIROC, sector, misalignmentType, deltaPotPar);
3243template <
typename DataT>
3244void SpaceCharge<DataT>::fillROCMisalignment(
const std::vector<std::pair<size_t, float>>& indicesTop,
const std::vector<std::pair<size_t, float>>& indicesBottom,
int sector,
int misalignmentType,
const std::pair<float, float>& deltaPotPar)
3246 for (
const auto& indexw : indicesTop) {
3247 const int index = indexw.first;
3253 if ((sector != -1) && (sectorTmp != sector)) {
3256 const Sector sec(sectorTmp);
3258 for (
size_t iR = iRStart; iR > 0; --iR) {
3259 const size_t currInd = (iZ + getNZVertices() * (iR + iPhi * getNRVertices()));
3260 const bool foundVertexBottom = std::binary_search(indicesBottom.begin(), indicesBottom.end(), std::make_pair(currInd, 0.0f), [](
const auto&
a,
const auto&
b) { return (a.first < b.first); });
3262 if (foundVertexBottom) {
3267 const float rPos =
getRVertex(iR, sec.side());
3269 const float zPos =
getZVertex(iZ, sec.side());
3270 const float x = getXFromPolar(rPos, phiPos);
3271 const float y = getYFromPolar(rPos, phiPos);
3275 if (misalignmentType == 0) {
3276 deltaPot = (lPos.X() - deltaPotPar.first) * deltaPotPar.second;
3277 }
else if (misalignmentType == 1) {
3278 deltaPot = lPos.Y() * deltaPotPar.second;
3280 deltaPot = deltaPotPar.second;
3282 mPotential[sec.side()](iZ, iR, iPhi) += deltaPot;
3287template <
typename DataT>
3290 mGlobalCorrdR[
side] -= otherSC.mGlobalCorrdR[
side];
3291 mGlobalCorrdZ[
side] -= otherSC.mGlobalCorrdZ[
side];
3292 mGlobalCorrdRPhi[
side] -= otherSC.mGlobalCorrdRPhi[
side];
3295template <
typename DataT>
3298 mGlobalDistdR[
side] -= otherSC.mGlobalDistdR[
side];
3299 mGlobalDistdZ[
side] -= otherSC.mGlobalDistdZ[
side];
3300 mGlobalDistdRPhi[
side] -= otherSC.mGlobalDistdRPhi[
side];
3303template <
typename DataT>
3308 mGlobalCorrdRPhi[
side] *=
val;
3311template <
typename DataT>
3314 initContainer(mDensity[
side],
true);
3315 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3316 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3317 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3318 for (
unsigned int iPhi = 0; iPhi <= (verticesPerSector / 2); ++iPhi) {
3319 float meanDensity = 0;
3320 for (
int iter = 0; iter < 2; ++iter) {
3322 const int iPhiTmpA = iPhi + sec * verticesPerSector;
3323 const int iPhiTmpB = ((sec + 1) * verticesPerSector - iPhi) % mParamGrid.NPhiVertices;
3325 meanDensity += mDensity[
side](iZ, iR, iPhiTmpA);
3326 meanDensity += mDensity[
side](iZ, iR, iPhiTmpB);
3329 mDensity[
side](iZ, iR, iPhiTmpA) = densMean;
3330 mDensity[
side](iZ, iR, iPhiTmpB) = densMean;
3339template <
typename DataT>
3343 initContainer(mDensity[
side],
true);
3344 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3346 const int iPhiFirst = sectorInSide * verticesPerSector;
3347 const int iPhiLast = iPhiFirst + verticesPerSector;
3348 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3349 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3350 for (
unsigned int iPhi = iPhiFirst; iPhi < iPhiLast; ++iPhi) {
3351 mDensity[
side](iZ, iR, iPhi) *= scalingFactor;
3357template <
typename DataT>
3361 initContainer(mDensity[
side],
true);
3362 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3364 const int iPhiFirst = sectorInSide * verticesPerSector;
3365 const int iPhiLast = iPhiFirst + verticesPerSector;
3366 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3368 for (
unsigned int iPhi = iPhiFirst; iPhi < iPhiLast; ++iPhi) {
3374 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3375 mDensity[
side](iZ, iR, iPhi) *= scalingFactor;
3382template <
typename DataT>
3385 mGrid3D[
Side::A] =
RegularGrid(GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(
Side::A) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices), mParamGrid);
3386 mGrid3D[
Side::C] =
RegularGrid(GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(
Side::C) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices), mParamGrid);
3389template <
typename DataT>
3393 std::vector<float> dRphi;
3394 std::vector<float>
r;
3395 dRphi.reserve(nPoints);
3397 for (
int i = 0;
i < nPoints; ++
i) {
3398 float radius = (rStart > 0) ? (rStart +
i) : (rmin +
i);
3399 float z = tgl * radius;
3404 dRphi.emplace_back(distRPhi);
3405 r.emplace_back(radius);
3408 TF1 fPol(
"pol2",
"pol2", rmin,
r.back());
3409 fPol.SetParameter(0, 0);
3410 fPol.SetParameter(1, 0);
3411 fPol.SetParameter(2, 0);
3412 TGraph gr(
r.size(),
r.data(), dRphi.data());
3413 gr.Fit(&fPol,
"QNRC");
3414 float dca = fPol.Eval(0);
3416 std::vector<double>
params{fPol.GetParameter(0), fPol.GetParameter(1), fPol.GetParameter(2)};
3417 std::vector<float> rInterpol;
3418 std::vector<float> dRPhiInterpol;
3419 std::vector<float> distanceInterpol;
3421 for (
int i = 0;
i < 500; ++
i) {
3422 float radius = rmin + float(
i) / 10;
3423 rInterpol.emplace_back(radius);
3424 dRPhiInterpol.emplace_back(fPol.Eval(radius));
3425 distanceInterpol.emplace_back(std::sqrt(rInterpol.back() * rInterpol.back() + dRPhiInterpol.back() * dRPhiInterpol.back()));
3428 for (
int i = -200;
i < 200; ++
i) {
3429 float radius = float(
i) / 10;
3430 rInterpol.emplace_back(radius);
3431 dRPhiInterpol.emplace_back(fPol.Eval(radius));
3432 distanceInterpol.emplace_back(std::sqrt(rInterpol.back() * rInterpol.back() + dRPhiInterpol.back() * dRPhiInterpol.back()));
3434 (*pcstream) <<
"tree"
3436 <<
"dRphi=" << dRphi
3440 <<
"rInterpol=" << rInterpol
3441 <<
"dRPhiInterpol=" << dRPhiInterpol
3442 <<
"distanceInterpol=" << distanceInterpol
3449template <
typename DataT>
3452 initContainer(mPotential[
side],
true);
3456template <
typename DataT>
3460 for (
int iside = 0; iside < 2; ++iside) {
3462 const std::vector<std::reference_wrapper<const DataContainer>> dataRef{mLocalDistdR[iside], mLocalDistdZ[iside], mLocalDistdRPhi[iside], mLocalVecDistdR[iside], mLocalVecDistdZ[iside], mLocalVecDistdRPhi[iside], mLocalCorrdR[iside], mLocalCorrdZ[iside], mLocalCorrdRPhi[iside], mGlobalDistdR[iside], mGlobalDistdZ[iside], mGlobalDistdRPhi[iside], mGlobalCorrdR[iside], mGlobalCorrdZ[iside], mGlobalCorrdRPhi[iside], mDensity[iside], mPotential[iside], mElectricFieldEr[iside], mElectricFieldEz[iside], mElectricFieldEphi[iside]};
3463 const std::vector<std::reference_wrapper<DataContainer>> dataNew{scNew.mLocalDistdR[iside], scNew.mLocalDistdZ[iside], scNew.mLocalDistdRPhi[iside], scNew.mLocalVecDistdR[iside], scNew.mLocalVecDistdZ[iside], scNew.mLocalVecDistdRPhi[iside], scNew.mLocalCorrdR[iside], scNew.mLocalCorrdZ[iside], scNew.mLocalCorrdRPhi[iside], scNew.mGlobalDistdR[iside], scNew.mGlobalDistdZ[iside], scNew.mGlobalDistdRPhi[iside], scNew.mGlobalCorrdR[iside], scNew.mGlobalCorrdZ[iside], scNew.mGlobalCorrdRPhi[iside], scNew.mDensity[iside], scNew.mPotential[iside], scNew.mElectricFieldEr[iside], scNew.mElectricFieldEz[iside], scNew.mElectricFieldEphi[iside]};
3464 for (
int i = 0;
i < dataRef.size(); ++
i) {
3465 const auto& objRef = dataRef[
i].get();
3466 if (objRef.getNDataPoints()) {
3467 auto& objNew = dataNew[
i].get();
3468 scNew.initContainer(objNew,
true);
3469 objNew = objRef.convert(scNew.mGrid3D[iside], mGrid3D[iside], sNThreads);
3473 *
this = std::move(scNew);
3494template void O2TPCSpaceCharge3DCalcD::setGlobalCorrectionsFromFile<double>(TFile&,
const Side);
3495template void O2TPCSpaceCharge3DCalcD::setGlobalCorrectionsFromFile<float>(TFile&,
const Side);
3496template void O2TPCSpaceCharge3DCalcD::setGlobalDistortionsFromFile<double>(TFile&,
const Side);
3497template void O2TPCSpaceCharge3DCalcD::setGlobalDistortionsFromFile<float>(TFile&,
const Side);
3517template void O2TPCSpaceCharge3DCalcF::setGlobalCorrectionsFromFile<double>(TFile&,
const Side);
3518template void O2TPCSpaceCharge3DCalcF::setGlobalCorrectionsFromFile<float>(TFile&,
const Side);
3519template void O2TPCSpaceCharge3DCalcF::setGlobalDistortionsFromFile<double>(TFile&,
const Side);
3520template void O2TPCSpaceCharge3DCalcF::setGlobalDistortionsFromFile<float>(TFile&,
const Side);