1265 const auto val = hOrig.GetBinContent(iPhi, iR, iZ);
1269 const auto totalWeight = weightPhi * weightR * weightZ;
1270 sum +=
val * totalWeight;
1271 sumW += totalWeight;
1277 const int iZ = (
side ==
Side::A) ? (iBinZ - mParamGrid.NZVertices - 1) : (mParamGrid.NZVertices - iBinZ);
1278 mDensity[
side](iZ, iBinR - 1, iBinPhi - 1) =
sum;
1284template <
typename DataT>
1285template <
typename ElectricFields>
1288 const Side side = formulaStruct.getSide();
1289 if (
type == Type::Distortions) {
1290 initContainer(mLocalDistdR[
side],
true);
1291 initContainer(mLocalDistdZ[
side],
true);
1292 initContainer(mLocalDistdRPhi[
side],
true);
1294 initContainer(mLocalCorrdR[
side],
true);
1295 initContainer(mLocalCorrdZ[
side],
true);
1296 initContainer(mLocalCorrdRPhi[
side],
true);
1300#pragma omp parallel for num_threads(sNThreads)
1301 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1303 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1305 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1314 const DataT stepSize = (z1 - z0) / sSteps;
1315 for (
int iter = 0; iter < sSteps; ++iter) {
1316 const DataT z0Tmp = (z0 + iter * stepSize + dzTmp);
1317 const DataT z1Tmp = (z0Tmp + stepSize);
1323 const DataT radiusTmp = regulateR(radius + drTmp,
side);
1324 const DataT phiTmp = regulatePhi(phi + dPhiTmp,
side);
1327 calcDistCorr(radiusTmp, phiTmp, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct,
true,
side);
1337 case Type::Corrections:
1338 mLocalCorrdR[
side](iZ + 1, iR, iPhi) = drTmp;
1339 mLocalCorrdRPhi[
side](iZ + 1, iR, iPhi) = dPhiTmp * radius;
1340 mLocalCorrdZ[
side](iZ + 1, iR, iPhi) = dzTmp;
1343 case Type::Distortions:
1344 mLocalDistdR[
side](iZ, iR, iPhi) = drTmp;
1345 mLocalDistdRPhi[
side](iZ, iR, iPhi) = dPhiTmp * radius;
1346 mLocalDistdZ[
side](iZ, iR, iPhi) = dzTmp;
1352 case Type::Corrections:
1353 mLocalCorrdR[
side](0, iR, iPhi) = 3 * (mLocalCorrdR[
side](1, iR, iPhi) - mLocalCorrdR[
side](2, iR, iPhi)) + mLocalCorrdR[
side](3, iR, iPhi);
1354 mLocalCorrdRPhi[
side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[
side](1, iR, iPhi) - mLocalCorrdRPhi[
side](2, iR, iPhi)) + mLocalCorrdRPhi[
side](3, iR, iPhi);
1355 mLocalCorrdZ[
side](0, iR, iPhi) = 3 * (mLocalCorrdZ[
side](1, iR, iPhi) - mLocalCorrdZ[
side](2, iR, iPhi)) + mLocalCorrdZ[
side](3, iR, iPhi);
1358 case Type::Distortions:
1359 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);
1360 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);
1361 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);
1368template <
typename DataT>
1369template <
typename ElectricFields>
1372 const Side side = formulaStruct.getSide();
1373 initContainer(mLocalVecDistdR[
side],
true);
1374 initContainer(mLocalVecDistdZ[
side],
true);
1375 initContainer(mLocalVecDistdRPhi[
side],
true);
1376 initContainer(mElectricFieldEr[
side],
true);
1377 initContainer(mElectricFieldEz[
side],
true);
1378 initContainer(mElectricFieldEphi[
side],
true);
1380#pragma omp parallel for num_threads(sNThreads)
1381 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1382 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1383 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
1384 const DataT ezField = getEzField(formulaStruct.getSide());
1385 const DataT er = mElectricFieldEr[
side](iZ, iR, iPhi);
1386 const DataT ez0 = mElectricFieldEz[
side](iZ, iR, iPhi);
1387 const DataT ephi = mElectricFieldEphi[
side](iZ, iR, iPhi);
1388 const DataT ez = getSign(formulaStruct.getSide()) * 1. / (ezField + ez0);
1389 const DataT erez = er * ez;
1390 const DataT ephiez = ephi * ez;
1392 const DataT vecdR = mC0 * erez + mC1 * ephiez;
1393 const DataT vecdRPhi = mC0 * ephiez - mC1 * erez;
1396 mLocalVecDistdR[
side](iZ, iR, iPhi) = vecdR;
1397 mLocalVecDistdRPhi[
side](iZ, iR, iPhi) = vecdRPhi;
1398 mLocalVecDistdZ[
side](iZ, iR, iPhi) = vecdZ;
1404template <
typename DataT>
1405template <
typename ElectricFields>
1408 if (
type == Type::Distortions) {
1409 initContainer(mLocalDistdR[
side],
true);
1410 initContainer(mLocalDistdZ[
side],
true);
1411 initContainer(mLocalDistdRPhi[
side],
true);
1413 initContainer(mLocalCorrdR[
side],
true);
1414 initContainer(mLocalCorrdZ[
side],
true);
1415 initContainer(mLocalCorrdRPhi[
side],
true);
1419#pragma omp parallel for num_threads(sNThreads)
1420 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1422 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1424 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1426 const size_t iZ0 =
type == Type::Corrections ? iZ + 1 : iZ;
1427 const size_t iZ1 =
type == Type::Corrections ? iZ : iZ + 1;
1432 const DataT stepSize = z1 - z0;
1433 const DataT absstepSize = std::abs(stepSize);
1435 const DataT stepSizeHalf = 0.5 * stepSize;
1436 const DataT absstepSizeHalf = std::abs(stepSizeHalf);
1439 const DataT zk1 = z0;
1440 const DataT rk1 = radius;
1441 const DataT phik1 = phi;
1449 case Type::Corrections:
1450 k1dR = getLocalVecCorrR(iZ0, iR, iPhi,
side);
1451 k1dZ = getLocalVecCorrZ(iZ0, iR, iPhi,
side);
1452 k1dRPhi = getLocalVecCorrRPhi(iZ0, iR, iPhi,
side);
1455 case Type::Distortions:
1456 k1dR = getLocalVecDistR(iZ0, iR, iPhi,
side);
1457 k1dZ = getLocalVecDistZ(iZ0, iR, iPhi,
side);
1458 k1dRPhi = getLocalVecDistRPhi(iZ0, iR, iPhi,
side);
1463 const DataT zk2 = zk1 + stepSizeHalf + absstepSizeHalf * k1dZ;
1464 const DataT rk2 = rk1 + absstepSizeHalf * k1dR;
1465 const DataT k1dPhi = k1dRPhi / rk1;
1466 const DataT phik2 = phik1 + absstepSizeHalf * k1dPhi;
1472 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk2, rk2, phik2,
side, k2dZ, k2dR, k2dRPhi) : getLocalDistortionVectorCyl(zk2, rk2, phik2,
side, k2dZ, k2dR, k2dRPhi);
1475 const DataT zk3 = zk1 + stepSizeHalf + absstepSizeHalf * k2dZ;
1476 const DataT rk3 = rk1 + absstepSizeHalf * k2dR;
1477 const DataT k2dPhi = k2dRPhi / rk2;
1478 const DataT phik3 = phik1 + absstepSizeHalf * k2dPhi;
1483 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk3, rk3, phik3,
side, k3dZ, k3dR, k3dRPhi) : getLocalDistortionVectorCyl(zk3, rk3, phik3,
side, k3dZ, k3dR, k3dRPhi);
1485 const DataT zk4 = zk1 + stepSize + absstepSize * k3dZ;
1486 const DataT rk4 = rk1 + absstepSize * k3dR;
1487 const DataT k3dPhi = k3dRPhi / rk3;
1488 const DataT phik4 = phik1 + absstepSize * k3dPhi;
1493 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk4, rk4, phik4,
side, k4dZ, k4dR, k4dRPhi) : getLocalDistortionVectorCyl(zk4, rk4, phik4,
side, k4dZ, k4dR, k4dRPhi);
1494 const DataT k4dPhi = k4dRPhi / rk4;
1497 const DataT stepsizeSixth = absstepSize / 6;
1498 const DataT drRK = stepsizeSixth * (k1dR + 2 * k2dR + 2 * k3dR + k4dR);
1499 const DataT dzRK = stepsizeSixth * (k1dZ + 2 * k2dZ + 2 * k3dZ + k4dZ);
1500 const DataT dphiRK = stepsizeSixth * (k1dPhi + 2 * k2dPhi + 2 * k3dPhi + k4dPhi);
1504 case Type::Corrections:
1505 mLocalCorrdR[
side](iZ + 1, iR, iPhi) = drRK;
1506 mLocalCorrdRPhi[
side](iZ + 1, iR, iPhi) = dphiRK * radius;
1507 mLocalCorrdZ[
side](iZ + 1, iR, iPhi) = dzRK;
1510 case Type::Distortions:
1511 mLocalDistdR[
side](iZ, iR, iPhi) = drRK;
1512 mLocalDistdRPhi[
side](iZ, iR, iPhi) = dphiRK * radius;
1513 mLocalDistdZ[
side](iZ, iR, iPhi) = dzRK;
1519 case Type::Corrections:
1520 mLocalCorrdR[
side](0, iR, iPhi) = 3 * (mLocalCorrdR[
side](1, iR, iPhi) - mLocalCorrdR[
side](2, iR, iPhi)) + mLocalCorrdR[
side](3, iR, iPhi);
1521 mLocalCorrdRPhi[
side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[
side](1, iR, iPhi) - mLocalCorrdRPhi[
side](2, iR, iPhi)) + mLocalCorrdRPhi[
side](3, iR, iPhi);
1522 mLocalCorrdZ[
side](0, iR, iPhi) = 3 * (mLocalCorrdZ[
side](1, iR, iPhi) - mLocalCorrdZ[
side](2, iR, iPhi)) + mLocalCorrdZ[
side](3, iR, iPhi);
1525 case Type::Distortions:
1526 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);
1527 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);
1528 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);
1535template <
typename DataT>
1536template <
typename Fields>
1539 const Side side = formulaStruct.getSide();
1540 initContainer(mGlobalDistdR[
side],
true);
1541 initContainer(mGlobalDistdZ[
side],
true);
1542 initContainer(mGlobalDistdRPhi[
side],
true);
1543 const DataT stepSize = formulaStruct.getID() == 2 ? getGridSpacingZ(
side) : getGridSpacingZ(
side) / sSteps;
1545#pragma omp parallel for num_threads(sNThreads)
1546 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1548 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1550 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1553 DataT dPhiDist = 0.0;
1558 if (iter > maxIterations) {
1559 LOGP(error,
"Aborting calculation of distortions for iZ: {}, iR: {}, iPhi: {} due to iteration '{}' > maxIterations '{}'!", iZ, iR, iPhi, iter, maxIterations);
1562 const DataT z0Tmp = z0 + dzDist + iter * stepSize;
1565 if ((getSide(z0Tmp) !=
side) && iter) {
1566 LOGP(error,
"Aborting calculation of distortions for iZ: {}, iR: {}, iPhi: {} due to change in the sides!", iZ, iR, iPhi);
1570 const DataT z1Tmp = z0Tmp + stepSize;
1571 const DataT radius = regulateR(r0 + drDist,
side);
1572 const DataT phi = regulatePhi(phi0 + dPhiDist,
side);
1579 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct);
1583 const bool checkReached =
side ==
Side::A ? z1Tmp >= getZMax(
side) : z1Tmp <= getZMax(
side);
1584 if (formulaStruct.getID() == 2 && checkReached) {
1585 const DataT fac = std::abs((getZMax(
side) - z0Tmp) * getInvSpacingZ(
side));
1599 const DataT endPoint = z1Tmp + ddZ;
1600 const DataT deltaZ = getZMax(
side) - endPoint;
1601 const DataT diff = endPoint - z0Tmp;
1602 const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0;
1603 drDist += ddR * fac;
1604 dPhiDist += ddPhi * fac;
1605 dzDist += ddZ * fac;
1611 mGlobalDistdR[
side](iZ, iR, iPhi) = drDist;
1612 mGlobalDistdRPhi[
side](iZ, iR, iPhi) = dPhiDist * r0;
1613 mGlobalDistdZ[
side](iZ, iR, iPhi) = dzDist;
1619template <
typename DataT>
1620template <
typename Formulas>
1623 using timer = std::chrono::high_resolution_clock;
1624 auto start = timer::now();
1625 const Side side = formulaStruct.getSide();
1626 initContainer(mGlobalCorrdR[
side],
true);
1627 initContainer(mGlobalCorrdZ[
side],
true);
1628 initContainer(mGlobalCorrdRPhi[
side],
true);
1630 const int iSteps = formulaStruct.getID() == 2 ? 1 : sSteps;
1631 const DataT stepSize = -getGridSpacingZ(
side) / iSteps;
1633#pragma omp parallel for num_threads(sNThreads)
1634 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1636 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1642 bool isOutOfVolume =
false;
1645 for (
size_t iZ = mParamGrid.NZVertices - 1; iZ >= 1; --iZ) {
1648 bool centralElectrodeReached =
false;
1649 for (
int iter = 0; iter < iSteps; ++iter) {
1650 if ((
type != 3) && (centralElectrodeReached || isOutOfVolume)) {
1653 DataT radius = r0 + drCorr;
1654 DataT phi = phi0 + dPhiCorr;
1655 const DataT z0Tmp = z0 + dzCorr + iter * stepSize;
1656 DataT z1Tmp = z0Tmp + stepSize;
1660 radius = regulateR(radius,
side);
1661 phi = regulatePhi(phi,
side);
1662 z1Tmp = regulateZ(z1Tmp,
side);
1670 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct);
1674 centralElectrodeReached = getSign(
side) * z1Tmp <= getZMin(
side);
1675 if (formulaStruct.getID() == 2 && centralElectrodeReached) {
1676 const DataT fac = (z0Tmp - getZMin(
side)) * getInvSpacingZ(
side);
1683 const DataT rCurr = r0 + drCorr + ddR;
1684 const DataT zCurr = z0Tmp + dzCorr + ddZ + stepSize;
1687 if ((
type != 3) && (rCurr <= getRMinSim(
side) || rCurr >= getRMaxSim(
side) || (std::abs(zCurr) > 1.2 * std::abs(getZMax(
side))))) {
1688 isOutOfVolume =
true;
1699 if ((
type != 3) && centralElectrodeReached) {
1700 const DataT endPoint = z1Tmp + ddZ;
1701 const DataT deltaZ = endPoint - getZMin(
side);
1702 const DataT diff = z0Tmp - endPoint;
1703 const DataT fac = diff != 0 ? deltaZ / diff : 0;
1704 drCorr += ddR * fac;
1705 dPhiCorr += ddPhi * fac;
1706 dzCorr += ddZ * fac;
1711 if ((
type == 1 ||
type == 2) && (centralElectrodeReached || isOutOfVolume)) {
1712 mGlobalCorrdR[
side](iZ - 1, iR, iPhi) = -1;
1713 mGlobalCorrdRPhi[
side](iZ - 1, iR, iPhi) = -1;
1714 mGlobalCorrdZ[
side](iZ - 1, iR, iPhi) = -1;
1716 mGlobalCorrdR[
side](iZ - 1, iR, iPhi) = drCorr;
1717 mGlobalCorrdRPhi[
side](iZ - 1, iR, iPhi) = dPhiCorr * r0;
1718 mGlobalCorrdZ[
side](iZ - 1, iR, iPhi) = dzCorr;
1725 for (
int iZ = mParamGrid.NZVertices - 1; iZ >= 0; --iZ) {
1727 for (
int iR = (mParamGrid.NRVertices / 2); iR >= 0; --iR) {
1728 if ((mGlobalCorrdR[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdRPhi[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdZ[
side](iZ, iR, iPhi) == -1)) {
1729 const size_t iRUp = iR + 1;
1732 mGlobalCorrdR[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1733 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1734 mGlobalCorrdZ[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1735 }
else if (
type == 2) {
1737 const size_t iRUpTwo = iR + 2;
1738 const size_t iRUpThree = iR + 3;
1739 mGlobalCorrdR[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdR[
side](iZ, iRUp, iPhi) - mGlobalCorrdR[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdR[
side](iZ, iRUpThree, iPhi);
1740 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdRPhi[
side](iZ, iRUp, iPhi) - mGlobalCorrdRPhi[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdRPhi[
side](iZ, iRUpThree, iPhi);
1741 mGlobalCorrdZ[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdZ[
side](iZ, iRUp, iPhi) - mGlobalCorrdZ[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdZ[
side](iZ, iRUpThree, iPhi);
1746 for (
int iR = (mParamGrid.NRVertices / 2); iR < mParamGrid.NRVertices; ++iR) {
1747 if ((mGlobalCorrdR[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdRPhi[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdZ[
side](iZ, iR, iPhi) == -1)) {
1748 const size_t iRUp = iR - 1;
1751 mGlobalCorrdR[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1752 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1753 mGlobalCorrdZ[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1754 }
else if (
type == 2) {
1756 const size_t iRUpTwo = iR - 2;
1757 const size_t iRUpThree = iR - 3;
1758 mGlobalCorrdR[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdR[
side](iZ, iRUp, iPhi) - mGlobalCorrdR[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdR[
side](iZ, iRUpThree, iPhi);
1759 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdRPhi[
side](iZ, iRUp, iPhi) - mGlobalCorrdRPhi[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdRPhi[
side](iZ, iRUpThree, iPhi);
1760 mGlobalCorrdZ[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdZ[
side](iZ, iRUp, iPhi) - mGlobalCorrdZ[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdZ[
side](iZ, iRUpThree, iPhi);
1768 auto stop = timer::now();
1769 std::chrono::duration<float>
time = stop -
start;
1770 const float totalTime =
time.count();
1771 LOGP(detail,
"calcGlobalCorrections took {}s", totalTime);
1774template <
typename DataT>
1780 const Side side = getSide(point.Z());
1783 getCorrections(point.X(), point.Y(), point.Z(),
side, corrX, corrY, corrZ);
1786 point.SetXYZ(point.X() + corrX, point.Y() + corrY, point.Y() + corrY);
1789template <
typename DataT>
1795 const Side side = getSide(point.Z());
1797 getDistortions(point.X(), point.Y(), point.Z(),
side, distX, distY, distZ);
1804 if (scSCale && scale != 0) {
1805 scSCale->
getDistortions(point.X() + distX, point.Y() + distY, point.Z() + distZ,
side, distXTmp, distYTmp, distZTmp);
1806 distX += distXTmp * scale;
1807 distY += distYTmp * scale;
1808 distZ += distZTmp * scale;
1813 float phi = std::atan2(
pos.Y(),
pos.X());
1817 unsigned char secNum = std::floor(phi /
SECPHIWIDTH);
1821 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_distortElectron",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_distortElectron").data()
1825 <<
"secNum=" << secNum
1826 <<
"distX=" << distX
1827 <<
"distY=" << distY
1828 <<
"distZ=" << distZ
1829 <<
"distXDer=" << distXTmp
1830 <<
"distYDer=" << distYTmp
1831 <<
"distZDer=" << distZTmp
1832 <<
"scale=" << scale
1837 point.SetXYZ(point.X() + distX, point.Y() + distY, point.Z() + distZ);
1840template <
typename DataT>
1843 return mInterpolatorDensity[
side](
z,
r, phi);
1846template <
typename DataT>
1849 const auto nPoints =
z.size();
1850 std::vector<float> density(nPoints);
1851#pragma omp parallel for num_threads(sNThreads)
1852 for (
size_t i = 0;
i < nPoints; ++
i) {
1853 density[
i] = getDensityCyl(
z[
i],
r[
i], phi[
i],
side);
1858template <
typename DataT>
1861 return mInterpolatorPotential[
side](
z,
r, phi);
1864template <
typename DataT>
1867 const auto nPoints =
z.size();
1868 std::vector<float> potential(nPoints);
1869#pragma omp parallel for num_threads(sNThreads)
1870 for (
size_t i = 0;
i < nPoints; ++
i) {
1871 potential[
i] = getPotentialCyl(
z[
i],
r[
i], phi[
i],
side);
1876template <
typename DataT>
1879 eZ = mInterpolatorEField[
side].evalFieldZ(
z,
r, phi);
1880 eR = mInterpolatorEField[
side].evalFieldR(
z,
r, phi);
1881 ePhi = mInterpolatorEField[
side].evalFieldPhi(
z,
r, phi);
1884template <
typename DataT>
1887 lcorrZ = mInterpolatorLocalCorr[
side].evaldZ(
z,
r, phi);
1888 lcorrR = mInterpolatorLocalCorr[
side].evaldR(
z,
r, phi);
1889 lcorrRPhi = mInterpolatorLocalCorr[
side].evaldRPhi(
z,
r, phi);
1892template <
typename DataT>
1895 const auto nPoints =
z.size();
1896 lcorrZ.resize(nPoints);
1897 lcorrR.resize(nPoints);
1898 lcorrRPhi.resize(nPoints);
1899#pragma omp parallel for num_threads(sNThreads)
1900 for (
size_t i = 0;
i < nPoints; ++
i) {
1901 getLocalCorrectionsCyl(
z[
i],
r[
i], phi[
i],
side, lcorrZ[
i], lcorrR[
i], lcorrRPhi[
i]);
1905template <
typename DataT>
1908 corrZ = mInterpolatorGlobalCorr[
side].evaldZ(
z,
r, phi);
1909 corrR = mInterpolatorGlobalCorr[
side].evaldR(
z,
r, phi);
1910 corrRPhi = mInterpolatorGlobalCorr[
side].evaldRPhi(
z,
r, phi);
1913template <
typename DataT>
1916 const auto nPoints =
z.size();
1917 corrZ.resize(nPoints);
1918 corrR.resize(nPoints);
1919 corrRPhi.resize(nPoints);
1920#pragma omp parallel for num_threads(sNThreads)
1921 for (
size_t i = 0;
i < nPoints; ++
i) {
1922 getCorrectionsCyl(
z[
i],
r[
i], phi[
i],
side, corrZ[
i], corrR[
i], corrRPhi[
i]);
1926template <
typename DataT>
1929 if (mUseAnaDistCorr) {
1930 getCorrectionsAnalytical(
x,
y,
z,
side, corrX, corrY, corrZ);
1933 const DataT radius = getRadiusFromCartesian(
x,
y);
1934 DataT phi = getPhiFromCartesian(
x,
y);
1939 getCorrectionsCyl(
z, radius, phi,
side, corrZ, corrR, corrRPhi);
1942 const DataT radiusCorr = radius + corrR;
1943 const DataT phiCorr = phi + corrRPhi / radius;
1945 corrX = getXFromPolar(radiusCorr, phiCorr) -
x;
1946 corrY = getYFromPolar(radiusCorr, phiCorr) -
y;
1950template <
typename DataT>
1953 ldistZ = mInterpolatorLocalDist[
side].evaldZ(
z,
r, phi);
1954 ldistR = mInterpolatorLocalDist[
side].evaldR(
z,
r, phi);
1955 ldistRPhi = mInterpolatorLocalDist[
side].evaldRPhi(
z,
r, phi);
1958template <
typename DataT>
1961 const auto nPoints =
z.size();
1962 ldistZ.resize(nPoints);
1963 ldistR.resize(nPoints);
1964 ldistRPhi.resize(nPoints);
1965#pragma omp parallel for num_threads(sNThreads)
1966 for (
size_t i = 0;
i < nPoints; ++
i) {
1967 getLocalDistortionsCyl(
z[
i],
r[
i], phi[
i],
side, ldistZ[
i], ldistR[
i], ldistRPhi[
i]);
1971template <
typename DataT>
1974 lvecdistZ = mInterpolatorLocalVecDist[
side].evaldZ(
z,
r, phi);
1975 lvecdistR = mInterpolatorLocalVecDist[
side].evaldR(
z,
r, phi);
1976 lvecdistRPhi = mInterpolatorLocalVecDist[
side].evaldRPhi(
z,
r, phi);
1979template <
typename DataT>
1982 const auto nPoints =
z.size();
1983 lvecdistZ.resize(nPoints);
1984 lvecdistR.resize(nPoints);
1985 lvecdistRPhi.resize(nPoints);
1986#pragma omp parallel for num_threads(sNThreads)
1987 for (
size_t i = 0;
i < nPoints; ++
i) {
1988 getLocalDistortionVectorCyl(
z[
i],
r[
i], phi[
i],
side, lvecdistZ[
i], lvecdistR[
i], lvecdistRPhi[
i]);
1992template <
typename DataT>
1995 lveccorrZ = -mInterpolatorLocalVecDist[
side].evaldZ(
z,
r, phi);
1996 lveccorrR = -mInterpolatorLocalVecDist[
side].evaldR(
z,
r, phi);
1997 lveccorrRPhi = -mInterpolatorLocalVecDist[
side].evaldRPhi(
z,
r, phi);
2000template <
typename DataT>
2003 const auto nPoints =
z.size();
2004 lveccorrZ.resize(nPoints);
2005 lveccorrR.resize(nPoints);
2006 lveccorrRPhi.resize(nPoints);
2007#pragma omp parallel for num_threads(sNThreads)
2008 for (
size_t i = 0;
i < nPoints; ++
i) {
2009 getLocalCorrectionVectorCyl(
z[
i],
r[
i], phi[
i],
side, lveccorrZ[
i], lveccorrR[
i], lveccorrRPhi[
i]);
2013template <
typename DataT>
2016 distZ = mInterpolatorGlobalDist[
side].evaldZ(
z,
r, phi);
2017 distR = mInterpolatorGlobalDist[
side].evaldR(
z,
r, phi);
2018 distRPhi = mInterpolatorGlobalDist[
side].evaldRPhi(
z,
r, phi);
2021template <
typename DataT>
2024 const auto nPoints =
z.size();
2025 distZ.resize(nPoints);
2026 distR.resize(nPoints);
2027 distRPhi.resize(nPoints);
2028#pragma omp parallel for num_threads(sNThreads)
2029 for (
size_t i = 0;
i < nPoints; ++
i) {
2030 getDistortionsCyl(
z[
i],
r[
i], phi[
i],
side, distZ[
i], distR[
i], distRPhi[
i]);
2034template <
typename DataT>
2039 if (mUseAnaDistCorr) {
2040 getDistortionsAnalytical(
x,
y, zClamped,
side, distX, distY, distZ);
2043 const DataT radius = getRadiusFromCartesian(
x,
y);
2044 const DataT phi = getPhiFromCartesian(
x,
y);
2048 DataT rClamped = regulateR(radius,
side);
2049 getDistortionsCyl(zClamped, rClamped, phi,
side, distZ, distR, distRPhi);
2052 const DataT radiusDist = rClamped + distR;
2053 const DataT phiDist = phi + distRPhi / rClamped;
2055 distX = getXFromPolar(radiusDist, phiDist) -
x;
2056 distY = getYFromPolar(radiusDist, phiDist) -
y;
2060template <
typename DataT>
2064 float phi = std::atan2(
pos.Y(),
pos.X());
2068 const unsigned char secNum = std::floor(phi /
SECPHIWIDTH);
2073 const DataT dlX = dist ? mAnaDistCorr.getDistortionsLX(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLX(lPos.X(), lPos.Y(), lPos.Z(),
side);
2074 const DataT dlY = dist ? mAnaDistCorr.getDistortionsLY(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLY(lPos.X(), lPos.Y(), lPos.Z(),
side);
2075 const DataT dlZ = dist ? mAnaDistCorr.getDistortionsLZ(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLZ(lPos.X(), lPos.Y(), lPos.Z(),
side);
2079 const LocalPosition3D lPosDist(lPos.X() + dlX, lPos.Y() + dlY, lPos.Z() + dlZ);
2083 distX = globalPosDist.X() -
x;
2084 distY = globalPosDist.Y() -
y;
2085 distZ = globalPosDist.Z() -
z;
2088 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_distortions_analytical",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_distortions_analytical").data()
2091 <<
"dlX=" << (*
const_cast<DataT*
>(&dlX))
2092 <<
"dlY=" << (*
const_cast<DataT*
>(&dlY))
2093 <<
"dlZ=" << (*
const_cast<DataT*
>(&dlZ))
2094 <<
"distX=" << distX
2095 <<
"distY=" << distY
2096 <<
"distZ=" << distZ
2101template <
typename DataT>
2104 using timer = std::chrono::high_resolution_clock;
2105 if (!mInitLookUpTables) {
2106 auto start = timer::now();
2111 float vDrift = gasParam.DriftV;
2113 const float t1 = 1.;
2114 const float t2 = 1.;
2116 const float omegaTau = -10. * bzField * vDrift / std::abs(getEzField(
Side::A));
2117 setOmegaTauT1T2(omegaTau,
t1, t2);
2118 if (mUseInitialSCDensity) {
2119 LOG(warning) <<
"mUseInitialSCDensity" << mUseInitialSCDensity;
2120 calculateDistortionsCorrections(
Side::A);
2121 calculateDistortionsCorrections(
Side::C);
2122 mInitLookUpTables =
true;
2124 auto stop = timer::now();
2125 std::chrono::duration<float>
time = stop -
start;
2126 LOGP(info,
"Total Time Distortions and Corrections for A and C Side: {}",
time.count());
2130template <
typename DataT>
2133 mGlobalDistdR[
side] = distdR;
2134 mGlobalDistdZ[
side] = distdZ;
2135 mGlobalDistdRPhi[
side] = distdRPhi;
2138template <
typename DataT>
2139template <
typename Fields>
2143 "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);
2144 localIntErOverEz =
static_cast<DataT>(fErOverEz.Integral(p1z, p2z));
2147 "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);
2148 localIntEPhiOverEz =
static_cast<DataT>(fEphiOverEz.Integral(p1z, p2z));
2151 "fEZOverEz", [&](
double*
x,
double* p) { (
void)p;
return static_cast<double>(formulaStruct.evalFieldZ(
static_cast<DataT>(
x[0]), p1r, p1phi) - ezField); }, p1z, p2z, 1);
2152 localIntDeltaEz = getSign(
side) *
static_cast<DataT>(fEz.Integral(p1z, p2z));
2155template <
typename DataT>
2156template <
typename Fields>
2160 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2161 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2162 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2164 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p1r, p1phi);
2165 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p1r, p1phi);
2166 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p1r, p1phi);
2168 const DataT eZ0 = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2169 const DataT eZ1 = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2171 const DataT deltaX = 0.5 * (p2z - p1z);
2172 localIntErOverEz = deltaX * (fielder0 * eZ0 + fielder1 * eZ1);
2173 localIntEPhiOverEz = deltaX * (fieldephi0 * eZ0 + fieldephi1 * eZ1);
2174 localIntDeltaEz = getSign(
side) * deltaX * (fieldez0 + fieldez1);
2177template <
typename DataT>
2178template <
typename Fields>
2182 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2183 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2184 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2186 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p1r, p1phi);
2187 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p1r, p1phi);
2188 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p1r, p1phi);
2190 const DataT deltaX = p2z - p1z;
2191 const DataT xk2N = (p2z -
static_cast<DataT>(0.5) * deltaX);
2192 const DataT ezField2 = formulaStruct.evalFieldZ(xk2N, p1r, p1phi);
2193 const DataT ezField2Denominator = isCloseToZero(ezField, ezField2) ? 0 : 1. / (ezField + ezField2);
2194 const DataT fieldSum2ErOverEz = formulaStruct.evalFieldR(xk2N, p1r, p1phi) * ezField2Denominator;
2195 const DataT fieldSum2EphiOverEz = formulaStruct.evalFieldPhi(xk2N, p1r, p1phi) * ezField2Denominator;
2197 const DataT eZ0 = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2198 const DataT eZ1 = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2200 const DataT deltaXSimpsonSixth = deltaX / 6.;
2201 localIntErOverEz = deltaXSimpsonSixth * (4. * fieldSum2ErOverEz + fielder0 * eZ0 + fielder1 * eZ1);
2202 localIntEPhiOverEz = deltaXSimpsonSixth * (4. * fieldSum2EphiOverEz + fieldephi0 * eZ0 + fieldephi1 * eZ1);
2203 localIntDeltaEz = getSign(
side) * deltaXSimpsonSixth * (4. * ezField2 + fieldez0 + fieldez1);
2206template <
typename DataT>
2207template <
typename Fields>
2208void 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
2213 const DataT p2phiSave = regulatePhi(p2phi,
side);
2215 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2216 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2217 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2219 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p2r, p2phiSave);
2220 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p2r, p2phiSave);
2221 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p2r, p2phiSave);
2223 const DataT eZ0Inv = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2224 const DataT eZ1Inv = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2226 const DataT pHalfZ = 0.5 * (p1z + p2z);
2227 const DataT pHalfPhiSave = regulatePhi(0.5 * (p1phi + p2phi),
side);
2228 const DataT pHalfR = 0.5 * (p1r + p2r);
2230 const DataT ezField2 = formulaStruct.evalFieldZ(pHalfZ, pHalfR, pHalfPhiSave);
2231 const DataT eZHalfInv = (isCloseToZero(ezField, ezField2) | isCloseToZero(ezField, fieldez0) | isCloseToZero(ezField, fieldez1)) ? 0 : 1. / (ezField + ezField2);
2232 const DataT fieldSum2ErOverEz = formulaStruct.evalFieldR(pHalfZ, pHalfR, pHalfPhiSave);
2233 const DataT fieldSum2EphiOverEz = formulaStruct.evalFieldPhi(pHalfZ, pHalfR, pHalfPhiSave);
2235 const DataT deltaXSimpsonSixth = (p2z - p1z) / 6;
2236 localIntErOverEz = deltaXSimpsonSixth * (4 * fieldSum2ErOverEz * eZHalfInv + fielder0 * eZ0Inv + fielder1 * eZ1Inv);
2237 localIntEPhiOverEz = deltaXSimpsonSixth * (4 * fieldSum2EphiOverEz * eZHalfInv + fieldephi0 * eZ0Inv + fieldephi1 * eZ1Inv);
2238 localIntDeltaEz = getSign(
side) * deltaXSimpsonSixth * (4 * ezField2 + fieldez0 + fieldez1);
2241template <
typename DataT>
2242std::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
2244 const unsigned int nElectrons = elePos.size();
2245 std::vector<std::pair<std::vector<o2::math_utils::Point3D<float>>, std::array<DataT, 3>>> electronTracks(nElectrons);
2247 for (
unsigned int i = 0;
i < nElectrons; ++
i) {
2248 electronTracks[
i].first.reserve(nSamplingPoints + 1);
2251 for (
unsigned int i = 0;
i < nElectrons; ++
i) {
2252 const DataT z0 = elePos[
i].Z();
2253 const DataT r0 = elePos[
i].Rho();
2254 const DataT phi0 = elePos[
i].Phi();
2256 if (!mElectricFieldEr[
side].getNDataPoints()) {
2257 LOGP(warning,
"E-Fields are not set! Calculation of drift path is not possible");
2261 const DataT stepSize = getZMax(
side) / nSamplingPoints;
2264 DataT dPhiDist = 0.0;
2268 const DataT z0Tmp = z0 + dzDist + iter * stepSize;
2269 const DataT z1Tmp = regulateZ(z0Tmp + stepSize,
side);
2270 const DataT radius = r0 + drDist;
2273 if (radius <= getRMin(
side) || radius >= getRMax(
side) || getSide(z0Tmp) !=
side) {
2277 const DataT phi = regulatePhi(phi0 + dPhiDist,
side);
2278 electronTracks[
i].first.emplace_back(
GlobalPosition3D(radius * std::cos(phi), radius * std::sin(phi), z0Tmp));
2285 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, numEFields);
2294 const bool checkReached =
side ==
Side::A ? z1Tmp >= getZMax(
side) : z1Tmp <= getZMax(
side);
2299 const DataT endPoint = z1Tmp + ddZ;
2300 const DataT deltaZ = getZMax(
side) - endPoint;
2301 const DataT diff = endPoint - z0Tmp;
2302 const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0;
2303 drDist += ddR * fac;
2304 dPhiDist += ddPhi * fac;
2305 dzDist += ddZ * fac;
2306 const DataT z1TmpEnd = regulateZ(z0Tmp + stepSize,
side);
2307 const DataT radiusEnd = regulateR(r0 + drDist,
side);
2308 const DataT phiEnd = regulatePhi(phi0 + dPhiDist,
side);
2309 electronTracks[
i].first.emplace_back(
GlobalPosition3D(radiusEnd * std::cos(phiEnd), radiusEnd * std::sin(phiEnd), z1TmpEnd));
2314 electronTracks[
i].second = std::array<DataT, 3>{drDist, dPhiDist * r0, dzDist};
2316 if (!outFile.empty()) {
2317 dumpElectronTracksToTree(electronTracks, nSamplingPoints, outFile.data());
2319 return electronTracks;
2322template <
typename DataT>
2326 pcstream.GetFile()->cd();
2331 for (
int i = 0;
i < electronTracks.size(); ++
i) {
2332 auto electronPath = electronTracks[
i].first;
2333 const int nPoints = electronPath.size();
2334 if (electronPath.empty()) {
2335 LOGP(warning,
"Track is empty. Continue to next track.");
2338 std::vector<float> relDriftVel;
2339 relDriftVel.reserve(nPoints);
2341 for (
int iPoint = 0; iPoint < (nPoints - 2); ++iPoint) {
2342 const DataT relDriftVelTmp = (electronPath[iPoint + 1].Z() - electronPath[iPoint].Z()) / getZMax(getSide(electronPath[iPoint].Z())) * nSamplingPoints;
2343 relDriftVel.emplace_back(std::abs(relDriftVelTmp));
2347 relDriftVel.emplace_back(relDriftVel.back());
2348 relDriftVel.emplace_back(relDriftVel.back());
2350 DataT distR = electronTracks[
i].second[0];
2351 DataT distRPhi = electronTracks[
i].second[1];
2352 DataT distZ = electronTracks[
i].second[2];
2354 DataT driftTime = std::abs(getZMax(getSide(electronPath.front().Z())) - (distZ + electronPath.front().Z())) / gasParam.DriftV;
2355 DataT timeBin = driftTime / eleParam.ZbinWidth;
2358 <<
"electronPath=" << electronPath
2359 <<
"relDriftVel.=" << relDriftVel
2360 <<
"distR=" << distR
2361 <<
"distRPhi=" << distRPhi
2362 <<
"distZ=" << distZ
2363 <<
"driftTime=" << driftTime
2364 <<
"timeBin=" << timeBin
2370template <
typename DataT>
2374 TFile fInp(inpFile,
"READ");
2375 TTree*
tree = (TTree*)fInp.Get(
"drift");
2376 std::vector<o2::tpc::GlobalPosition3D>* electronPathTree =
new std::vector<o2::tpc::GlobalPosition3D>;
2377 tree->SetBranchAddress(
"electronPath", &electronPathTree);
2379 std::vector<std::vector<o2::tpc::GlobalPosition3D>> electronPaths;
2380 std::vector<o2::tpc::GlobalPosition3D> elePosTmp;
2381 const int entries =
tree->GetEntriesFast();
2382 for (
int i = 0;
i < entries; ++
i) {
2384 electronPaths.emplace_back(*electronPathTree);
2386 delete electronPathTree;
2389 TCanvas can(
"canvas",
"canvas", 1000, 600);
2390 can.SetTopMargin(0.04f);
2391 can.SetRightMargin(0.04f);
2392 can.SetBottomMargin(0.12f);
2393 can.SetLeftMargin(0.11f);
2395 const int nElectrons = electronPaths.size();
2396 std::vector<int> indexStartEle(nElectrons);
2397 std::vector<int> countReadoutReached(nElectrons);
2400 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};
2403 unsigned int maxPoints = 0;
2404 std::vector<TGraph> gr(nElectrons);
2405 for (
int i = 0;
i < nElectrons; ++
i) {
2406 gr[
i].SetMarkerColor(colorsPalette[
i % colorsPalette.size()]);
2408 if (electronPaths[
i].
size() > maxPoints) {
2409 maxPoints = electronPaths[
i].size();
2413 const DataT pointsPerIteration = maxPoints /
static_cast<DataT>(maxsamplingpoints);
2414 std::vector<DataT> zRemainder(nElectrons);
2417 for (
auto& graph : gr) {
2421 for (
int iEle = 0; iEle < nElectrons; ++iEle) {
2422 const int nSamplingPoints = electronPaths[iEle].size();
2423 const int nPoints = std::round(pointsPerIteration + zRemainder[iEle]);
2424 zRemainder[iEle] = pointsPerIteration - nPoints;
2425 const auto& electronPath = electronPaths[iEle];
2427 if (nPoints == 0 && countReadoutReached[iEle] == 0) {
2428 const int indexPoint = indexStartEle[iEle];
2429 const DataT radius = electronPath[indexPoint].Rho();
2430 const DataT z = electronPath[indexPoint].Z();
2431 const DataT phi = electronPath[indexPoint].Phi();
2432 type == 0 ? gr[iEle].AddPoint(
z, radius) : gr[iEle].AddPoint(phi, radius);
2435 for (
int iPoint = 0; iPoint < nPoints; ++iPoint) {
2436 const int indexPoint = indexStartEle[iEle];
2437 if (indexPoint >= nSamplingPoints) {
2438 countReadoutReached[iEle] = 1;
2442 const DataT radius = electronPath[indexPoint].Rho();
2443 const DataT z = electronPath[indexPoint].Z();
2444 const DataT phi = electronPath[indexPoint].Phi();
2445 if (iPoint == nPoints / 2) {
2446 type == 0 ? gr[iEle].AddPoint(
z, radius) : gr[iEle].AddPoint(phi, radius);
2448 ++indexStartEle[iEle];
2452 for (
auto& graph : gr) {
2453 if (graph.GetN() > 0) {
2454 graph.Draw(
"P SAME");
2457 can.Print(Form(
"%s.gif+%i", outName, gifSpeed));
2459 const int sumReadoutReached = std::accumulate(countReadoutReached.begin(), countReadoutReached.end(), 0);
2460 if (sumReadoutReached == nElectrons) {
2465 can.Print(Form(
"%s.gif++", outName));
2468template <
typename DataT>
2472 const DataT rSpacing = GridProp::getGridSpacingR(nRPoints);
2473 const DataT zSpacing =
side ==
Side::A ? GridProp::getGridSpacingZ(nZPoints) : -GridProp::getGridSpacingZ(nZPoints);
2475 std::uniform_real_distribution<DataT> uniR(-rSpacing / 2, rSpacing / 2);
2476 std::uniform_real_distribution<DataT> uniPhi(-phiSpacing / 2, phiSpacing / 2);
2478 std::vector<std::vector<float>> phiPosOut(nPhiPoints);
2479 std::vector<std::vector<float>> rPosOut(nPhiPoints);
2480 std::vector<std::vector<float>> zPosOut(nPhiPoints);
2481 std::vector<std::vector<int>> iPhiOut(nPhiPoints);
2482 std::vector<std::vector<int>> iROut(nPhiPoints);
2483 std::vector<std::vector<int>> iZOut(nPhiPoints);
2484 std::vector<std::vector<float>> densityOut(nPhiPoints);
2485 std::vector<std::vector<float>> potentialOut(nPhiPoints);
2486 std::vector<std::vector<float>> eZOut(nPhiPoints);
2487 std::vector<std::vector<float>> eROut(nPhiPoints);
2488 std::vector<std::vector<float>> ePhiOut(nPhiPoints);
2489 std::vector<std::vector<float>> distZOut(nPhiPoints);
2490 std::vector<std::vector<float>> distROut(nPhiPoints);
2491 std::vector<std::vector<float>> distRPhiOut(nPhiPoints);
2492 std::vector<std::vector<float>> corrZOut(nPhiPoints);
2493 std::vector<std::vector<float>> corrROut(nPhiPoints);
2494 std::vector<std::vector<float>> corrRPhiOut(nPhiPoints);
2495 std::vector<std::vector<float>> lcorrZOut(nPhiPoints);
2496 std::vector<std::vector<float>> lcorrROut(nPhiPoints);
2497 std::vector<std::vector<float>> lcorrRPhiOut(nPhiPoints);
2498 std::vector<std::vector<float>> ldistZOut(nPhiPoints);
2499 std::vector<std::vector<float>> ldistROut(nPhiPoints);
2500 std::vector<std::vector<float>> ldistRPhiOut(nPhiPoints);
2501 std::vector<std::vector<float>> xOut(nPhiPoints);
2502 std::vector<std::vector<float>> yOut(nPhiPoints);
2503 std::vector<std::vector<float>> bROut(nPhiPoints);
2504 std::vector<std::vector<float>> bZOut(nPhiPoints);
2505 std::vector<std::vector<float>> bPhiOut(nPhiPoints);
2506 std::vector<std::vector<LocalPosition3D>> lPosOut(nPhiPoints);
2507 std::vector<std::vector<int>> sectorOut(nPhiPoints);
2508 std::vector<std::vector<size_t>> globalIdxOut(nPhiPoints);
2509 std::vector<std::vector<bool>> isOnPadPlane(nPhiPoints);
2511#pragma omp parallel for num_threads(sNThreads)
2512 for (
int iPhi = 0; iPhi < nPhiPoints; ++iPhi) {
2513 const int nPoints = nZPoints * nRPoints;
2514 phiPosOut[iPhi].reserve(nPoints);
2515 rPosOut[iPhi].reserve(nPoints);
2516 zPosOut[iPhi].reserve(nPoints);
2517 iPhiOut[iPhi].reserve(nPoints);
2518 iROut[iPhi].reserve(nPoints);
2519 iZOut[iPhi].reserve(nPoints);
2520 densityOut[iPhi].reserve(nPoints);
2521 potentialOut[iPhi].reserve(nPoints);
2522 eZOut[iPhi].reserve(nPoints);
2523 eROut[iPhi].reserve(nPoints);
2524 ePhiOut[iPhi].reserve(nPoints);
2525 distZOut[iPhi].reserve(nPoints);
2526 distROut[iPhi].reserve(nPoints);
2527 distRPhiOut[iPhi].reserve(nPoints);
2528 corrZOut[iPhi].reserve(nPoints);
2529 corrROut[iPhi].reserve(nPoints);
2530 corrRPhiOut[iPhi].reserve(nPoints);
2531 lcorrZOut[iPhi].reserve(nPoints);
2532 lcorrROut[iPhi].reserve(nPoints);
2533 lcorrRPhiOut[iPhi].reserve(nPoints);
2534 ldistZOut[iPhi].reserve(nPoints);
2535 ldistROut[iPhi].reserve(nPoints);
2536 ldistRPhiOut[iPhi].reserve(nPoints);
2537 xOut[iPhi].reserve(nPoints);
2538 yOut[iPhi].reserve(nPoints);
2539 bROut[iPhi].reserve(nPoints);
2540 bZOut[iPhi].reserve(nPoints);
2541 bPhiOut[iPhi].reserve(nPoints);
2542 lPosOut[iPhi].reserve(nPoints);
2543 sectorOut[iPhi].reserve(nPoints);
2544 globalIdxOut[iPhi].reserve(nPoints);
2545 isOnPadPlane[iPhi].reserve(nPoints);
2547 std::mt19937 rng(std::random_device{}());
2548 DataT phiPos = iPhi * phiSpacing;
2549 for (
int iR = 0; iR < nRPoints; ++iR) {
2550 DataT rPos = getRMin(
side) + iR * rSpacing;
2551 for (
int iZ = 0; iZ < nZPoints; ++iZ) {
2552 DataT zPos = getZMin(
side) + iZ * zSpacing;
2554 phiPos += uniPhi(rng);
2555 o2::math_utils::detail::bringTo02PiGen<DataT>(phiPos);
2559 DataT density = getDensityCyl(zPos, rPos, phiPos,
side);
2560 DataT potential = getPotentialCyl(zPos, rPos, phiPos,
side);
2565 getDistortionsCyl(zPos, rPos, phiPos,
side, distZ, distR, distRPhi);
2570 getLocalDistortionsCyl(zPos, rPos, phiPos,
side, ldistZ, ldistR, ldistRPhi);
2578 const DataT zDistorted = zPos + distZ;
2579 const DataT radiusDistorted = rPos + distR;
2580 const DataT phiDistorted = regulatePhi(phiPos + distRPhi / rPos,
side);
2581 getCorrectionsCyl(zDistorted, radiusDistorted, phiDistorted,
side, corrZ, corrR, corrRPhi);
2582 corrRPhi *= rPos / radiusDistorted;
2587 getLocalCorrectionsCyl(zPos, rPos, phiPos,
side, lcorrZ, lcorrR, lcorrRPhi);
2593 getElectricFieldsCyl(zPos, rPos, phiPos,
side, eZ, eR, ePhi);
2596 const float x = getXFromPolar(rPos, phiPos);
2597 const float y = getYFromPolar(rPos, phiPos);
2600 const float bR = mBField.evalFieldR(zPos, rPos, phiPos);
2601 const float bZ = mBField.evalFieldZ(zPos, rPos, phiPos);
2602 const float bPhi = mBField.evalFieldPhi(zPos, rPos, phiPos);
2605 unsigned char secNum = std::floor(phiPos /
SECPHIWIDTH);
2609 phiPosOut[iPhi].emplace_back(phiPos);
2610 rPosOut[iPhi].emplace_back(rPos);
2611 zPosOut[iPhi].emplace_back(zPos);
2612 iPhiOut[iPhi].emplace_back(iPhi);
2613 iROut[iPhi].emplace_back(iR);
2614 iZOut[iPhi].emplace_back(iZ);
2615 if (mDensity[
side].getNDataPoints()) {
2616 densityOut[iPhi].emplace_back(density);
2618 if (mPotential[
side].getNDataPoints()) {
2619 potentialOut[iPhi].emplace_back(potential);
2621 if (mElectricFieldEr[
side].getNDataPoints()) {
2622 eZOut[iPhi].emplace_back(eZ);
2623 eROut[iPhi].emplace_back(eR);
2624 ePhiOut[iPhi].emplace_back(ePhi);
2626 if (mGlobalDistdR[
side].getNDataPoints()) {
2627 distZOut[iPhi].emplace_back(distZ);
2628 distROut[iPhi].emplace_back(distR);
2629 distRPhiOut[iPhi].emplace_back(distRPhi);
2631 if (mGlobalCorrdR[
side].getNDataPoints()) {
2632 corrZOut[iPhi].emplace_back(corrZ);
2633 corrROut[iPhi].emplace_back(corrR);
2634 corrRPhiOut[iPhi].emplace_back(corrRPhi);
2636 if (mLocalCorrdR[
side].getNDataPoints()) {
2637 lcorrZOut[iPhi].emplace_back(lcorrZ);
2638 lcorrROut[iPhi].emplace_back(lcorrR);
2639 lcorrRPhiOut[iPhi].emplace_back(lcorrRPhi);
2641 if (mLocalDistdR[
side].getNDataPoints()) {
2642 ldistZOut[iPhi].emplace_back(ldistZ);
2643 ldistROut[iPhi].emplace_back(ldistR);
2644 ldistRPhiOut[iPhi].emplace_back(ldistRPhi);
2646 xOut[iPhi].emplace_back(
x);
2647 yOut[iPhi].emplace_back(
y);
2648 bROut[iPhi].emplace_back(bR);
2649 bZOut[iPhi].emplace_back(bZ);
2650 bPhiOut[iPhi].emplace_back(bPhi);
2651 lPosOut[iPhi].emplace_back(lPos);
2652 sectorOut[iPhi].emplace_back(sector);
2653 const size_t idx = (iZ + nZPoints * (iR + iPhi * nRPoints));
2654 globalIdxOut[iPhi].emplace_back(idx);
2656 const float xDist = getXFromPolar(radiusDistorted, phiDistorted);
2657 const float yDist = getYFromPolar(radiusDistorted, phiDistorted);
2660 isOnPadPlane[iPhi].emplace_back(digiPadPos.
isValid());
2665 if (ROOT::IsImplicitMTEnabled() && (ROOT::GetThreadPoolSize() != sNThreads)) {
2666 ROOT::DisableImplicitMT();
2668 ROOT::EnableImplicitMT(sNThreads);
2669 ROOT::RDataFrame dFrame(nPhiPoints);
2672 auto dfStore = dFrame.DefineSlotEntry(
"x", [&xOut = xOut](
unsigned int, ULong64_t
entry) {
return xOut[
entry]; });
2673 dfStore = dfStore.DefineSlotEntry(
"y", [&yOut = yOut](
unsigned int, ULong64_t
entry) {
return yOut[
entry]; });
2674 dfStore = dfStore.DefineSlotEntry(
"phi", [&phiPosOut = phiPosOut](
unsigned int, ULong64_t
entry) {
return phiPosOut[
entry]; });
2675 dfStore = dfStore.DefineSlotEntry(
"r", [&rPosOut = rPosOut](
unsigned int, ULong64_t
entry) {
return rPosOut[
entry]; });
2676 dfStore = dfStore.DefineSlotEntry(
"z", [&zPosOut = zPosOut](
unsigned int, ULong64_t
entry) {
return zPosOut[
entry]; });
2677 dfStore = dfStore.DefineSlotEntry(
"iPhi", [&iPhiOut = iPhiOut](
unsigned int, ULong64_t
entry) {
return iPhiOut[
entry]; });
2678 dfStore = dfStore.DefineSlotEntry(
"iR", [&iROut = iROut](
unsigned int, ULong64_t
entry) {
return iROut[
entry]; });
2679 dfStore = dfStore.DefineSlotEntry(
"iZ", [&iZOut = iZOut](
unsigned int, ULong64_t
entry) {
return iZOut[
entry]; });
2680 dfStore = dfStore.DefineSlotEntry(
"lPos", [&lPosOut = lPosOut](
unsigned int, ULong64_t
entry) {
return lPosOut[
entry]; });
2681 dfStore = dfStore.DefineSlotEntry(
"sector", [§orOut = sectorOut](
unsigned int, ULong64_t
entry) {
return sectorOut[
entry]; });
2682 dfStore = dfStore.DefineSlotEntry(
"scdensity", [&densityOut = densityOut](
unsigned int, ULong64_t
entry) {
return densityOut[
entry]; });
2683 dfStore = dfStore.DefineSlotEntry(
"potential", [&potentialOut = potentialOut](
unsigned int, ULong64_t
entry) {
return potentialOut[
entry]; });
2684 dfStore = dfStore.DefineSlotEntry(
"eZ", [&eZOut = eZOut](
unsigned int, ULong64_t
entry) {
return eZOut[
entry]; });
2685 dfStore = dfStore.DefineSlotEntry(
"eR", [&eROut = eROut](
unsigned int, ULong64_t
entry) {
return eROut[
entry]; });
2686 dfStore = dfStore.DefineSlotEntry(
"ePhi", [&ePhiOut = ePhiOut](
unsigned int, ULong64_t
entry) {
return ePhiOut[
entry]; });
2687 dfStore = dfStore.DefineSlotEntry(
"distZ", [&distZOut = distZOut](
unsigned int, ULong64_t
entry) {
return distZOut[
entry]; });
2688 dfStore = dfStore.DefineSlotEntry(
"distR", [&distROut = distROut](
unsigned int, ULong64_t
entry) {
return distROut[
entry]; });
2689 dfStore = dfStore.DefineSlotEntry(
"distRPhi", [&distRPhiOut = distRPhiOut](
unsigned int, ULong64_t
entry) {
return distRPhiOut[
entry]; });
2690 dfStore = dfStore.DefineSlotEntry(
"corrZ", [&corrZOut = corrZOut](
unsigned int, ULong64_t
entry) {
return corrZOut[
entry]; });
2691 dfStore = dfStore.DefineSlotEntry(
"corrR", [&corrROut = corrROut](
unsigned int, ULong64_t
entry) {
return corrROut[
entry]; });
2692 dfStore = dfStore.DefineSlotEntry(
"corrRPhi", [&corrRPhiOut = corrRPhiOut](
unsigned int, ULong64_t
entry) {
return corrRPhiOut[
entry]; });
2693 dfStore = dfStore.DefineSlotEntry(
"lcorrZ", [&lcorrZOut = lcorrZOut](
unsigned int, ULong64_t
entry) {
return lcorrZOut[
entry]; });
2694 dfStore = dfStore.DefineSlotEntry(
"lcorrR", [&lcorrROut = lcorrROut](
unsigned int, ULong64_t
entry) {
return lcorrROut[
entry]; });
2695 dfStore = dfStore.DefineSlotEntry(
"lcorrRPhi", [&lcorrRPhiOut = lcorrRPhiOut](
unsigned int, ULong64_t
entry) {
return lcorrRPhiOut[
entry]; });
2696 dfStore = dfStore.DefineSlotEntry(
"ldistZ", [&ldistZOut = ldistZOut](
unsigned int, ULong64_t
entry) {
return ldistZOut[
entry]; });
2697 dfStore = dfStore.DefineSlotEntry(
"ldistR", [&ldistROut = ldistROut](
unsigned int, ULong64_t
entry) {
return ldistROut[
entry]; });
2698 dfStore = dfStore.DefineSlotEntry(
"ldistRPhi", [&ldistRPhiOut = ldistRPhiOut](
unsigned int, ULong64_t
entry) {
return ldistRPhiOut[
entry]; });
2699 dfStore = dfStore.DefineSlotEntry(
"bR", [&bROut = bROut](
unsigned int, ULong64_t
entry) {
return bROut[
entry]; });
2700 dfStore = dfStore.DefineSlotEntry(
"bZ", [&bZOut = bZOut](
unsigned int, ULong64_t
entry) {
return bZOut[
entry]; });
2701 dfStore = dfStore.DefineSlotEntry(
"bPhi", [&bPhiOut = bPhiOut](
unsigned int, ULong64_t
entry) {
return bPhiOut[
entry]; });
2702 dfStore = dfStore.DefineSlotEntry(
"globalIndex", [&globalIdxOut = globalIdxOut](
unsigned int, ULong64_t
entry) {
return globalIdxOut[
entry]; });
2703 dfStore = dfStore.DefineSlotEntry(
"isOnPadPlane", [&isOnPadPlane = isOnPadPlane](
unsigned int, ULong64_t
entry) {
return isOnPadPlane[
entry]; });
2704 dfStore.Snapshot(
"tree", outFileName);
2708template <
typename DataT>
2712 const DataT zSpacing = (
side ==
Side::A) ? GridProp::getGridSpacingZ(nZPoints) : -GridProp::getGridSpacingZ(nZPoints);
2716 std::vector<std::vector<float>> phiPosOut(nZPoints);
2717 std::vector<std::vector<float>> rPosOut(nZPoints);
2718 std::vector<std::vector<float>> zPosOut(nZPoints);
2719 std::vector<std::vector<int>> rowOut(nZPoints);
2720 std::vector<std::vector<float>> lxOut(nZPoints);
2721 std::vector<std::vector<float>> lyOut(nZPoints);
2722 std::vector<std::vector<float>> xOut(nZPoints);
2723 std::vector<std::vector<float>> yOut(nZPoints);
2724 std::vector<std::vector<float>> corrZOut(nZPoints);
2725 std::vector<std::vector<float>> corrROut(nZPoints);
2726 std::vector<std::vector<float>> corrRPhiOut(nZPoints);
2727 std::vector<std::vector<float>> erOut(nZPoints);
2728 std::vector<std::vector<float>> ezOut(nZPoints);
2729 std::vector<std::vector<float>> ephiOut(nZPoints);
2730 std::vector<std::vector<float>> potentialOut(nZPoints);
2731 std::vector<std::vector<int>> izOut(nZPoints);
2732 std::vector<std::vector<size_t>> globalIdxOut(nZPoints);
2734#pragma omp parallel for num_threads(sNThreads)
2735 for (
int iZ = 0; iZ < nZPoints; ++iZ) {
2736 phiPosOut[iZ].reserve(nPads);
2737 rPosOut[iZ].reserve(nPads);
2738 zPosOut[iZ].reserve(nPads);
2739 corrZOut[iZ].reserve(nPads);
2740 corrROut[iZ].reserve(nPads);
2741 corrRPhiOut[iZ].reserve(nPads);
2742 rowOut[iZ].reserve(nPads);
2743 lxOut[iZ].reserve(nPads);
2744 lyOut[iZ].reserve(nPads);
2745 xOut[iZ].reserve(nPads);
2746 yOut[iZ].reserve(nPads);
2747 erOut[iZ].reserve(nPads);
2748 ezOut[iZ].reserve(nPads);
2749 ephiOut[iZ].reserve(nPads);
2750 izOut[iZ].reserve(nPads);
2751 potentialOut[iZ].reserve(nPads);
2752 globalIdxOut[iZ].reserve(nPads);
2754 DataT zPos = getZMin(
side) + iZ * zSpacing;
2760 auto lx = padcentre.X();
2761 auto ly = padcentre.Y();
2764 auto x = globalPos.X();
2765 auto y = globalPos.Y();
2767 auto r = getRadiusFromCartesian(
x,
y);
2768 auto phi = getPhiFromCartesian(
x,
y);
2772 getCorrectionsCyl(zPos,
r, phi,
side, corrZ, corrR, corrRPhi);
2777 getElectricFieldsCyl(zPos,
r, phi,
side, eZ, eR, ePhi);
2779 potentialOut[iZ].emplace_back(getPotentialCyl(zPos,
r, phi,
side));
2780 erOut[iZ].emplace_back(eR);
2781 ezOut[iZ].emplace_back(eZ);
2782 ephiOut[iZ].emplace_back(ePhi);
2783 phiPosOut[iZ].emplace_back(phi);
2784 rPosOut[iZ].emplace_back(
r);
2785 zPosOut[iZ].emplace_back(zPos);
2786 corrZOut[iZ].emplace_back(corrZ);
2787 corrROut[iZ].emplace_back(corrR);
2788 corrRPhiOut[iZ].emplace_back(corrRPhi);
2790 lxOut[iZ].emplace_back(lx);
2791 lyOut[iZ].emplace_back(ly);
2792 xOut[iZ].emplace_back(
x);
2793 yOut[iZ].emplace_back(
y);
2794 izOut[iZ].emplace_back(iZ);
2796 globalIdxOut[iZ].emplace_back(idx);
2802 if (ROOT::IsImplicitMTEnabled() && (ROOT::GetThreadPoolSize() != sNThreads)) {
2803 ROOT::DisableImplicitMT();
2805 ROOT::EnableImplicitMT(sNThreads);
2806 ROOT::RDataFrame dFrame(nZPoints);
2809 auto dfStore = dFrame.DefineSlotEntry(
"phi", [&phiPosOut = phiPosOut](
unsigned int, ULong64_t
entry) {
return phiPosOut[
entry]; });
2810 dfStore = dfStore.DefineSlotEntry(
"r", [&rPosOut = rPosOut](
unsigned int, ULong64_t
entry) {
return rPosOut[
entry]; });
2811 dfStore = dfStore.DefineSlotEntry(
"z", [&zPosOut = zPosOut](
unsigned int, ULong64_t
entry) {
return zPosOut[
entry]; });
2812 dfStore = dfStore.DefineSlotEntry(
"iz", [&izOut = izOut](
unsigned int, ULong64_t
entry) {
return izOut[
entry]; });
2813 dfStore = dfStore.DefineSlotEntry(
"corrZ", [&corrZOut = corrZOut](
unsigned int, ULong64_t
entry) {
return corrZOut[
entry]; });
2814 dfStore = dfStore.DefineSlotEntry(
"corrR", [&corrROut = corrROut](
unsigned int, ULong64_t
entry) {
return corrROut[
entry]; });
2815 dfStore = dfStore.DefineSlotEntry(
"corrRPhi", [&corrRPhiOut = corrRPhiOut](
unsigned int, ULong64_t
entry) {
return corrRPhiOut[
entry]; });
2816 dfStore = dfStore.DefineSlotEntry(
"row", [&rowOut = rowOut](
unsigned int, ULong64_t
entry) {
return rowOut[
entry]; });
2817 dfStore = dfStore.DefineSlotEntry(
"lx", [&lxOut = lxOut](
unsigned int, ULong64_t
entry) {
return lxOut[
entry]; });
2818 dfStore = dfStore.DefineSlotEntry(
"ly", [&lyOut = lyOut](
unsigned int, ULong64_t
entry) {
return lyOut[
entry]; });
2819 dfStore = dfStore.DefineSlotEntry(
"x", [&xOut = xOut](
unsigned int, ULong64_t
entry) {
return xOut[
entry]; });
2820 dfStore = dfStore.DefineSlotEntry(
"y", [&yOut = yOut](
unsigned int, ULong64_t
entry) {
return yOut[
entry]; });
2821 dfStore = dfStore.DefineSlotEntry(
"er", [&erOut = erOut](
unsigned int, ULong64_t
entry) {
return erOut[
entry]; });
2822 dfStore = dfStore.DefineSlotEntry(
"ez", [&ezOut = ezOut](
unsigned int, ULong64_t
entry) {
return ezOut[
entry]; });
2823 dfStore = dfStore.DefineSlotEntry(
"ephi", [&ephiOut = ephiOut](
unsigned int, ULong64_t
entry) {
return ephiOut[
entry]; });
2824 dfStore = dfStore.DefineSlotEntry(
"potential", [&potentialOut = potentialOut](
unsigned int, ULong64_t
entry) {
return potentialOut[
entry]; });
2825 dfStore = dfStore.DefineSlotEntry(
"globalIndex", [&globalIdxOut = globalIdxOut](
unsigned int, ULong64_t
entry) {
return globalIdxOut[
entry]; });
2826 dfStore.Snapshot(
"tree", outFileName);
2830template <
typename DataT>
2833 const auto deltaPhi = histoIonsPhiRZ.GetXaxis()->GetBinWidth(1);
2834 const auto deltaZ = histoIonsPhiRZ.GetZaxis()->GetBinWidth(1);
2836 for (
int ir = 1;
ir <= histoIonsPhiRZ.GetNbinsY(); ++
ir) {
2837 const auto r0 = histoIonsPhiRZ.GetYaxis()->GetBinLowEdge(
ir);
2838 const auto r1 = histoIonsPhiRZ.GetYaxis()->GetBinUpEdge(
ir);
2839 const auto norm = fac * (r1 * r1 - r0 * r0);
2840 for (
int iphi = 1; iphi <= histoIonsPhiRZ.GetNbinsX(); ++iphi) {
2841 for (
int iz = 1; iz <= histoIonsPhiRZ.GetNbinsZ(); ++iz) {
2842 const auto charge = histoIonsPhiRZ.GetBinContent(iphi,
ir, iz);
2843 histoIonsPhiRZ.SetBinContent(iphi,
ir, iz,
charge / norm);
2849template <
typename DataT>
2852 if (!mAnaDistCorr.isValid()) {
2853 LOGP(info,
"============== analytical functions are not set! returning ==============");
2856 bool isOK = outf.WriteObject(&mAnaDistCorr,
"analyticalDistCorr");
2860template <
typename DataT>
2863 TFile fIn(inpf.data(),
"READ");
2864 const bool containsFormulas = fIn.GetListOfKeys()->Contains(
"analyticalDistCorr");
2865 if (!containsFormulas) {
2866 LOGP(info,
"============== analytical functions are not stored! returning ==============");
2869 LOGP(info,
"Using analytical corrections and distortions");
2870 setUseAnalyticalDistCorr(
true);
2872 mAnaDistCorr = *form;
2876template <
typename DataT>
2880 ddR = mC0 * localIntErOverEz + mC1 * localIntEPhiOverEz;
2881 ddPhi = (mC0 * localIntEPhiOverEz - mC1 * localIntErOverEz) / radius;
2885template <
typename DataT>
2889 ddR = mC2 * localIntBrOverBz - mC1 * localIntBPhiOverBz;
2890 ddPhi = (mC2 * localIntBPhiOverBz + mC1 * localIntBrOverBz) / radius;
2893template <
typename DataT>
2896 const std::unordered_map<int, std::pair<int, int>> field_to_current = {{2, {12000, 6000}},
2898 {-2, {-12000, -6000}},
2899 {-5, {-30000, -6000}},
2901 auto currents_iter = field_to_current.find(field);
2902 if (currents_iter == field_to_current.end()) {
2903 LOG(error) <<
" Could not lookup currents for fieldvalue " << field;
2906 mBField.setBField(field);
2910 setBFields(magField);
2913template <
typename DataT>
2918 float vDrift = gasParam.DriftV;
2919 const float omegaTau = -10. * bzField * vDrift / std::abs(getEzField(
Side::A));
2920 LOGP(detail,
"Setting omegaTau to {} for {}kG", omegaTau, bzField);
2921 const float t1 = 1.;
2922 const float t2 = 1.;
2923 setOmegaTauT1T2(omegaTau,
t1, t2);
2926template <
typename DataT>
2927template <
typename Fields>
2932 DataT localIntErOverEz = 0;
2933 DataT localIntEPhiOverEz = 0;
2934 DataT localIntDeltaEz = 0;
2936 DataT localIntBrOverBz = 0;
2937 DataT localIntBPhiOverBz = 0;
2938 DataT localIntDeltaBz = 0;
2943 switch (sNumericalIntegrationStrategy) {
2944 case IntegrationStrategy::SimpsonIterative:
2945 for (
int i = 0;
i < sSimpsonNIteratives; ++
i) {
2946 const DataT tmpZ = localDistCorr ? (p2z + ddZ) : regulateZ(p2z + ddZ, formulaStruct.getSide());
2947 if (mSimEDistortions) {
2948 integrateEFieldsSimpsonIterative(p1r, p1r + ddR + ddRExB, p1phi, p1phi + ddPhi + ddPhiExB, p1z, tmpZ, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2949 langevinCylindricalE(ddR, ddPhi, ddZ, (p1r + 0.5 * (ddR + ddRExB)), localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2951 if (mSimExBMisalignment) {
2952 integrateEFieldsSimpsonIterative(p1r, p1r + ddR + ddRExB, p1phi, p1phi + ddPhi + ddPhiExB, p1z, tmpZ, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2953 langevinCylindricalB(ddRExB, ddPhiExB, (p1r + 0.5 * (ddR + ddRExB)), localIntBrOverBz, localIntBPhiOverBz);
2957 case IntegrationStrategy::Simpson:
2958 if (mSimEDistortions) {
2959 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2960 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2962 if (mSimExBMisalignment) {
2963 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2964 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2967 case IntegrationStrategy::Trapezoidal:
2968 if (mSimEDistortions) {
2969 integrateEFieldsTrapezoidal(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2970 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2972 if (mSimExBMisalignment) {
2973 integrateEFieldsTrapezoidal(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2974 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2977 case IntegrationStrategy::Root:
2978 if (mSimEDistortions) {
2979 integrateEFieldsRoot(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2980 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2982 if (mSimExBMisalignment) {
2983 integrateEFieldsRoot(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2984 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2988 if (mSimEDistortions) {
2989 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2990 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2992 if (mSimExBMisalignment) {
2993 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2994 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2999 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_calcDistCorr",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_calcDistCorr").data()
3000 <<
"p1r=" << (*
const_cast<DataT*
>(&p1r))
3001 <<
"p1phi=" << (*
const_cast<DataT*
>(&p1phi))
3002 <<
"p1z=" << (*
const_cast<DataT*
>(&p1z))
3003 <<
"p2z=" << (*
const_cast<DataT*
>(&p2z))
3004 <<
"localIntErOverEz=" << localIntErOverEz
3005 <<
"localIntEPhiOverEz=" << localIntEPhiOverEz
3006 <<
"localIntDeltaEz=" << localIntDeltaEz
3008 <<
"ddPhi=" << ddPhi
3010 <<
"localIntBrOverBz=" << localIntBrOverBz
3011 <<
"localIntBPhiOverBz=" << localIntBPhiOverBz
3012 <<
"localIntDeltaBz=" << localIntDeltaBz
3013 <<
"ddRExB=" << ddRExB
3014 <<
"ddPhiExB=" << ddPhiExB
3022template <
typename DataT>
3025 if (!mElectricFieldEr[
side].getNDataPoints()) {
3026 LOGP(info,
"============== E-Fields are not set! returning ==============");
3029 const std::string sideName = getSideName(
side);
3030 const int er = mElectricFieldEr[
side].writeToFile(
file, option, fmt::format(
"fieldEr_side{}", sideName), sNThreads);
3031 const int ez = mElectricFieldEz[
side].writeToFile(
file,
"UPDATE", fmt::format(
"fieldEz_side{}", sideName), sNThreads);
3032 const int ephi = mElectricFieldEphi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"fieldEphi_side{}", sideName), sNThreads);
3033 dumpMetaData(
file,
"UPDATE",
false);
3034 return er + ez + ephi;
3037template <
typename DataT>
3040 const std::string sideName = getSideName(
side);
3041 std::string_view treeEr{fmt::format(
"fieldEr_side{}", sideName)};
3042 if (!checkGridFromFile(
file, treeEr)) {
3045 initContainer(mElectricFieldEr[
side],
true);
3046 initContainer(mElectricFieldEz[
side],
true);
3047 initContainer(mElectricFieldEphi[
side],
true);
3048 mElectricFieldEr[
side].initFromFile(
file, treeEr, sNThreads);
3049 mElectricFieldEz[
side].initFromFile(
file, fmt::format(
"fieldEz_side{}", sideName), sNThreads);
3050 mElectricFieldEphi[
side].initFromFile(
file, fmt::format(
"fieldEphi_side{}", sideName), sNThreads);
3054template <
typename DataT>
3057 if (!mGlobalDistdR[
side].getNDataPoints()) {
3058 LOGP(info,
"============== global distortions are not set! returning ==============");
3061 const std::string sideName = getSideName(
side);
3062 const int er = mGlobalDistdR[
side].writeToFile(
file, option, fmt::format(
"distR_side{}", sideName), sNThreads);
3063 const int ez = mGlobalDistdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"distZ_side{}", sideName), sNThreads);
3064 const int ephi = mGlobalDistdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"distRphi_side{}", sideName), sNThreads);
3065 dumpMetaData(
file,
"UPDATE",
false);
3066 return er + ez + ephi;
3069template <
typename DataT>
3072 const std::string sideName = getSideName(
side);
3073 std::string_view
tree{fmt::format(
"distR_side{}", sideName)};
3074 if (!checkGridFromFile(
file,
tree)) {
3077 initContainer(mGlobalDistdR[
side],
true);
3078 initContainer(mGlobalDistdZ[
side],
true);
3079 initContainer(mGlobalDistdRPhi[
side],
true);
3080 mGlobalDistdR[
side].initFromFile(
file,
tree, sNThreads);
3081 mGlobalDistdZ[
side].initFromFile(
file, fmt::format(
"distZ_side{}", sideName), sNThreads);
3082 mGlobalDistdRPhi[
side].initFromFile(
file, fmt::format(
"distRphi_side{}", sideName), sNThreads);
3086template <
typename DataT>
3087template <
typename DataTIn>
3090 initContainer(mGlobalDistdR[
side],
false);
3091 initContainer(mGlobalDistdZ[
side],
false);
3092 initContainer(mGlobalDistdRPhi[
side],
false);
3093 const std::string sideName = getSideName(
side);
3094 mGlobalDistdR[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distR_side{}", sideName).
data());
3095 mGlobalDistdZ[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distZ_side{}", sideName).
data());
3096 mGlobalDistdRPhi[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distRphi_side{}", sideName).
data());
3099template <
typename DataT>
3102 if (!mGlobalCorrdR[
side].getNDataPoints()) {
3103 LOGP(info,
"============== global corrections are not set! returning ==============");
3106 const std::string sideName = getSideName(
side);
3107 const int er = mGlobalCorrdR[
side].writeToFile(
file, option, fmt::format(
"corrR_side{}", sideName), sNThreads);
3108 const int ez = mGlobalCorrdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"corrZ_side{}", sideName), sNThreads);
3109 const int ephi = mGlobalCorrdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"corrRPhi_side{}", sideName), sNThreads);
3110 dumpMetaData(
file,
"UPDATE",
false);
3111 return er + ez + ephi;
3114template <
typename DataT>
3117 const std::string sideName = getSideName(
side);
3118 const std::string_view treename{fmt::format(
"corrR_side{}", getSideName(
side))};
3119 if (!checkGridFromFile(
file, treename)) {
3123 initContainer(mGlobalCorrdR[
side],
true);
3124 initContainer(mGlobalCorrdZ[
side],
true);
3125 initContainer(mGlobalCorrdRPhi[
side],
true);
3126 mGlobalCorrdR[
side].initFromFile(
file, treename, sNThreads);
3127 mGlobalCorrdZ[
side].initFromFile(
file, fmt::format(
"corrZ_side{}", sideName), sNThreads);
3128 mGlobalCorrdRPhi[
side].initFromFile(
file, fmt::format(
"corrRPhi_side{}", sideName), sNThreads);
3132template <
typename DataT>
3133template <
typename DataTIn>
3136 initContainer(mGlobalCorrdR[
side],
false);
3137 initContainer(mGlobalCorrdZ[
side],
false);
3138 initContainer(mGlobalCorrdRPhi[
side],
false);
3139 const std::string sideName = getSideName(
side);
3140 mGlobalCorrdR[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrR_side{}", sideName).
data());
3141 mGlobalCorrdZ[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrZ_side{}", sideName).
data());
3142 mGlobalCorrdRPhi[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrRPhi_side{}", sideName).
data());
3145template <
typename DataT>
3148 if (!mLocalCorrdR[
side].getNDataPoints()) {
3149 LOGP(info,
"============== local corrections are not set! returning ==============");
3152 const std::string sideName = getSideName(
side);
3153 const int lCorrdR = mLocalCorrdR[
side].writeToFile(
file, option, fmt::format(
"lcorrR_side{}", sideName), sNThreads);
3154 const int lCorrdZ = mLocalCorrdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lcorrZ_side{}", sideName), sNThreads);
3155 const int lCorrdRPhi = mLocalCorrdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lcorrRPhi_side{}", sideName), sNThreads);
3156 dumpMetaData(
file,
"UPDATE",
false);
3157 return lCorrdR + lCorrdZ + lCorrdRPhi;
3160template <
typename DataT>
3163 const std::string sideName = getSideName(
side);
3164 const std::string_view treename{fmt::format(
"lcorrR_side{}", getSideName(
side))};
3165 if (!checkGridFromFile(
file, treename)) {
3168 initContainer(mLocalCorrdR[
side],
true);
3169 initContainer(mLocalCorrdZ[
side],
true);
3170 initContainer(mLocalCorrdRPhi[
side],
true);
3171 const bool lCorrdR = mLocalCorrdR[
side].initFromFile(
file, treename, sNThreads);
3172 const bool lCorrdZ = mLocalCorrdZ[
side].initFromFile(
file, fmt::format(
"lcorrZ_side{}", sideName), sNThreads);
3173 const bool lCorrdRPhi = mLocalCorrdRPhi[
side].initFromFile(
file, fmt::format(
"lcorrRPhi_side{}", sideName), sNThreads);
3177template <
typename DataT>
3180 if (!mLocalDistdR[
side].getNDataPoints()) {
3181 LOGP(info,
"============== local distortions are not set! returning ==============");
3184 const std::string sideName = getSideName(
side);
3185 const int lDistdR = mLocalDistdR[
side].writeToFile(
file, option, fmt::format(
"ldistR_side{}", sideName), sNThreads);
3186 const int lDistdZ = mLocalDistdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"ldistZ_side{}", sideName), sNThreads);
3187 const int lDistdRPhi = mLocalDistdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"ldistRPhi_side{}", sideName), sNThreads);
3188 dumpMetaData(
file,
"UPDATE",
false);
3189 return lDistdR + lDistdZ + lDistdRPhi;
3192template <
typename DataT>
3195 if (!mLocalVecDistdR[
side].getNDataPoints()) {
3196 LOGP(info,
"============== local distortion vectors are not set! returning ==============");
3199 const std::string sideName = getSideName(
side);
3200 const int lVecDistdR = mLocalVecDistdR[
side].writeToFile(
file, option, fmt::format(
"lvecdistR_side{}", sideName), sNThreads);
3201 const int lVecDistdZ = mLocalVecDistdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lvecdistZ_side{}", sideName), sNThreads);
3202 const int lVecDistdRPhi = mLocalVecDistdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lvecdistRPhi_side{}", sideName), sNThreads);
3203 dumpMetaData(
file,
"UPDATE",
false);
3204 return lVecDistdR + lVecDistdZ + lVecDistdRPhi;
3207template <
typename DataT>
3210 const std::string sideName = getSideName(
side);
3211 const std::string_view treename{fmt::format(
"ldistR_side{}", getSideName(
side))};
3212 if (!checkGridFromFile(
file, treename)) {
3215 initContainer(mLocalDistdR[
side],
true);
3216 initContainer(mLocalDistdZ[
side],
true);
3217 initContainer(mLocalDistdRPhi[
side],
true);
3218 const bool lDistdR = mLocalDistdR[
side].initFromFile(
file, treename, sNThreads);
3219 const bool lDistdZ = mLocalDistdZ[
side].initFromFile(
file, fmt::format(
"ldistZ_side{}", sideName), sNThreads);
3220 const bool lDistdRPhi = mLocalDistdRPhi[
side].initFromFile(
file, fmt::format(
"ldistRPhi_side{}", sideName), sNThreads);
3224template <
typename DataT>
3227 const std::string sideName = getSideName(
side);
3228 const std::string_view treename{fmt::format(
"lvecdistR_side{}", getSideName(
side))};
3229 if (!checkGridFromFile(
file, treename)) {
3232 initContainer(mLocalVecDistdR[
side],
true);
3233 initContainer(mLocalVecDistdZ[
side],
true);
3234 initContainer(mLocalVecDistdRPhi[
side],
true);
3235 const bool lVecDistdR = mLocalVecDistdR[
side].initFromFile(
file, treename, sNThreads);
3236 const bool lVecDistdZ = mLocalVecDistdZ[
side].initFromFile(
file, fmt::format(
"lvecdistZ_side{}", sideName), sNThreads);
3237 const bool lVecDistdRPhi = mLocalVecDistdRPhi[
side].initFromFile(
file, fmt::format(
"lvecdistRPhi_side{}", sideName), sNThreads);
3241template <
typename DataT>
3244 if (!mPotential[
side].getNDataPoints()) {
3245 LOGP(info,
"============== potential not set! returning ==============");
3248 int status = mPotential[
side].writeToFile(
file, option, fmt::format(
"potential_side{}", getSideName(
side)), sNThreads);
3249 dumpMetaData(
file,
"UPDATE",
false);
3253template <
typename DataT>
3256 const std::string_view treename{fmt::format(
"potential_side{}", getSideName(
side))};
3257 if (!checkGridFromFile(
file, treename)) {
3260 initContainer(mPotential[
side],
true);
3261 mPotential[
side].initFromFile(
file, treename, sNThreads);
3265template <
typename DataT>
3268 if (!mDensity[
side].getNDataPoints()) {
3269 LOGP(info,
"============== space charge density are not set! returning ==============");
3272 int status = mDensity[
side].writeToFile(
file, option, fmt::format(
"density_side{}", getSideName(
side)), sNThreads);
3273 dumpMetaData(
file,
"UPDATE",
false);
3277template <
typename DataT>
3280 unsigned short nr, nz, nphi;
3281 if (!DataContainer::getVertices(
tree,
file, nr, nz, nphi)) {
3286 if ((mParamGrid.NRVertices != nr) || (mParamGrid.NZVertices != nz) || (mParamGrid.NPhiVertices != nphi)) {
3287 LOGP(info,
"Different number of vertices found in input file. Initializing new space charge object with nR {} nZ {} nPhi {} vertices", nr, nz, nphi);
3292 *
this = std::move(scTmp);
3297template <
typename DataT>
3300 const std::string_view treename{fmt::format(
"density_side{}", getSideName(
side))};
3301 if (!checkGridFromFile(
file, treename)) {
3304 initContainer(mDensity[
side],
true);
3305 mDensity[
side].initFromFile(
file, treename, sNThreads);
3309template <
typename DataT>
3312 if (!mGlobalCorrdR[
side].getNDataPoints()) {
3313 LOGP(info,
"============== global corrections are not set! returning ==============");
3316 const std::string sideName = getSideName(
side);
3317 const int er = mGlobalCorrdR[
side].template writeToFile<float>(outf, fmt::format(
"corrR_side{}", sideName).
data());
3318 const int ez = mGlobalCorrdZ[
side].template writeToFile<float>(outf, fmt::format(
"corrZ_side{}", sideName).
data());
3319 const int ephi = mGlobalCorrdRPhi[
side].template writeToFile<float>(outf, fmt::format(
"corrRPhi_side{}", sideName).
data());
3320 return er + ez + ephi;
3323template <
typename DataT>
3326 if (option ==
"RECREATE") {
3328 gSystem->Unlink(
file.data());
3330 dumpElectricFields(
file,
side,
"UPDATE");
3331 dumpPotential(
file,
side,
"UPDATE");
3333 dumpGlobalDistortions(
file,
side,
"UPDATE");
3334 dumpGlobalCorrections(
file,
side,
"UPDATE");
3335 dumpLocalCorrections(
file,
side,
"UPDATE");
3336 dumpLocalDistortions(
file,
side,
"UPDATE");
3337 dumpLocalDistCorrVectors(
file,
side,
"UPDATE");
3340template <
typename DataT>
3347template <
typename DataT>
3350 TFile
f(
file.data(), option.data());
3351 if (!overwriteExisting &&
f.GetListOfKeys()->Contains(
"meta")) {
3357 std::vector<float>
params{
static_cast<float>(mC0),
static_cast<float>(mC1),
static_cast<float>(mC2)};
3358 auto helperA = mGrid3D[
Side::A].getHelper();
3359 auto helperC = mGrid3D[
Side::C].getHelper();
3362 ROOT::RDataFrame dFrame(1);
3363 auto dfStore = dFrame.DefineSlotEntry(
"paramsC", [&
params =
params](
unsigned int, ULong64_t
entry) {
return params; });
3364 dfStore = dfStore.DefineSlotEntry(
"grid_A", [&helperA = helperA](
unsigned int, ULong64_t
entry) {
return helperA; });
3365 dfStore = dfStore.DefineSlotEntry(
"grid_C", [&helperC = helperC](
unsigned int, ULong64_t
entry) {
return helperC; });
3366 dfStore = dfStore.DefineSlotEntry(
"BField", [field = mBField.getBField()](
unsigned int, ULong64_t
entry) { return field; });
3367 dfStore = dfStore.DefineSlotEntry(
"metaInf", [meta = mMeta](
unsigned int, ULong64_t
entry) {
return meta; });
3370 ROOT::RDF::RSnapshotOptions opt;
3372 opt.fOverwriteIfExists =
true;
3373 dfStore.Snapshot(
"meta",
file, {
"paramsC",
"grid_A",
"grid_C",
"BField",
"metaInf"}, opt);
3376template <
typename DataT>
3379 if (mReadMetaData) {
3384 TFile
f(
file.data(),
"READ");
3385 if (!
f.GetListOfKeys()->Contains(
"meta")) {
3394 mGrid3D[
Side::A] =
RegularGrid3D<DataT>(gridA.zmin, gridA.rmin, gridA.phimin, gridA.spacingZ, gridA.spacingR, gridA.spacingPhi, gridA.params);
3395 mGrid3D[
Side::C] =
RegularGrid3D<DataT>(gridC.zmin, gridC.rmin, gridC.phimin, gridC.spacingZ, gridC.spacingR, gridC.spacingPhi, gridC.params);
3396 mBField.setBField(field);
3399 ROOT::RDataFrame dFrame(
"meta",
file);
3400 dFrame.Foreach(readMeta, {
"paramsC",
"grid_A",
"grid_C",
"BField"});
3402 const auto&
cols = dFrame.GetColumnNames();
3403 if (std::find(
cols.begin(),
cols.end(),
"metaInf") !=
cols.end()) {
3404 auto readMetaInf = [&mMeta = mMeta](
const SCMetaData& meta) {
3407 dFrame.Foreach(readMetaInf, {
"metaInf"});
3410 LOGP(info,
"Setting meta data: mC0={} mC1={} mC2={}", mC0, mC1, mC2);
3411 mReadMetaData =
true;
3414template <
typename DataT>
3417 LOGP(warning,
"Use this feature only if you know what you are doing!");
3419 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},
3420 {GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(
Side::C) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) /
SECTORSPERSIDE * nSectors, mParamGrid}};
3421 mGrid3D[0] = gridTmp[0];
3422 mGrid3D[1] = gridTmp[1];
3425template <
typename DataT>
3431template <
typename DataT>
3436 setElectricFieldsFromFile(
file,
side);
3437 setLocalDistortionsFromFile(
file,
side);
3438 setLocalCorrectionsFromFile(
file,
side);
3439 setGlobalDistortionsFromFile(
file,
side);
3440 setGlobalCorrectionsFromFile(
file,
side);
3441 setLocalDistCorrVectorsFromFile(
file,
side);
3444template <
typename DataT>
3451template <
typename DataT>
3454 if (!
data.getNDataPoints()) {
3455 data.setGrid(getNZVertices(), getNRVertices(), getNPhiVertices(), initMem);
3459template <
typename DataT>
3462 const DataT wt0 = t2 * omegaTau;
3463 const DataT wt02 = wt0 * wt0;
3464 mC0 = 1 / (1 + wt02);
3465 const DataT wt1 =
t1 * omegaTau;
3466 mC1 = wt1 / (1 + wt1 * wt1);
3467 mC2 = wt02 / (1 + wt02);
3470template <
typename DataT>
3475 LOGP(warning,
"Space charge objects have different grid definition");
3483template <
typename DataT>
3488 LOGP(warning,
"Space charge objects have different grid definition");
3492 mGlobalCorrdR[
side] += otherSC.mGlobalCorrdR[
side];
3493 mGlobalCorrdZ[
side] += otherSC.mGlobalCorrdZ[
side];
3494 mGlobalCorrdRPhi[
side] += otherSC.mGlobalCorrdRPhi[
side];
3497template <
typename DataT>
3500 TFile fInp(
file,
"READ");
3501 TH3F* hSCA = (TH3F*)fInp.Get(nameA);
3502 TH3F* hSCC = (TH3F*)fInp.Get(nameC);
3504 LOGP(error,
"Histogram {} not found", nameA);
3507 LOGP(error,
"Histogram {} not found", nameC);
3509 fillChargeDensityFromHisto(*hSCA, *hSCC);
3512template <
typename DataT>
3515 const int nPhiBinsTmp = hisSCDensity3D_A.GetXaxis()->GetNbins();
3516 const int nRBinsTmp = hisSCDensity3D_A.GetYaxis()->GetNbins();
3517 const int nZBins = hisSCDensity3D_A.GetZaxis()->GetNbins();
3518 const auto phiLow = hisSCDensity3D_A.GetXaxis()->GetBinLowEdge(1);
3519 const auto phiUp = hisSCDensity3D_A.GetXaxis()->GetBinUpEdge(nPhiBinsTmp);
3520 const auto rLow = hisSCDensity3D_A.GetYaxis()->GetBinLowEdge(1);
3521 const auto rUp = hisSCDensity3D_A.GetYaxis()->GetBinUpEdge(nRBinsTmp);
3522 const auto zUp = hisSCDensity3D_A.GetZaxis()->GetBinUpEdge(nZBins);
3524 TH3F hisSCMerged(
"hisMerged",
"hisMerged", nPhiBinsTmp, phiLow, phiUp, nRBinsTmp, rLow, rUp, 2 * nZBins, -zUp, zUp);
3526 for (
int iside = 0; iside < FNSIDES; ++iside) {
3527 const auto& hSC = (iside == 0) ? hisSCDensity3D_A : hisSCDensity3D_C;
3528#pragma omp parallel for num_threads(sNThreads)
3529 for (
int iz = 1; iz <= nZBins; ++iz) {
3530 const int izTmp = (iside == 0) ? (nZBins + iz) : iz;
3531 for (
int ir = 1;
ir <= nRBinsTmp; ++
ir) {
3532 for (
int iphi = 1; iphi <= nPhiBinsTmp; ++iphi) {
3533 hisSCMerged.SetBinContent(iphi,
ir, izTmp, hSC.GetBinContent(iphi,
ir, iz));
3538 fillChargeDensityFromHisto(hisSCMerged);
3541template <
typename DataT>
3545 const int nOrbits = 12;
3551 const int nIDCSlices = idcZero.size();
3554 const float idcsPerMS = nTimeStampsPerIDCInterval / idcIntegrationTimeMS;
3557 const float lengthZSliceMS = ionDriftTimeMS / nIDCSlices;
3560 const float scaleToIonDrift = lengthZSliceMS * idcsPerMS;
3566 const float conversionFactor = scaleToIonDrift / conversionADCToEle;
3567 LOGP(info,
"Converting IDCs to space-charge density with conversion factor of {}", conversionFactor);
3569 for (
auto& calIDC : idcZero) {
3570 if (normToPadArea) {
3576 float idcTmp = calIDC.getValue(sector, globalPad);
3577 calIDC.setValue(sector, globalPad, conversionFactor * idcTmp /
Mapper::INVPADAREA[region]);
3583 calIDC *= conversionFactor;
3591template <
typename DataT>
3594 convertIDCsToCharge(idcZero, mapIBF, ionDriftTimeMS, normToPadArea);
3595 fillChargeFromCalDet(idcZero);
3598template <
typename DataT>
3603 const int iside =
static_cast<int>(
side);
3604 initContainer(mPotential[iside],
true);
3605 const int phiVerticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3606 int phiVerticesEnd = phiVerticesPerSector;
3608 if (misalignmentType == MisalignmentType::RodShift) {
3609 const float rodDiameter = 1;
3610 const float rodRadius = rodDiameter / 2;
3612 int nPhiVerticesPerRod =
static_cast<int>(rodRadius * mParamGrid.NPhiVertices / (
TWOPI * radiusTmp) + 0.5);
3613 if (nPhiVerticesPerRod == 0) {
3614 nPhiVerticesPerRod = 1;
3616 phiVerticesEnd = nPhiVerticesPerRod;
3619 const int phiStart = sector * phiVerticesPerSector;
3620 const int phiEnd = phiStart + phiVerticesEnd;
3621 const int nRVertex = (fcType == FCType::IFC) ? 0 : (mParamGrid.NRVertices - 1);
3622 for (
size_t iPhi = phiStart; iPhi < phiEnd; ++iPhi) {
3623 const int iPhiSector = iPhi % phiVerticesPerSector;
3625 float potentialSector = 0;
3626 float potentialLastSector = 0;
3627 if ((misalignmentType == MisalignmentType::ShiftedClip) || (misalignmentType == MisalignmentType::RodShift)) {
3628 const float potentialShiftedClips = deltaPot - iPhiSector * deltaPot / phiVerticesEnd;
3629 potentialSector = potentialShiftedClips;
3630 potentialLastSector = potentialShiftedClips;
3631 }
else if (misalignmentType == MisalignmentType::RotatedClip) {
3633 if (iPhiSector == 0) {
3634 potentialSector = 0;
3635 potentialLastSector = 0;
3637 const float potentialRotatedClip = -deltaPot + (iPhiSector - 1) * deltaPot / (phiVerticesPerSector - 2);
3638 potentialSector = potentialRotatedClip;
3639 potentialLastSector = -potentialRotatedClip;
3643 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3644 mPotential[iside](iZ, nRVertex, iPhi) += potentialSector;
3645 if (iPhiSector > 0) {
3646 const int iPhiMirror = ((phiStart - iPhiSector) + mParamGrid.NPhiVertices) % mParamGrid.NPhiVertices;
3647 mPotential[iside](iZ, nRVertex, iPhiMirror) += potentialLastSector;
3653template <
typename DataT>
3656 if (
other.mPotential[
side].getData().empty()) {
3657 LOGP(info,
"Other space-charge object is empty!");
3661 if ((mParamGrid.NRVertices !=
other.mParamGrid.NRVertices) || (mParamGrid.NZVertices !=
other.mParamGrid.NZVertices) || (mParamGrid.NPhiVertices !=
other.mParamGrid.NPhiVertices)) {
3662 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);
3667 *
this = std::move(scTmp);
3670 initContainer(mPotential[
side],
true);
3672 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3673 for (
size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) {
3674 const size_t iRFirst = 0;
3675 mPotential[
side](iZ, iRFirst, iPhi) += scaling *
other.mPotential[
side](iZ, iRFirst, iPhi);
3677 const size_t iRLast = mParamGrid.NRVertices - 1;
3678 mPotential[
side](iZ, iRLast, iPhi) += scaling *
other.mPotential[
side](iZ, iRLast, iPhi);
3682 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3683 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3684 const size_t iZFirst = 0;
3685 mPotential[
side](iZFirst, iR, iPhi) += scaling *
other.mPotential[
side](iZFirst, iR, iPhi);
3687 const size_t iZLast = mParamGrid.NZVertices - 1;
3688 mPotential[
side](iZLast, iR, iPhi) += scaling *
other.mPotential[
side](iZLast, iR, iPhi);
3693template <
typename DataT>
3696 const float zMaxAbs = std::abs(
zMax);
3697 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3698 for (
size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) {
3701 const size_t iRFirst = 0;
3702 mPotential[
side](iZ, iRFirst, iPhi) = 0;
3704 const size_t iRLast = mParamGrid.NRVertices - 1;
3705 mPotential[
side](iZ, iRLast, iPhi) = 0;
3710 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3711 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3712 const size_t iZFirst = 0;
3714 if ((zFirst <
zMin) || (zFirst >
zMax)) {
3715 mPotential[
side](iZFirst, iR, iPhi) = 0;
3718 const size_t iZLast = mParamGrid.NZVertices - 1;
3720 if ((zLast <
zMin) || (zLast >
zMax)) {
3721 mPotential[
side](iZLast, iR, iPhi) = 0;
3727template <
typename DataT>
3730 std::function<
DataT(
DataT)> chargeUpIFCLinear = [zStart,
type, offs, deltaPot, zMaxDeltaPot](
const DataT z) {
3731 const float absZ = std::abs(
z);
3732 const float absZMaxDeltaPot = std::abs(zMaxDeltaPot);
3733 if ((absZ <= absZMaxDeltaPot) && (absZ >= zStart)) {
3736 const float offsZ = 1;
3737 const float zMaxDeltaPotTmp = zMaxDeltaPot - zStart + offsZ;
3738 const float p1 = deltaPot / (1 / offsZ - 1 / zMaxDeltaPotTmp);
3739 const float p2 = -
p1 / zMaxDeltaPotTmp;
3740 const float absZShifted = zMaxDeltaPotTmp - (absZ - zStart);
3743 }
else if (
type == 0 ||
type == 4) {
3745 return static_cast<DataT>(deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + offs);
3746 }
else if (
type == 2) {
3748 return DataT(deltaPot);
3749 }
else if (
type == 3) {
3751 return static_cast<DataT>(-deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + deltaPot);
3755 }
else if (
type == 4) {
3762 setPotentialBoundaryInnerRadius(chargeUpIFCLinear,
side);
3765template <
typename DataT>
3769 const float absZ = std::abs(
z);
3770 const float absZMaxDeltaPot = std::abs(zMaxDeltaPot);
3772 bool check = (absZ >= absZMaxDeltaPot);
3774 check = (absZ >= absZMaxDeltaPot);
3777 if (
check && (absZ <= zEnd)) {
3780 const float p1 = (deltaPot - offs) / (1 / zMaxDeltaPot - 1 / zEnd);
3781 const float p2 = offs -
p1 / zEnd;
3784 }
else if (
type == 2) {
3786 const float offsZ = 1 + offs;
3787 const float zEndTmp = zEnd - zMaxDeltaPot + offsZ;
3788 const float p1 = deltaPot / (1 / offsZ - 1 / zEndTmp);
3789 const float p2 = -
p1 / zEndTmp;
3790 const float absZShifted = absZ - zMaxDeltaPot + offsZ;
3793 }
else if (
type == 0 ||
type == 3) {
3795 const float zPos = absZ - zEnd;
3796 return static_cast<DataT>(deltaPot / (absZMaxDeltaPot - zEnd) * zPos + offs);
3800 }
else if (
type == 3) {
3806 setPotentialBoundaryInnerRadius(chargeUpIFCLinear,
side);
3809template <
typename DataT>
3812 setGlobalDistCorr(Type::Corrections, gCorr,
side);
3815template <
typename DataT>
3818 setGlobalDistCorr(Type::Distortions, gDist,
side);
3821template <
typename DataT>
3824 if (
type == Type::Distortions) {
3825 initContainer(mGlobalDistdR[
side],
true);
3826 initContainer(mGlobalDistdZ[
side],
true);
3827 initContainer(mGlobalDistdRPhi[
side],
true);
3829 initContainer(mGlobalCorrdR[
side],
true);
3830 initContainer(mGlobalCorrdZ[
side],
true);
3831 initContainer(mGlobalCorrdRPhi[
side],
true);
3834#pragma omp parallel for num_threads(sNThreads)
3835 for (
unsigned int iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3838 phi = o2::math_utils::detail::toPMPi(phi);
3840 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3842 const DataT x = getXFromPolar(radius, phi);
3843 const DataT y = getYFromPolar(radius, phi);
3845 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3852 gFunc(sector,
x,
y,
z, gCx, gCy, gCz);
3853 const DataT gCxCorr =
x + gCx;
3854 const DataT gCyCorr =
y + gCy;
3857 const DataT corrR = getRadiusFromCartesian(gCxCorr, gCyCorr) - radius;
3858 DataT phiDiff = getPhiFromCartesian(gCxCorr, gCyCorr) - phi;
3859 phiDiff = o2::math_utils::detail::toPMPi(phiDiff);
3860 const DataT corrRPhi = phiDiff * radius;
3863 if (
type == Type::Distortions) {
3864 mGlobalDistdR[
side](iZ, iR, iPhi) = corrR;
3865 mGlobalDistdZ[
side](iZ, iR, iPhi) = gCz;
3866 mGlobalDistdRPhi[
side](iZ, iR, iPhi) = corrRPhi;
3868 mGlobalCorrdR[
side](iZ, iR, iPhi) = corrR;
3869 mGlobalCorrdZ[
side](iZ, iR, iPhi) = gCz;
3870 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = corrRPhi;
3877template <
typename DataT>
3880 setROCMisalignment(
type, 2, sector, potential, potential);
3883template <
typename DataT>
3886 setROCMisalignment(
type, 0, sector, potentialMin, potentialMax);
3889template <
typename DataT>
3892 setROCMisalignment(
type, 1, sector, potentialMin, potentialMax);
3895template <
typename DataT>
3898 initContainer(mPotential[
Sector(sector).
side()],
true);
3899 const auto indPhiTopIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
false,
Side::A,
false,
true);
3901 const auto rotationPoints = [](
const int regStart,
const int regEnd,
int misalignmentType,
const float potMax,
const float potMin) {
3902 if (misalignmentType == 0) {
3904 const float radStart = mapper.getPadRegionInfo(regStart).getRadiusFirstRow();
3905 const auto& padReg = mapper.getPadRegionInfo(regEnd);
3906 const float radEnd = padReg.getRadiusFirstRow() + padReg.getPadHeight() * padReg.getNumberOfPadRows() - radStart;
3907 const float rotationPoint = radStart + radEnd / 2;
3908 const float slope = (potMax - potMin) / radEnd;
3909 return std::pair<float, float>{rotationPoint,
slope};
3910 }
else if (misalignmentType == 1) {
3911 return std::pair<float, float>{0, (potMax - potMin) / 100};
3913 return std::pair<float, float>{0, (potMax + potMin) / 2};
3917 if (stackType == 0) {
3918 const auto deltaPotPar = rotationPoints(0, 3, misalignmentType, potMax, potMin);
3919 const auto indPhiBottomIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
true,
Side::A,
false,
true);
3920 fillROCMisalignment(indPhiTopIROC, indPhiBottomIROC, sector, misalignmentType, deltaPotPar);
3921 }
else if (stackType == 1) {
3922 const auto deltaPotPar = rotationPoints(4, 9, misalignmentType, potMax, potMin);
3923 const auto indPhiTopOROC3 = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::OROC3gem,
false,
Side::A,
false,
true);
3924 fillROCMisalignment(indPhiTopOROC3, indPhiTopIROC, sector, misalignmentType, deltaPotPar);
3925 }
else if (stackType == 2) {
3926 const auto deltaPotPar = rotationPoints(0, 9, misalignmentType, potMax, potMin);
3927 const auto indPhiBottomIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
true,
Side::A,
false,
true);
3928 const auto indPhiTopOROC3 = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::OROC3gem,
false,
Side::A,
false,
true);
3929 fillROCMisalignment(indPhiTopIROC, indPhiBottomIROC, sector, misalignmentType, deltaPotPar);
3930 fillROCMisalignment(indPhiTopOROC3, indPhiTopIROC, sector, misalignmentType, deltaPotPar);
3934template <
typename DataT>
3935void 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)
3937 for (
const auto& indexw : indicesTop) {
3938 const int index = indexw.first;
3944 if ((sector != -1) && (sectorTmp != sector)) {
3947 const Sector sec(sectorTmp);
3949 for (
size_t iR = iRStart; iR > 0; --iR) {
3950 const size_t currInd = (iZ + getNZVertices() * (iR + iPhi * getNRVertices()));
3951 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); });
3953 if (foundVertexBottom) {
3958 const float rPos =
getRVertex(iR, sec.side());
3960 const float zPos =
getZVertex(iZ, sec.side());
3961 const float x = getXFromPolar(rPos, phiPos);
3962 const float y = getYFromPolar(rPos, phiPos);
3966 if (misalignmentType == 0) {
3967 deltaPot = (lPos.X() - deltaPotPar.first) * deltaPotPar.second;
3968 }
else if (misalignmentType == 1) {
3969 deltaPot = lPos.Y() * deltaPotPar.second;
3971 deltaPot = deltaPotPar.second;
3973 mPotential[sec.side()](iZ, iR, iPhi) += deltaPot;
3978template <
typename DataT>
3981 mGlobalCorrdR[
side] -= otherSC.mGlobalCorrdR[
side];
3982 mGlobalCorrdZ[
side] -= otherSC.mGlobalCorrdZ[
side];
3983 mGlobalCorrdRPhi[
side] -= otherSC.mGlobalCorrdRPhi[
side];
3986template <
typename DataT>
3989 mGlobalDistdR[
side] -= otherSC.mGlobalDistdR[
side];
3990 mGlobalDistdZ[
side] -= otherSC.mGlobalDistdZ[
side];
3991 mGlobalDistdRPhi[
side] -= otherSC.mGlobalDistdRPhi[
side];
3994template <
typename DataT>
3999 mGlobalCorrdRPhi[
side] *=
val;
4002template <
typename DataT>
4005 initContainer(mDensity[
side],
true);
4006 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
4007 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
4008 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
4009 for (
unsigned int iPhi = 0; iPhi <= (verticesPerSector / 2); ++iPhi) {
4010 float meanDensity = 0;
4011 for (
int iter = 0; iter < 2; ++iter) {
4013 const int iPhiTmpA = iPhi + sec * verticesPerSector;
4014 const int iPhiTmpB = ((sec + 1) * verticesPerSector - iPhi) % mParamGrid.NPhiVertices;
4016 meanDensity += mDensity[
side](iZ, iR, iPhiTmpA);
4017 meanDensity += mDensity[
side](iZ, iR, iPhiTmpB);
4020 mDensity[
side](iZ, iR, iPhiTmpA) = densMean;
4021 mDensity[
side](iZ, iR, iPhiTmpB) = densMean;
4030template <
typename DataT>
4034 initContainer(mDensity[
side],
true);
4035 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
4037 const int iPhiFirst = sectorInSide * verticesPerSector;
4038 const int iPhiLast = iPhiFirst + verticesPerSector;
4039 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
4040 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
4041 for (
unsigned int iPhi = iPhiFirst; iPhi < iPhiLast; ++iPhi) {
4042 mDensity[
side](iZ, iR, iPhi) *= scalingFactor;
4048template <
typename DataT>
4052 initContainer(mDensity[
side],
true);
4053 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
4055 const int iPhiFirst = sectorInSide * verticesPerSector;
4056 const int iPhiLast = iPhiFirst + verticesPerSector;
4057 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
4059 for (
unsigned int iPhi = iPhiFirst; iPhi < iPhiLast; ++iPhi) {
4065 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
4066 mDensity[
side](iZ, iR, iPhi) *= scalingFactor;
4073template <
typename DataT>
4076 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);
4077 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);
4080template <
typename DataT>
4084 std::vector<float> dRphi;
4085 std::vector<float>
r;
4086 dRphi.reserve(nPoints);
4088 for (
int i = 0;
i < nPoints; ++
i) {
4089 float radius = (rStart > 0) ? (rStart +
i) : (rmin +
i);
4090 float z = tgl * radius;
4095 dRphi.emplace_back(distRPhi);
4096 r.emplace_back(radius);
4099 TF1 fPol(
"pol2",
"pol2", rmin,
r.back());
4100 fPol.SetParameter(0, 0);
4101 fPol.SetParameter(1, 0);
4102 fPol.SetParameter(2, 0);
4103 TGraph gr(
r.size(),
r.data(), dRphi.data());
4104 gr.Fit(&fPol,
"QNRC");
4105 float dca = fPol.Eval(0);
4107 std::vector<double>
params{fPol.GetParameter(0), fPol.GetParameter(1), fPol.GetParameter(2)};
4108 std::vector<float> rInterpol;
4109 std::vector<float> dRPhiInterpol;
4110 std::vector<float> distanceInterpol;
4112 for (
int i = 0;
i < 500; ++
i) {
4113 float radius = rmin + float(
i) / 10;
4114 rInterpol.emplace_back(radius);
4115 dRPhiInterpol.emplace_back(fPol.Eval(radius));
4116 distanceInterpol.emplace_back(std::sqrt(rInterpol.back() * rInterpol.back() + dRPhiInterpol.back() * dRPhiInterpol.back()));
4119 for (
int i = -200;
i < 200; ++
i) {
4120 float radius = float(
i) / 10;
4121 rInterpol.emplace_back(radius);
4122 dRPhiInterpol.emplace_back(fPol.Eval(radius));
4123 distanceInterpol.emplace_back(std::sqrt(rInterpol.back() * rInterpol.back() + dRPhiInterpol.back() * dRPhiInterpol.back()));
4125 (*pcstream) <<
"tree"
4127 <<
"dRphi=" << dRphi
4131 <<
"rInterpol=" << rInterpol
4132 <<
"dRPhiInterpol=" << dRPhiInterpol
4133 <<
"distanceInterpol=" << distanceInterpol
4140template <
typename DataT>
4143 initContainer(mPotential[
side],
true);
4147template <
typename DataT>
4151 for (
int iside = 0; iside < 2; ++iside) {
4153 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]};
4154 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]};
4155 for (
int i = 0;
i < dataRef.size(); ++
i) {
4156 const auto& objRef = dataRef[
i].get();
4157 if (objRef.getNDataPoints()) {
4158 auto& objNew = dataNew[
i].get();
4159 scNew.initContainer(objNew,
true);
4160 objNew = objRef.convert(scNew.mGrid3D[iside], mGrid3D[iside], sNThreads);
4164 *
this = std::move(scNew);
4185template void O2TPCSpaceCharge3DCalcD::setGlobalCorrectionsFromFile<double>(TFile&,
const Side);
4186template void O2TPCSpaceCharge3DCalcD::setGlobalCorrectionsFromFile<float>(TFile&,
const Side);
4187template void O2TPCSpaceCharge3DCalcD::setGlobalDistortionsFromFile<double>(TFile&,
const Side);
4188template void O2TPCSpaceCharge3DCalcD::setGlobalDistortionsFromFile<float>(TFile&,
const Side);
4208template void O2TPCSpaceCharge3DCalcF::setGlobalCorrectionsFromFile<double>(TFile&,
const Side);
4209template void O2TPCSpaceCharge3DCalcF::setGlobalCorrectionsFromFile<float>(TFile&,
const Side);
4210template void O2TPCSpaceCharge3DCalcF::setGlobalDistortionsFromFile<double>(TFile&,
const Side);
4211template void O2TPCSpaceCharge3DCalcF::setGlobalDistortionsFromFile<float>(TFile&,
const Side);