1235 const auto totalWeight = weightPhi * weightR * weightZ;
1236 sum +=
val * totalWeight;
1237 sumW += totalWeight;
1243 const int iZ = (
side ==
Side::A) ? (iBinZ - mParamGrid.NZVertices - 1) : (mParamGrid.NZVertices - iBinZ);
1244 mDensity[
side](iZ, iBinR - 1, iBinPhi - 1) =
sum;
1250template <
typename DataT>
1251template <
typename ElectricFields>
1254 const Side side = formulaStruct.getSide();
1255 if (
type == Type::Distortions) {
1256 initContainer(mLocalDistdR[
side],
true);
1257 initContainer(mLocalDistdZ[
side],
true);
1258 initContainer(mLocalDistdRPhi[
side],
true);
1260 initContainer(mLocalCorrdR[
side],
true);
1261 initContainer(mLocalCorrdZ[
side],
true);
1262 initContainer(mLocalCorrdRPhi[
side],
true);
1266#pragma omp parallel for num_threads(sNThreads)
1267 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1269 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1271 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1280 const DataT stepSize = (z1 - z0) / sSteps;
1281 for (
int iter = 0; iter < sSteps; ++iter) {
1282 const DataT z0Tmp = (z0 + iter * stepSize + dzTmp);
1283 const DataT z1Tmp = (z0Tmp + stepSize);
1289 const DataT radiusTmp = regulateR(radius + drTmp,
side);
1290 const DataT phiTmp = regulatePhi(phi + dPhiTmp,
side);
1293 calcDistCorr(radiusTmp, phiTmp, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct,
true,
side);
1303 case Type::Corrections:
1304 mLocalCorrdR[
side](iZ + 1, iR, iPhi) = drTmp;
1305 mLocalCorrdRPhi[
side](iZ + 1, iR, iPhi) = dPhiTmp * radius;
1306 mLocalCorrdZ[
side](iZ + 1, iR, iPhi) = dzTmp;
1309 case Type::Distortions:
1310 mLocalDistdR[
side](iZ, iR, iPhi) = drTmp;
1311 mLocalDistdRPhi[
side](iZ, iR, iPhi) = dPhiTmp * radius;
1312 mLocalDistdZ[
side](iZ, iR, iPhi) = dzTmp;
1318 case Type::Corrections:
1319 mLocalCorrdR[
side](0, iR, iPhi) = 3 * (mLocalCorrdR[
side](1, iR, iPhi) - mLocalCorrdR[
side](2, iR, iPhi)) + mLocalCorrdR[
side](3, iR, iPhi);
1320 mLocalCorrdRPhi[
side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[
side](1, iR, iPhi) - mLocalCorrdRPhi[
side](2, iR, iPhi)) + mLocalCorrdRPhi[
side](3, iR, iPhi);
1321 mLocalCorrdZ[
side](0, iR, iPhi) = 3 * (mLocalCorrdZ[
side](1, iR, iPhi) - mLocalCorrdZ[
side](2, iR, iPhi)) + mLocalCorrdZ[
side](3, iR, iPhi);
1324 case Type::Distortions:
1325 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);
1326 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);
1327 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);
1334template <
typename DataT>
1335template <
typename ElectricFields>
1338 const Side side = formulaStruct.getSide();
1339 initContainer(mLocalVecDistdR[
side],
true);
1340 initContainer(mLocalVecDistdZ[
side],
true);
1341 initContainer(mLocalVecDistdRPhi[
side],
true);
1342 initContainer(mElectricFieldEr[
side],
true);
1343 initContainer(mElectricFieldEz[
side],
true);
1344 initContainer(mElectricFieldEphi[
side],
true);
1346#pragma omp parallel for num_threads(sNThreads)
1347 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1348 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1349 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
1350 const DataT ezField = getEzField(formulaStruct.getSide());
1351 const DataT er = mElectricFieldEr[
side](iZ, iR, iPhi);
1352 const DataT ez0 = mElectricFieldEz[
side](iZ, iR, iPhi);
1353 const DataT ephi = mElectricFieldEphi[
side](iZ, iR, iPhi);
1354 const DataT ez = getSign(formulaStruct.getSide()) * 1. / (ezField + ez0);
1355 const DataT erez = er * ez;
1356 const DataT ephiez = ephi * ez;
1358 const DataT vecdR = mC0 * erez + mC1 * ephiez;
1359 const DataT vecdRPhi = mC0 * ephiez - mC1 * erez;
1362 mLocalVecDistdR[
side](iZ, iR, iPhi) = vecdR;
1363 mLocalVecDistdRPhi[
side](iZ, iR, iPhi) = vecdRPhi;
1364 mLocalVecDistdZ[
side](iZ, iR, iPhi) = vecdZ;
1370template <
typename DataT>
1371template <
typename ElectricFields>
1374 if (
type == Type::Distortions) {
1375 initContainer(mLocalDistdR[
side],
true);
1376 initContainer(mLocalDistdZ[
side],
true);
1377 initContainer(mLocalDistdRPhi[
side],
true);
1379 initContainer(mLocalCorrdR[
side],
true);
1380 initContainer(mLocalCorrdZ[
side],
true);
1381 initContainer(mLocalCorrdRPhi[
side],
true);
1385#pragma omp parallel for num_threads(sNThreads)
1386 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1388 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1390 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1392 const size_t iZ0 =
type == Type::Corrections ? iZ + 1 : iZ;
1393 const size_t iZ1 =
type == Type::Corrections ? iZ : iZ + 1;
1398 const DataT stepSize = z1 - z0;
1399 const DataT absstepSize = std::abs(stepSize);
1401 const DataT stepSizeHalf = 0.5 * stepSize;
1402 const DataT absstepSizeHalf = std::abs(stepSizeHalf);
1405 const DataT zk1 = z0;
1406 const DataT rk1 = radius;
1407 const DataT phik1 = phi;
1415 case Type::Corrections:
1416 k1dR = getLocalVecCorrR(iZ0, iR, iPhi,
side);
1417 k1dZ = getLocalVecCorrZ(iZ0, iR, iPhi,
side);
1418 k1dRPhi = getLocalVecCorrRPhi(iZ0, iR, iPhi,
side);
1421 case Type::Distortions:
1422 k1dR = getLocalVecDistR(iZ0, iR, iPhi,
side);
1423 k1dZ = getLocalVecDistZ(iZ0, iR, iPhi,
side);
1424 k1dRPhi = getLocalVecDistRPhi(iZ0, iR, iPhi,
side);
1429 const DataT zk2 = zk1 + stepSizeHalf + absstepSizeHalf * k1dZ;
1430 const DataT rk2 = rk1 + absstepSizeHalf * k1dR;
1431 const DataT k1dPhi = k1dRPhi / rk1;
1432 const DataT phik2 = phik1 + absstepSizeHalf * k1dPhi;
1438 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk2, rk2, phik2,
side, k2dZ, k2dR, k2dRPhi) : getLocalDistortionVectorCyl(zk2, rk2, phik2,
side, k2dZ, k2dR, k2dRPhi);
1441 const DataT zk3 = zk1 + stepSizeHalf + absstepSizeHalf * k2dZ;
1442 const DataT rk3 = rk1 + absstepSizeHalf * k2dR;
1443 const DataT k2dPhi = k2dRPhi / rk2;
1444 const DataT phik3 = phik1 + absstepSizeHalf * k2dPhi;
1449 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk3, rk3, phik3,
side, k3dZ, k3dR, k3dRPhi) : getLocalDistortionVectorCyl(zk3, rk3, phik3,
side, k3dZ, k3dR, k3dRPhi);
1451 const DataT zk4 = zk1 + stepSize + absstepSize * k3dZ;
1452 const DataT rk4 = rk1 + absstepSize * k3dR;
1453 const DataT k3dPhi = k3dRPhi / rk3;
1454 const DataT phik4 = phik1 + absstepSize * k3dPhi;
1459 type == Type::Corrections ? getLocalCorrectionVectorCyl(zk4, rk4, phik4,
side, k4dZ, k4dR, k4dRPhi) : getLocalDistortionVectorCyl(zk4, rk4, phik4,
side, k4dZ, k4dR, k4dRPhi);
1460 const DataT k4dPhi = k4dRPhi / rk4;
1463 const DataT stepsizeSixth = absstepSize / 6;
1464 const DataT drRK = stepsizeSixth * (k1dR + 2 * k2dR + 2 * k3dR + k4dR);
1465 const DataT dzRK = stepsizeSixth * (k1dZ + 2 * k2dZ + 2 * k3dZ + k4dZ);
1466 const DataT dphiRK = stepsizeSixth * (k1dPhi + 2 * k2dPhi + 2 * k3dPhi + k4dPhi);
1470 case Type::Corrections:
1471 mLocalCorrdR[
side](iZ + 1, iR, iPhi) = drRK;
1472 mLocalCorrdRPhi[
side](iZ + 1, iR, iPhi) = dphiRK * radius;
1473 mLocalCorrdZ[
side](iZ + 1, iR, iPhi) = dzRK;
1476 case Type::Distortions:
1477 mLocalDistdR[
side](iZ, iR, iPhi) = drRK;
1478 mLocalDistdRPhi[
side](iZ, iR, iPhi) = dphiRK * radius;
1479 mLocalDistdZ[
side](iZ, iR, iPhi) = dzRK;
1485 case Type::Corrections:
1486 mLocalCorrdR[
side](0, iR, iPhi) = 3 * (mLocalCorrdR[
side](1, iR, iPhi) - mLocalCorrdR[
side](2, iR, iPhi)) + mLocalCorrdR[
side](3, iR, iPhi);
1487 mLocalCorrdRPhi[
side](0, iR, iPhi) = 3 * (mLocalCorrdRPhi[
side](1, iR, iPhi) - mLocalCorrdRPhi[
side](2, iR, iPhi)) + mLocalCorrdRPhi[
side](3, iR, iPhi);
1488 mLocalCorrdZ[
side](0, iR, iPhi) = 3 * (mLocalCorrdZ[
side](1, iR, iPhi) - mLocalCorrdZ[
side](2, iR, iPhi)) + mLocalCorrdZ[
side](3, iR, iPhi);
1491 case Type::Distortions:
1492 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);
1493 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);
1494 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);
1501template <
typename DataT>
1502template <
typename Fields>
1505 const Side side = formulaStruct.getSide();
1506 initContainer(mGlobalDistdR[
side],
true);
1507 initContainer(mGlobalDistdZ[
side],
true);
1508 initContainer(mGlobalDistdRPhi[
side],
true);
1509 const DataT stepSize = formulaStruct.getID() == 2 ? getGridSpacingZ(
side) : getGridSpacingZ(
side) / sSteps;
1511#pragma omp parallel for num_threads(sNThreads)
1512 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1514 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1516 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices - 1; ++iZ) {
1519 DataT dPhiDist = 0.0;
1524 if (iter > maxIterations) {
1525 LOGP(error,
"Aborting calculation of distortions for iZ: {}, iR: {}, iPhi: {} due to iteration '{}' > maxIterations '{}'!", iZ, iR, iPhi, iter, maxIterations);
1528 const DataT z0Tmp = z0 + dzDist + iter * stepSize;
1531 if ((getSide(z0Tmp) !=
side) && iter) {
1532 LOGP(error,
"Aborting calculation of distortions for iZ: {}, iR: {}, iPhi: {} due to change in the sides!", iZ, iR, iPhi);
1536 const DataT z1Tmp = z0Tmp + stepSize;
1537 const DataT radius = regulateR(r0 + drDist,
side);
1538 const DataT phi = regulatePhi(phi0 + dPhiDist,
side);
1545 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct);
1549 const bool checkReached =
side ==
Side::A ? z1Tmp >= getZMax(
side) : z1Tmp <= getZMax(
side);
1550 if (formulaStruct.getID() == 2 && checkReached) {
1551 const DataT fac = std::abs((getZMax(
side) - z0Tmp) * getInvSpacingZ(
side));
1565 const DataT endPoint = z1Tmp + ddZ;
1566 const DataT deltaZ = getZMax(
side) - endPoint;
1567 const DataT diff = endPoint - z0Tmp;
1568 const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0;
1569 drDist += ddR * fac;
1570 dPhiDist += ddPhi * fac;
1571 dzDist += ddZ * fac;
1577 mGlobalDistdR[
side](iZ, iR, iPhi) = drDist;
1578 mGlobalDistdRPhi[
side](iZ, iR, iPhi) = dPhiDist * r0;
1579 mGlobalDistdZ[
side](iZ, iR, iPhi) = dzDist;
1585template <
typename DataT>
1586template <
typename Formulas>
1589 using timer = std::chrono::high_resolution_clock;
1590 auto start = timer::now();
1591 const Side side = formulaStruct.getSide();
1592 initContainer(mGlobalCorrdR[
side],
true);
1593 initContainer(mGlobalCorrdZ[
side],
true);
1594 initContainer(mGlobalCorrdRPhi[
side],
true);
1596 const int iSteps = formulaStruct.getID() == 2 ? 1 : sSteps;
1597 const DataT stepSize = -getGridSpacingZ(
side) / iSteps;
1599#pragma omp parallel for num_threads(sNThreads)
1600 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
1602 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
1608 bool isOutOfVolume =
false;
1611 for (
size_t iZ = mParamGrid.NZVertices - 1; iZ >= 1; --iZ) {
1614 bool centralElectrodeReached =
false;
1615 for (
int iter = 0; iter < iSteps; ++iter) {
1616 if ((
type != 3) && (centralElectrodeReached || isOutOfVolume)) {
1619 DataT radius = r0 + drCorr;
1620 DataT phi = phi0 + dPhiCorr;
1621 const DataT z0Tmp = z0 + dzCorr + iter * stepSize;
1622 DataT z1Tmp = z0Tmp + stepSize;
1626 radius = regulateR(radius,
side);
1627 phi = regulatePhi(phi,
side);
1628 z1Tmp = regulateZ(z1Tmp,
side);
1636 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, formulaStruct);
1640 centralElectrodeReached = getSign(
side) * z1Tmp <= getZMin(
side);
1641 if (formulaStruct.getID() == 2 && centralElectrodeReached) {
1642 const DataT fac = (z0Tmp - getZMin(
side)) * getInvSpacingZ(
side);
1649 const DataT rCurr = r0 + drCorr + ddR;
1650 const DataT zCurr = z0Tmp + dzCorr + ddZ + stepSize;
1653 if ((
type != 3) && (rCurr <= getRMinSim(
side) || rCurr >= getRMaxSim(
side) || (std::abs(zCurr) > 1.2 * std::abs(getZMax(
side))))) {
1654 isOutOfVolume =
true;
1665 if ((
type != 3) && centralElectrodeReached) {
1666 const DataT endPoint = z1Tmp + ddZ;
1667 const DataT deltaZ = endPoint - getZMin(
side);
1668 const DataT diff = z0Tmp - endPoint;
1669 const DataT fac = diff != 0 ? deltaZ / diff : 0;
1670 drCorr += ddR * fac;
1671 dPhiCorr += ddPhi * fac;
1672 dzCorr += ddZ * fac;
1677 if ((
type == 1 ||
type == 2) && (centralElectrodeReached || isOutOfVolume)) {
1678 mGlobalCorrdR[
side](iZ - 1, iR, iPhi) = -1;
1679 mGlobalCorrdRPhi[
side](iZ - 1, iR, iPhi) = -1;
1680 mGlobalCorrdZ[
side](iZ - 1, iR, iPhi) = -1;
1682 mGlobalCorrdR[
side](iZ - 1, iR, iPhi) = drCorr;
1683 mGlobalCorrdRPhi[
side](iZ - 1, iR, iPhi) = dPhiCorr * r0;
1684 mGlobalCorrdZ[
side](iZ - 1, iR, iPhi) = dzCorr;
1691 for (
int iZ = mParamGrid.NZVertices - 1; iZ >= 0; --iZ) {
1693 for (
int iR = (mParamGrid.NRVertices / 2); iR >= 0; --iR) {
1694 if ((mGlobalCorrdR[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdRPhi[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdZ[
side](iZ, iR, iPhi) == -1)) {
1695 const size_t iRUp = iR + 1;
1698 mGlobalCorrdR[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1699 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1700 mGlobalCorrdZ[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1701 }
else if (
type == 2) {
1703 const size_t iRUpTwo = iR + 2;
1704 const size_t iRUpThree = iR + 3;
1705 mGlobalCorrdR[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdR[
side](iZ, iRUp, iPhi) - mGlobalCorrdR[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdR[
side](iZ, iRUpThree, iPhi);
1706 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdRPhi[
side](iZ, iRUp, iPhi) - mGlobalCorrdRPhi[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdRPhi[
side](iZ, iRUpThree, iPhi);
1707 mGlobalCorrdZ[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdZ[
side](iZ, iRUp, iPhi) - mGlobalCorrdZ[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdZ[
side](iZ, iRUpThree, iPhi);
1712 for (
int iR = (mParamGrid.NRVertices / 2); iR < mParamGrid.NRVertices; ++iR) {
1713 if ((mGlobalCorrdR[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdRPhi[
side](iZ, iR, iPhi) == -1) && (mGlobalCorrdZ[
side](iZ, iR, iPhi) == -1)) {
1714 const size_t iRUp = iR - 1;
1717 mGlobalCorrdR[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1718 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1719 mGlobalCorrdZ[
side](iZ, iR, iPhi) = mGlobalCorrdR[
side](iZ, iRUp, iPhi);
1720 }
else if (
type == 2) {
1722 const size_t iRUpTwo = iR - 2;
1723 const size_t iRUpThree = iR - 3;
1724 mGlobalCorrdR[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdR[
side](iZ, iRUp, iPhi) - mGlobalCorrdR[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdR[
side](iZ, iRUpThree, iPhi);
1725 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdRPhi[
side](iZ, iRUp, iPhi) - mGlobalCorrdRPhi[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdRPhi[
side](iZ, iRUpThree, iPhi);
1726 mGlobalCorrdZ[
side](iZ, iR, iPhi) = 3 * (mGlobalCorrdZ[
side](iZ, iRUp, iPhi) - mGlobalCorrdZ[
side](iZ, iRUpTwo, iPhi)) + mGlobalCorrdZ[
side](iZ, iRUpThree, iPhi);
1734 auto stop = timer::now();
1735 std::chrono::duration<float>
time = stop -
start;
1736 const float totalTime =
time.count();
1737 LOGP(detail,
"calcGlobalCorrections took {}s", totalTime);
1740template <
typename DataT>
1746 const Side side = getSide(point.Z());
1749 getCorrections(point.X(), point.Y(), point.Z(),
side, corrX, corrY, corrZ);
1752 point.SetXYZ(point.X() + corrX, point.Y() + corrY, point.Y() + corrY);
1755template <
typename DataT>
1761 const Side side = getSide(point.Z());
1763 getDistortions(point.X(), point.Y(), point.Z(),
side, distX, distY, distZ);
1770 if (scSCale && scale != 0) {
1771 scSCale->
getDistortions(point.X() + distX, point.Y() + distY, point.Z() + distZ,
side, distXTmp, distYTmp, distZTmp);
1772 distX += distXTmp * scale;
1773 distY += distYTmp * scale;
1774 distZ += distZTmp * scale;
1779 float phi = std::atan2(
pos.Y(),
pos.X());
1783 unsigned char secNum = std::floor(phi /
SECPHIWIDTH);
1787 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_distortElectron",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_distortElectron").data()
1791 <<
"secNum=" << secNum
1792 <<
"distX=" << distX
1793 <<
"distY=" << distY
1794 <<
"distZ=" << distZ
1795 <<
"distXDer=" << distXTmp
1796 <<
"distYDer=" << distYTmp
1797 <<
"distZDer=" << distZTmp
1798 <<
"scale=" << scale
1803 point.SetXYZ(point.X() + distX, point.Y() + distY, point.Z() + distZ);
1806template <
typename DataT>
1809 return mInterpolatorDensity[
side](
z,
r, phi);
1812template <
typename DataT>
1815 return mInterpolatorPotential[
side](
z,
r, phi);
1818template <
typename DataT>
1821 const auto nPoints =
z.size();
1822 std::vector<float> potential(nPoints);
1823#pragma omp parallel for num_threads(sNThreads)
1824 for (
size_t i = 0;
i < nPoints; ++
i) {
1825 potential[
i] = getPotentialCyl(
z[
i],
r[
i], phi[
i],
side);
1830template <
typename DataT>
1833 eZ = mInterpolatorEField[
side].evalFieldZ(
z,
r, phi);
1834 eR = mInterpolatorEField[
side].evalFieldR(
z,
r, phi);
1835 ePhi = mInterpolatorEField[
side].evalFieldPhi(
z,
r, phi);
1838template <
typename DataT>
1841 lcorrZ = mInterpolatorLocalCorr[
side].evaldZ(
z,
r, phi);
1842 lcorrR = mInterpolatorLocalCorr[
side].evaldR(
z,
r, phi);
1843 lcorrRPhi = mInterpolatorLocalCorr[
side].evaldRPhi(
z,
r, phi);
1846template <
typename DataT>
1849 const auto nPoints =
z.size();
1850 lcorrZ.resize(nPoints);
1851 lcorrR.resize(nPoints);
1852 lcorrRPhi.resize(nPoints);
1853#pragma omp parallel for num_threads(sNThreads)
1854 for (
size_t i = 0;
i < nPoints; ++
i) {
1855 getLocalCorrectionsCyl(
z[
i],
r[
i], phi[
i],
side, lcorrZ[
i], lcorrR[
i], lcorrRPhi[
i]);
1859template <
typename DataT>
1862 corrZ = mInterpolatorGlobalCorr[
side].evaldZ(
z,
r, phi);
1863 corrR = mInterpolatorGlobalCorr[
side].evaldR(
z,
r, phi);
1864 corrRPhi = mInterpolatorGlobalCorr[
side].evaldRPhi(
z,
r, phi);
1867template <
typename DataT>
1870 const auto nPoints =
z.size();
1871 corrZ.resize(nPoints);
1872 corrR.resize(nPoints);
1873 corrRPhi.resize(nPoints);
1874#pragma omp parallel for num_threads(sNThreads)
1875 for (
size_t i = 0;
i < nPoints; ++
i) {
1876 getCorrectionsCyl(
z[
i],
r[
i], phi[
i],
side, corrZ[
i], corrR[
i], corrRPhi[
i]);
1880template <
typename DataT>
1883 if (mUseAnaDistCorr) {
1884 getCorrectionsAnalytical(
x,
y,
z,
side, corrX, corrY, corrZ);
1887 const DataT radius = getRadiusFromCartesian(
x,
y);
1888 const DataT phi = getPhiFromCartesian(
x,
y);
1892 getCorrectionsCyl(
z, radius, phi,
side, corrZ, corrR, corrRPhi);
1895 const DataT radiusCorr = radius + corrR;
1896 const DataT phiCorr = phi + corrRPhi / radius;
1898 corrX = getXFromPolar(radiusCorr, phiCorr) -
x;
1899 corrY = getYFromPolar(radiusCorr, phiCorr) -
y;
1903template <
typename DataT>
1906 ldistZ = mInterpolatorLocalDist[
side].evaldZ(
z,
r, phi);
1907 ldistR = mInterpolatorLocalDist[
side].evaldR(
z,
r, phi);
1908 ldistRPhi = mInterpolatorLocalDist[
side].evaldRPhi(
z,
r, phi);
1911template <
typename DataT>
1914 const auto nPoints =
z.size();
1915 ldistZ.resize(nPoints);
1916 ldistR.resize(nPoints);
1917 ldistRPhi.resize(nPoints);
1918#pragma omp parallel for num_threads(sNThreads)
1919 for (
size_t i = 0;
i < nPoints; ++
i) {
1920 getLocalDistortionsCyl(
z[
i],
r[
i], phi[
i],
side, ldistZ[
i], ldistR[
i], ldistRPhi[
i]);
1924template <
typename DataT>
1927 lvecdistZ = mInterpolatorLocalVecDist[
side].evaldZ(
z,
r, phi);
1928 lvecdistR = mInterpolatorLocalVecDist[
side].evaldR(
z,
r, phi);
1929 lvecdistRPhi = mInterpolatorLocalVecDist[
side].evaldRPhi(
z,
r, phi);
1932template <
typename DataT>
1935 const auto nPoints =
z.size();
1936 lvecdistZ.resize(nPoints);
1937 lvecdistR.resize(nPoints);
1938 lvecdistRPhi.resize(nPoints);
1939#pragma omp parallel for num_threads(sNThreads)
1940 for (
size_t i = 0;
i < nPoints; ++
i) {
1941 getLocalDistortionVectorCyl(
z[
i],
r[
i], phi[
i],
side, lvecdistZ[
i], lvecdistR[
i], lvecdistRPhi[
i]);
1945template <
typename DataT>
1948 lveccorrZ = -mInterpolatorLocalVecDist[
side].evaldZ(
z,
r, phi);
1949 lveccorrR = -mInterpolatorLocalVecDist[
side].evaldR(
z,
r, phi);
1950 lveccorrRPhi = -mInterpolatorLocalVecDist[
side].evaldRPhi(
z,
r, phi);
1953template <
typename DataT>
1956 const auto nPoints =
z.size();
1957 lveccorrZ.resize(nPoints);
1958 lveccorrR.resize(nPoints);
1959 lveccorrRPhi.resize(nPoints);
1960#pragma omp parallel for num_threads(sNThreads)
1961 for (
size_t i = 0;
i < nPoints; ++
i) {
1962 getLocalCorrectionVectorCyl(
z[
i],
r[
i], phi[
i],
side, lveccorrZ[
i], lveccorrR[
i], lveccorrRPhi[
i]);
1966template <
typename DataT>
1969 distZ = mInterpolatorGlobalDist[
side].evaldZ(
z,
r, phi);
1970 distR = mInterpolatorGlobalDist[
side].evaldR(
z,
r, phi);
1971 distRPhi = mInterpolatorGlobalDist[
side].evaldRPhi(
z,
r, phi);
1974template <
typename DataT>
1977 const auto nPoints =
z.size();
1978 distZ.resize(nPoints);
1979 distR.resize(nPoints);
1980 distRPhi.resize(nPoints);
1981#pragma omp parallel for num_threads(sNThreads)
1982 for (
size_t i = 0;
i < nPoints; ++
i) {
1983 getDistortionsCyl(
z[
i],
r[
i], phi[
i],
side, distZ[
i], distR[
i], distRPhi[
i]);
1987template <
typename DataT>
1992 if (mUseAnaDistCorr) {
1993 getDistortionsAnalytical(
x,
y, zClamped,
side, distX, distY, distZ);
1996 const DataT radius = getRadiusFromCartesian(
x,
y);
1997 const DataT phi = getPhiFromCartesian(
x,
y);
2001 DataT rClamped = regulateR(radius,
side);
2002 getDistortionsCyl(zClamped, rClamped, phi,
side, distZ, distR, distRPhi);
2005 const DataT radiusDist = rClamped + distR;
2006 const DataT phiDist = phi + distRPhi / rClamped;
2008 distX = getXFromPolar(radiusDist, phiDist) -
x;
2009 distY = getYFromPolar(radiusDist, phiDist) -
y;
2013template <
typename DataT>
2017 float phi = std::atan2(
pos.Y(),
pos.X());
2021 const unsigned char secNum = std::floor(phi /
SECPHIWIDTH);
2026 const DataT dlX = dist ? mAnaDistCorr.getDistortionsLX(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLX(lPos.X(), lPos.Y(), lPos.Z(),
side);
2027 const DataT dlY = dist ? mAnaDistCorr.getDistortionsLY(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLY(lPos.X(), lPos.Y(), lPos.Z(),
side);
2028 const DataT dlZ = dist ? mAnaDistCorr.getDistortionsLZ(lPos.X(), lPos.Y(), lPos.Z(),
side) : mAnaDistCorr.getCorrectionsLZ(lPos.X(), lPos.Y(), lPos.Z(),
side);
2032 const LocalPosition3D lPosDist(lPos.X() + dlX, lPos.Y() + dlY, lPos.Z() + dlZ);
2036 distX = globalPosDist.X() -
x;
2037 distY = globalPosDist.Y() -
y;
2038 distZ = globalPosDist.Z() -
z;
2041 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_distortions_analytical",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_distortions_analytical").data()
2044 <<
"dlX=" << (*
const_cast<DataT*
>(&dlX))
2045 <<
"dlY=" << (*
const_cast<DataT*
>(&dlY))
2046 <<
"dlZ=" << (*
const_cast<DataT*
>(&dlZ))
2047 <<
"distX=" << distX
2048 <<
"distY=" << distY
2049 <<
"distZ=" << distZ
2054template <
typename DataT>
2057 using timer = std::chrono::high_resolution_clock;
2058 if (!mInitLookUpTables) {
2059 auto start = timer::now();
2064 float vDrift = gasParam.DriftV;
2066 const float t1 = 1.;
2067 const float t2 = 1.;
2069 const float omegaTau = -10. * bzField * vDrift / std::abs(getEzField(
Side::A));
2070 setOmegaTauT1T2(omegaTau,
t1, t2);
2071 if (mUseInitialSCDensity) {
2072 LOG(warning) <<
"mUseInitialSCDensity" << mUseInitialSCDensity;
2073 calculateDistortionsCorrections(
Side::A);
2074 calculateDistortionsCorrections(
Side::C);
2075 mInitLookUpTables =
true;
2077 auto stop = timer::now();
2078 std::chrono::duration<float>
time = stop -
start;
2079 LOGP(info,
"Total Time Distortions and Corrections for A and C Side: {}",
time.count());
2083template <
typename DataT>
2086 mGlobalDistdR[
side] = distdR;
2087 mGlobalDistdZ[
side] = distdZ;
2088 mGlobalDistdRPhi[
side] = distdRPhi;
2091template <
typename DataT>
2092template <
typename Fields>
2096 "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);
2097 localIntErOverEz =
static_cast<DataT>(fErOverEz.Integral(p1z, p2z));
2100 "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);
2101 localIntEPhiOverEz =
static_cast<DataT>(fEphiOverEz.Integral(p1z, p2z));
2104 "fEZOverEz", [&](
double*
x,
double* p) { (
void)p;
return static_cast<double>(formulaStruct.evalFieldZ(
static_cast<DataT>(
x[0]), p1r, p1phi) - ezField); }, p1z, p2z, 1);
2105 localIntDeltaEz = getSign(
side) *
static_cast<DataT>(fEz.Integral(p1z, p2z));
2108template <
typename DataT>
2109template <
typename Fields>
2113 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2114 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2115 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2117 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p1r, p1phi);
2118 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p1r, p1phi);
2119 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p1r, p1phi);
2121 const DataT eZ0 = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2122 const DataT eZ1 = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2124 const DataT deltaX = 0.5 * (p2z - p1z);
2125 localIntErOverEz = deltaX * (fielder0 * eZ0 + fielder1 * eZ1);
2126 localIntEPhiOverEz = deltaX * (fieldephi0 * eZ0 + fieldephi1 * eZ1);
2127 localIntDeltaEz = getSign(
side) * deltaX * (fieldez0 + fieldez1);
2130template <
typename DataT>
2131template <
typename Fields>
2135 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2136 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2137 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2139 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p1r, p1phi);
2140 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p1r, p1phi);
2141 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p1r, p1phi);
2143 const DataT deltaX = p2z - p1z;
2144 const DataT xk2N = (p2z -
static_cast<DataT>(0.5) * deltaX);
2145 const DataT ezField2 = formulaStruct.evalFieldZ(xk2N, p1r, p1phi);
2146 const DataT ezField2Denominator = isCloseToZero(ezField, ezField2) ? 0 : 1. / (ezField + ezField2);
2147 const DataT fieldSum2ErOverEz = formulaStruct.evalFieldR(xk2N, p1r, p1phi) * ezField2Denominator;
2148 const DataT fieldSum2EphiOverEz = formulaStruct.evalFieldPhi(xk2N, p1r, p1phi) * ezField2Denominator;
2150 const DataT eZ0 = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2151 const DataT eZ1 = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2153 const DataT deltaXSimpsonSixth = deltaX / 6.;
2154 localIntErOverEz = deltaXSimpsonSixth * (4. * fieldSum2ErOverEz + fielder0 * eZ0 + fielder1 * eZ1);
2155 localIntEPhiOverEz = deltaXSimpsonSixth * (4. * fieldSum2EphiOverEz + fieldephi0 * eZ0 + fieldephi1 * eZ1);
2156 localIntDeltaEz = getSign(
side) * deltaXSimpsonSixth * (4. * ezField2 + fieldez0 + fieldez1);
2159template <
typename DataT>
2160template <
typename Fields>
2161void 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
2166 const DataT p2phiSave = regulatePhi(p2phi,
side);
2168 const DataT fielder0 = formulaStruct.evalFieldR(p1z, p1r, p1phi);
2169 const DataT fieldez0 = formulaStruct.evalFieldZ(p1z, p1r, p1phi);
2170 const DataT fieldephi0 = formulaStruct.evalFieldPhi(p1z, p1r, p1phi);
2172 const DataT fielder1 = formulaStruct.evalFieldR(p2z, p2r, p2phiSave);
2173 const DataT fieldez1 = formulaStruct.evalFieldZ(p2z, p2r, p2phiSave);
2174 const DataT fieldephi1 = formulaStruct.evalFieldPhi(p2z, p2r, p2phiSave);
2176 const DataT eZ0Inv = isCloseToZero(ezField, fieldez0) ? 0 : 1. / (ezField + fieldez0);
2177 const DataT eZ1Inv = isCloseToZero(ezField, fieldez1) ? 0 : 1. / (ezField + fieldez1);
2179 const DataT pHalfZ = 0.5 * (p1z + p2z);
2180 const DataT pHalfPhiSave = regulatePhi(0.5 * (p1phi + p2phi),
side);
2181 const DataT pHalfR = 0.5 * (p1r + p2r);
2183 const DataT ezField2 = formulaStruct.evalFieldZ(pHalfZ, pHalfR, pHalfPhiSave);
2184 const DataT eZHalfInv = (isCloseToZero(ezField, ezField2) | isCloseToZero(ezField, fieldez0) | isCloseToZero(ezField, fieldez1)) ? 0 : 1. / (ezField + ezField2);
2185 const DataT fieldSum2ErOverEz = formulaStruct.evalFieldR(pHalfZ, pHalfR, pHalfPhiSave);
2186 const DataT fieldSum2EphiOverEz = formulaStruct.evalFieldPhi(pHalfZ, pHalfR, pHalfPhiSave);
2188 const DataT deltaXSimpsonSixth = (p2z - p1z) / 6;
2189 localIntErOverEz = deltaXSimpsonSixth * (4 * fieldSum2ErOverEz * eZHalfInv + fielder0 * eZ0Inv + fielder1 * eZ1Inv);
2190 localIntEPhiOverEz = deltaXSimpsonSixth * (4 * fieldSum2EphiOverEz * eZHalfInv + fieldephi0 * eZ0Inv + fieldephi1 * eZ1Inv);
2191 localIntDeltaEz = getSign(
side) * deltaXSimpsonSixth * (4 * ezField2 + fieldez0 + fieldez1);
2194template <
typename DataT>
2195std::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
2197 const unsigned int nElectrons = elePos.size();
2198 std::vector<std::pair<std::vector<o2::math_utils::Point3D<float>>, std::array<DataT, 3>>> electronTracks(nElectrons);
2200 for (
unsigned int i = 0;
i < nElectrons; ++
i) {
2201 electronTracks[
i].first.reserve(nSamplingPoints + 1);
2204 for (
unsigned int i = 0;
i < nElectrons; ++
i) {
2205 const DataT z0 = elePos[
i].Z();
2206 const DataT r0 = elePos[
i].Rho();
2207 const DataT phi0 = elePos[
i].Phi();
2209 if (!mElectricFieldEr[
side].getNDataPoints()) {
2210 LOGP(warning,
"E-Fields are not set! Calculation of drift path is not possible");
2214 const DataT stepSize = getZMax(
side) / nSamplingPoints;
2217 DataT dPhiDist = 0.0;
2221 const DataT z0Tmp = z0 + dzDist + iter * stepSize;
2222 const DataT z1Tmp = regulateZ(z0Tmp + stepSize,
side);
2223 const DataT radius = r0 + drDist;
2226 if (radius <= getRMin(
side) || radius >= getRMax(
side) || getSide(z0Tmp) !=
side) {
2230 const DataT phi = regulatePhi(phi0 + dPhiDist,
side);
2231 electronTracks[
i].first.emplace_back(
GlobalPosition3D(radius * std::cos(phi), radius * std::sin(phi), z0Tmp));
2238 processGlobalDistCorr(radius, phi, z0Tmp, z1Tmp, ddR, ddPhi, ddZ, numEFields);
2247 const bool checkReached =
side ==
Side::A ? z1Tmp >= getZMax(
side) : z1Tmp <= getZMax(
side);
2252 const DataT endPoint = z1Tmp + ddZ;
2253 const DataT deltaZ = getZMax(
side) - endPoint;
2254 const DataT diff = endPoint - z0Tmp;
2255 const DataT fac = diff != 0 ? std::abs(deltaZ / diff) : 0;
2256 drDist += ddR * fac;
2257 dPhiDist += ddPhi * fac;
2258 dzDist += ddZ * fac;
2259 const DataT z1TmpEnd = regulateZ(z0Tmp + stepSize,
side);
2260 const DataT radiusEnd = regulateR(r0 + drDist,
side);
2261 const DataT phiEnd = regulatePhi(phi0 + dPhiDist,
side);
2262 electronTracks[
i].first.emplace_back(
GlobalPosition3D(radiusEnd * std::cos(phiEnd), radiusEnd * std::sin(phiEnd), z1TmpEnd));
2267 electronTracks[
i].second = std::array<DataT, 3>{drDist, dPhiDist * r0, dzDist};
2269 if (!outFile.empty()) {
2270 dumpElectronTracksToTree(electronTracks, nSamplingPoints, outFile.data());
2272 return electronTracks;
2275template <
typename DataT>
2279 pcstream.GetFile()->cd();
2284 for (
int i = 0;
i < electronTracks.size(); ++
i) {
2285 auto electronPath = electronTracks[
i].first;
2286 const int nPoints = electronPath.size();
2287 if (electronPath.empty()) {
2288 LOGP(warning,
"Track is empty. Continue to next track.");
2291 std::vector<float> relDriftVel;
2292 relDriftVel.reserve(nPoints);
2294 for (
int iPoint = 0; iPoint < (nPoints - 2); ++iPoint) {
2295 const DataT relDriftVelTmp = (electronPath[iPoint + 1].Z() - electronPath[iPoint].Z()) / getZMax(getSide(electronPath[iPoint].Z())) * nSamplingPoints;
2296 relDriftVel.emplace_back(std::abs(relDriftVelTmp));
2300 relDriftVel.emplace_back(relDriftVel.back());
2301 relDriftVel.emplace_back(relDriftVel.back());
2303 DataT distR = electronTracks[
i].second[0];
2304 DataT distRPhi = electronTracks[
i].second[1];
2305 DataT distZ = electronTracks[
i].second[2];
2307 DataT driftTime = std::abs(getZMax(getSide(electronPath.front().Z())) - (distZ + electronPath.front().Z())) / gasParam.DriftV;
2308 DataT timeBin = driftTime / eleParam.ZbinWidth;
2311 <<
"electronPath=" << electronPath
2312 <<
"relDriftVel.=" << relDriftVel
2313 <<
"distR=" << distR
2314 <<
"distRPhi=" << distRPhi
2315 <<
"distZ=" << distZ
2316 <<
"driftTime=" << driftTime
2317 <<
"timeBin=" << timeBin
2323template <
typename DataT>
2327 TFile fInp(inpFile,
"READ");
2328 TTree*
tree = (TTree*)fInp.Get(
"drift");
2329 std::vector<o2::tpc::GlobalPosition3D>* electronPathTree =
new std::vector<o2::tpc::GlobalPosition3D>;
2330 tree->SetBranchAddress(
"electronPath", &electronPathTree);
2332 std::vector<std::vector<o2::tpc::GlobalPosition3D>> electronPaths;
2333 std::vector<o2::tpc::GlobalPosition3D> elePosTmp;
2334 const int entries =
tree->GetEntriesFast();
2335 for (
int i = 0;
i < entries; ++
i) {
2337 electronPaths.emplace_back(*electronPathTree);
2339 delete electronPathTree;
2342 TCanvas can(
"canvas",
"canvas", 1000, 600);
2343 can.SetTopMargin(0.04f);
2344 can.SetRightMargin(0.04f);
2345 can.SetBottomMargin(0.12f);
2346 can.SetLeftMargin(0.11f);
2348 const int nElectrons = electronPaths.size();
2349 std::vector<int> indexStartEle(nElectrons);
2350 std::vector<int> countReadoutReached(nElectrons);
2353 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};
2356 unsigned int maxPoints = 0;
2357 std::vector<TGraph> gr(nElectrons);
2358 for (
int i = 0;
i < nElectrons; ++
i) {
2359 gr[
i].SetMarkerColor(colorsPalette[
i % colorsPalette.size()]);
2361 if (electronPaths[
i].
size() > maxPoints) {
2362 maxPoints = electronPaths[
i].size();
2366 const DataT pointsPerIteration = maxPoints /
static_cast<DataT>(maxsamplingpoints);
2367 std::vector<DataT> zRemainder(nElectrons);
2370 for (
auto& graph : gr) {
2374 for (
int iEle = 0; iEle < nElectrons; ++iEle) {
2375 const int nSamplingPoints = electronPaths[iEle].size();
2376 const int nPoints = std::round(pointsPerIteration + zRemainder[iEle]);
2377 zRemainder[iEle] = pointsPerIteration - nPoints;
2378 const auto& electronPath = electronPaths[iEle];
2380 if (nPoints == 0 && countReadoutReached[iEle] == 0) {
2381 const int indexPoint = indexStartEle[iEle];
2382 const DataT radius = electronPath[indexPoint].Rho();
2383 const DataT z = electronPath[indexPoint].Z();
2384 const DataT phi = electronPath[indexPoint].Phi();
2385 type == 0 ? gr[iEle].AddPoint(
z, radius) : gr[iEle].AddPoint(phi, radius);
2388 for (
int iPoint = 0; iPoint < nPoints; ++iPoint) {
2389 const int indexPoint = indexStartEle[iEle];
2390 if (indexPoint >= nSamplingPoints) {
2391 countReadoutReached[iEle] = 1;
2395 const DataT radius = electronPath[indexPoint].Rho();
2396 const DataT z = electronPath[indexPoint].Z();
2397 const DataT phi = electronPath[indexPoint].Phi();
2398 if (iPoint == nPoints / 2) {
2399 type == 0 ? gr[iEle].AddPoint(
z, radius) : gr[iEle].AddPoint(phi, radius);
2401 ++indexStartEle[iEle];
2405 for (
auto& graph : gr) {
2406 if (graph.GetN() > 0) {
2407 graph.Draw(
"P SAME");
2410 can.Print(Form(
"%s.gif+%i", outName, gifSpeed));
2412 const int sumReadoutReached = std::accumulate(countReadoutReached.begin(), countReadoutReached.end(), 0);
2413 if (sumReadoutReached == nElectrons) {
2418 can.Print(Form(
"%s.gif++", outName));
2421template <
typename DataT>
2425 const DataT rSpacing = GridProp::getGridSpacingR(nRPoints);
2426 const DataT zSpacing =
side ==
Side::A ? GridProp::getGridSpacingZ(nZPoints) : -GridProp::getGridSpacingZ(nZPoints);
2428 std::uniform_real_distribution<DataT> uniR(-rSpacing / 2, rSpacing / 2);
2429 std::uniform_real_distribution<DataT> uniPhi(-phiSpacing / 2, phiSpacing / 2);
2431 std::vector<std::vector<float>> phiPosOut(nPhiPoints);
2432 std::vector<std::vector<float>> rPosOut(nPhiPoints);
2433 std::vector<std::vector<float>> zPosOut(nPhiPoints);
2434 std::vector<std::vector<int>> iPhiOut(nPhiPoints);
2435 std::vector<std::vector<int>> iROut(nPhiPoints);
2436 std::vector<std::vector<int>> iZOut(nPhiPoints);
2437 std::vector<std::vector<float>> densityOut(nPhiPoints);
2438 std::vector<std::vector<float>> potentialOut(nPhiPoints);
2439 std::vector<std::vector<float>> eZOut(nPhiPoints);
2440 std::vector<std::vector<float>> eROut(nPhiPoints);
2441 std::vector<std::vector<float>> ePhiOut(nPhiPoints);
2442 std::vector<std::vector<float>> distZOut(nPhiPoints);
2443 std::vector<std::vector<float>> distROut(nPhiPoints);
2444 std::vector<std::vector<float>> distRPhiOut(nPhiPoints);
2445 std::vector<std::vector<float>> corrZOut(nPhiPoints);
2446 std::vector<std::vector<float>> corrROut(nPhiPoints);
2447 std::vector<std::vector<float>> corrRPhiOut(nPhiPoints);
2448 std::vector<std::vector<float>> lcorrZOut(nPhiPoints);
2449 std::vector<std::vector<float>> lcorrROut(nPhiPoints);
2450 std::vector<std::vector<float>> lcorrRPhiOut(nPhiPoints);
2451 std::vector<std::vector<float>> ldistZOut(nPhiPoints);
2452 std::vector<std::vector<float>> ldistROut(nPhiPoints);
2453 std::vector<std::vector<float>> ldistRPhiOut(nPhiPoints);
2454 std::vector<std::vector<float>> xOut(nPhiPoints);
2455 std::vector<std::vector<float>> yOut(nPhiPoints);
2456 std::vector<std::vector<float>> bROut(nPhiPoints);
2457 std::vector<std::vector<float>> bZOut(nPhiPoints);
2458 std::vector<std::vector<float>> bPhiOut(nPhiPoints);
2459 std::vector<std::vector<LocalPosition3D>> lPosOut(nPhiPoints);
2460 std::vector<std::vector<int>> sectorOut(nPhiPoints);
2461 std::vector<std::vector<size_t>> globalIdxOut(nPhiPoints);
2463#pragma omp parallel for num_threads(sNThreads)
2464 for (
int iPhi = 0; iPhi < nPhiPoints; ++iPhi) {
2465 const int nPoints = nZPoints * nRPoints;
2466 phiPosOut[iPhi].reserve(nPoints);
2467 rPosOut[iPhi].reserve(nPoints);
2468 zPosOut[iPhi].reserve(nPoints);
2469 iPhiOut[iPhi].reserve(nPoints);
2470 iROut[iPhi].reserve(nPoints);
2471 iZOut[iPhi].reserve(nPoints);
2472 densityOut[iPhi].reserve(nPoints);
2473 potentialOut[iPhi].reserve(nPoints);
2474 eZOut[iPhi].reserve(nPoints);
2475 eROut[iPhi].reserve(nPoints);
2476 ePhiOut[iPhi].reserve(nPoints);
2477 distZOut[iPhi].reserve(nPoints);
2478 distROut[iPhi].reserve(nPoints);
2479 distRPhiOut[iPhi].reserve(nPoints);
2480 corrZOut[iPhi].reserve(nPoints);
2481 corrROut[iPhi].reserve(nPoints);
2482 corrRPhiOut[iPhi].reserve(nPoints);
2483 lcorrZOut[iPhi].reserve(nPoints);
2484 lcorrROut[iPhi].reserve(nPoints);
2485 lcorrRPhiOut[iPhi].reserve(nPoints);
2486 ldistZOut[iPhi].reserve(nPoints);
2487 ldistROut[iPhi].reserve(nPoints);
2488 ldistRPhiOut[iPhi].reserve(nPoints);
2489 xOut[iPhi].reserve(nPoints);
2490 yOut[iPhi].reserve(nPoints);
2491 bROut[iPhi].reserve(nPoints);
2492 bZOut[iPhi].reserve(nPoints);
2493 bPhiOut[iPhi].reserve(nPoints);
2494 lPosOut[iPhi].reserve(nPoints);
2495 sectorOut[iPhi].reserve(nPoints);
2496 globalIdxOut[iPhi].reserve(nPoints);
2498 std::mt19937 rng(std::random_device{}());
2499 DataT phiPos = iPhi * phiSpacing;
2500 for (
int iR = 0; iR < nRPoints; ++iR) {
2501 DataT rPos = getRMin(
side) + iR * rSpacing;
2502 for (
int iZ = 0; iZ < nZPoints; ++iZ) {
2503 DataT zPos = getZMin(
side) + iZ * zSpacing;
2505 phiPos += uniPhi(rng);
2506 o2::math_utils::detail::bringTo02PiGen<DataT>(phiPos);
2510 DataT density = getDensityCyl(zPos, rPos, phiPos,
side);
2511 DataT potential = getPotentialCyl(zPos, rPos, phiPos,
side);
2516 getDistortionsCyl(zPos, rPos, phiPos,
side, distZ, distR, distRPhi);
2521 getLocalDistortionsCyl(zPos, rPos, phiPos,
side, ldistZ, ldistR, ldistRPhi);
2529 const DataT zDistorted = zPos + distZ;
2530 const DataT radiusDistorted = rPos + distR;
2531 const DataT phiDistorted = regulatePhi(phiPos + distRPhi / rPos,
side);
2532 getCorrectionsCyl(zDistorted, radiusDistorted, phiDistorted,
side, corrZ, corrR, corrRPhi);
2533 corrRPhi *= rPos / radiusDistorted;
2538 getLocalCorrectionsCyl(zPos, rPos, phiPos,
side, lcorrZ, lcorrR, lcorrRPhi);
2544 getElectricFieldsCyl(zPos, rPos, phiPos,
side, eZ, eR, ePhi);
2547 const float x = getXFromPolar(rPos, phiPos);
2548 const float y = getYFromPolar(rPos, phiPos);
2551 const float bR = mBField.evalFieldR(zPos, rPos, phiPos);
2552 const float bZ = mBField.evalFieldZ(zPos, rPos, phiPos);
2553 const float bPhi = mBField.evalFieldPhi(zPos, rPos, phiPos);
2556 unsigned char secNum = std::floor(phiPos /
SECPHIWIDTH);
2560 phiPosOut[iPhi].emplace_back(phiPos);
2561 rPosOut[iPhi].emplace_back(rPos);
2562 zPosOut[iPhi].emplace_back(zPos);
2563 iPhiOut[iPhi].emplace_back(iPhi);
2564 iROut[iPhi].emplace_back(iR);
2565 iZOut[iPhi].emplace_back(iZ);
2566 if (mDensity[
side].getNDataPoints()) {
2567 densityOut[iPhi].emplace_back(density);
2569 if (mPotential[
side].getNDataPoints()) {
2570 potentialOut[iPhi].emplace_back(potential);
2572 if (mElectricFieldEr[
side].getNDataPoints()) {
2573 eZOut[iPhi].emplace_back(eZ);
2574 eROut[iPhi].emplace_back(eR);
2575 ePhiOut[iPhi].emplace_back(ePhi);
2577 if (mGlobalDistdR[
side].getNDataPoints()) {
2578 distZOut[iPhi].emplace_back(distZ);
2579 distROut[iPhi].emplace_back(distR);
2580 distRPhiOut[iPhi].emplace_back(distRPhi);
2582 if (mGlobalCorrdR[
side].getNDataPoints()) {
2583 corrZOut[iPhi].emplace_back(corrZ);
2584 corrROut[iPhi].emplace_back(corrR);
2585 corrRPhiOut[iPhi].emplace_back(corrRPhi);
2587 if (mLocalCorrdR[
side].getNDataPoints()) {
2588 lcorrZOut[iPhi].emplace_back(lcorrZ);
2589 lcorrROut[iPhi].emplace_back(lcorrR);
2590 lcorrRPhiOut[iPhi].emplace_back(lcorrRPhi);
2592 if (mLocalDistdR[
side].getNDataPoints()) {
2593 ldistZOut[iPhi].emplace_back(ldistZ);
2594 ldistROut[iPhi].emplace_back(ldistR);
2595 ldistRPhiOut[iPhi].emplace_back(ldistRPhi);
2597 xOut[iPhi].emplace_back(
x);
2598 yOut[iPhi].emplace_back(
y);
2599 bROut[iPhi].emplace_back(bR);
2600 bZOut[iPhi].emplace_back(bZ);
2601 bPhiOut[iPhi].emplace_back(bPhi);
2602 lPosOut[iPhi].emplace_back(lPos);
2603 sectorOut[iPhi].emplace_back(sector);
2604 const size_t idx = (iZ + nZPoints * (iR + iPhi * nRPoints));
2605 globalIdxOut[iPhi].emplace_back(idx);
2610 if (ROOT::IsImplicitMTEnabled() && (ROOT::GetThreadPoolSize() != sNThreads)) {
2611 ROOT::DisableImplicitMT();
2613 ROOT::EnableImplicitMT(sNThreads);
2614 ROOT::RDataFrame dFrame(nPhiPoints);
2617 auto dfStore = dFrame.DefineSlotEntry(
"x", [&xOut = xOut](
unsigned int, ULong64_t
entry) {
return xOut[
entry]; });
2618 dfStore = dfStore.DefineSlotEntry(
"y", [&yOut = yOut](
unsigned int, ULong64_t
entry) {
return yOut[
entry]; });
2619 dfStore = dfStore.DefineSlotEntry(
"phi", [&phiPosOut = phiPosOut](
unsigned int, ULong64_t
entry) {
return phiPosOut[
entry]; });
2620 dfStore = dfStore.DefineSlotEntry(
"r", [&rPosOut = rPosOut](
unsigned int, ULong64_t
entry) {
return rPosOut[
entry]; });
2621 dfStore = dfStore.DefineSlotEntry(
"z", [&zPosOut = zPosOut](
unsigned int, ULong64_t
entry) {
return zPosOut[
entry]; });
2622 dfStore = dfStore.DefineSlotEntry(
"iPhi", [&iPhiOut = iPhiOut](
unsigned int, ULong64_t
entry) {
return iPhiOut[
entry]; });
2623 dfStore = dfStore.DefineSlotEntry(
"iR", [&iROut = iROut](
unsigned int, ULong64_t
entry) {
return iROut[
entry]; });
2624 dfStore = dfStore.DefineSlotEntry(
"iZ", [&iZOut = iZOut](
unsigned int, ULong64_t
entry) {
return iZOut[
entry]; });
2625 dfStore = dfStore.DefineSlotEntry(
"lPos", [&lPosOut = lPosOut](
unsigned int, ULong64_t
entry) {
return lPosOut[
entry]; });
2626 dfStore = dfStore.DefineSlotEntry(
"sector", [§orOut = sectorOut](
unsigned int, ULong64_t
entry) {
return sectorOut[
entry]; });
2627 dfStore = dfStore.DefineSlotEntry(
"scdensity", [&densityOut = densityOut](
unsigned int, ULong64_t
entry) {
return densityOut[
entry]; });
2628 dfStore = dfStore.DefineSlotEntry(
"potential", [&potentialOut = potentialOut](
unsigned int, ULong64_t
entry) {
return potentialOut[
entry]; });
2629 dfStore = dfStore.DefineSlotEntry(
"eZ", [&eZOut = eZOut](
unsigned int, ULong64_t
entry) {
return eZOut[
entry]; });
2630 dfStore = dfStore.DefineSlotEntry(
"eR", [&eROut = eROut](
unsigned int, ULong64_t
entry) {
return eROut[
entry]; });
2631 dfStore = dfStore.DefineSlotEntry(
"ePhi", [&ePhiOut = ePhiOut](
unsigned int, ULong64_t
entry) {
return ePhiOut[
entry]; });
2632 dfStore = dfStore.DefineSlotEntry(
"distZ", [&distZOut = distZOut](
unsigned int, ULong64_t
entry) {
return distZOut[
entry]; });
2633 dfStore = dfStore.DefineSlotEntry(
"distR", [&distROut = distROut](
unsigned int, ULong64_t
entry) {
return distROut[
entry]; });
2634 dfStore = dfStore.DefineSlotEntry(
"distRPhi", [&distRPhiOut = distRPhiOut](
unsigned int, ULong64_t
entry) {
return distRPhiOut[
entry]; });
2635 dfStore = dfStore.DefineSlotEntry(
"corrZ", [&corrZOut = corrZOut](
unsigned int, ULong64_t
entry) {
return corrZOut[
entry]; });
2636 dfStore = dfStore.DefineSlotEntry(
"corrR", [&corrROut = corrROut](
unsigned int, ULong64_t
entry) {
return corrROut[
entry]; });
2637 dfStore = dfStore.DefineSlotEntry(
"corrRPhi", [&corrRPhiOut = corrRPhiOut](
unsigned int, ULong64_t
entry) {
return corrRPhiOut[
entry]; });
2638 dfStore = dfStore.DefineSlotEntry(
"lcorrZ", [&lcorrZOut = lcorrZOut](
unsigned int, ULong64_t
entry) {
return lcorrZOut[
entry]; });
2639 dfStore = dfStore.DefineSlotEntry(
"lcorrR", [&lcorrROut = lcorrROut](
unsigned int, ULong64_t
entry) {
return lcorrROut[
entry]; });
2640 dfStore = dfStore.DefineSlotEntry(
"lcorrRPhi", [&lcorrRPhiOut = lcorrRPhiOut](
unsigned int, ULong64_t
entry) {
return lcorrRPhiOut[
entry]; });
2641 dfStore = dfStore.DefineSlotEntry(
"ldistZ", [&ldistZOut = ldistZOut](
unsigned int, ULong64_t
entry) {
return ldistZOut[
entry]; });
2642 dfStore = dfStore.DefineSlotEntry(
"ldistR", [&ldistROut = ldistROut](
unsigned int, ULong64_t
entry) {
return ldistROut[
entry]; });
2643 dfStore = dfStore.DefineSlotEntry(
"ldistRPhi", [&ldistRPhiOut = ldistRPhiOut](
unsigned int, ULong64_t
entry) {
return ldistRPhiOut[
entry]; });
2644 dfStore = dfStore.DefineSlotEntry(
"bR", [&bROut = bROut](
unsigned int, ULong64_t
entry) {
return bROut[
entry]; });
2645 dfStore = dfStore.DefineSlotEntry(
"bZ", [&bZOut = bZOut](
unsigned int, ULong64_t
entry) {
return bZOut[
entry]; });
2646 dfStore = dfStore.DefineSlotEntry(
"bPhi", [&bPhiOut = bPhiOut](
unsigned int, ULong64_t
entry) {
return bPhiOut[
entry]; });
2647 dfStore = dfStore.DefineSlotEntry(
"globalIndex", [&globalIdxOut = globalIdxOut](
unsigned int, ULong64_t
entry) {
return globalIdxOut[
entry]; });
2648 dfStore.Snapshot(
"tree", outFileName);
2652template <
typename DataT>
2656 const DataT zSpacing = (
side ==
Side::A) ? GridProp::getGridSpacingZ(nZPoints) : -GridProp::getGridSpacingZ(nZPoints);
2660 std::vector<std::vector<float>> phiPosOut(nZPoints);
2661 std::vector<std::vector<float>> rPosOut(nZPoints);
2662 std::vector<std::vector<float>> zPosOut(nZPoints);
2663 std::vector<std::vector<int>> rowOut(nZPoints);
2664 std::vector<std::vector<float>> lxOut(nZPoints);
2665 std::vector<std::vector<float>> lyOut(nZPoints);
2666 std::vector<std::vector<float>> xOut(nZPoints);
2667 std::vector<std::vector<float>> yOut(nZPoints);
2668 std::vector<std::vector<float>> corrZOut(nZPoints);
2669 std::vector<std::vector<float>> corrROut(nZPoints);
2670 std::vector<std::vector<float>> corrRPhiOut(nZPoints);
2671 std::vector<std::vector<float>> erOut(nZPoints);
2672 std::vector<std::vector<float>> ezOut(nZPoints);
2673 std::vector<std::vector<float>> ephiOut(nZPoints);
2674 std::vector<std::vector<float>> potentialOut(nZPoints);
2675 std::vector<std::vector<int>> izOut(nZPoints);
2676 std::vector<std::vector<size_t>> globalIdxOut(nZPoints);
2678#pragma omp parallel for num_threads(sNThreads)
2679 for (
int iZ = 0; iZ < nZPoints; ++iZ) {
2680 phiPosOut[iZ].reserve(nPads);
2681 rPosOut[iZ].reserve(nPads);
2682 zPosOut[iZ].reserve(nPads);
2683 corrZOut[iZ].reserve(nPads);
2684 corrROut[iZ].reserve(nPads);
2685 corrRPhiOut[iZ].reserve(nPads);
2686 rowOut[iZ].reserve(nPads);
2687 lxOut[iZ].reserve(nPads);
2688 lyOut[iZ].reserve(nPads);
2689 xOut[iZ].reserve(nPads);
2690 yOut[iZ].reserve(nPads);
2691 erOut[iZ].reserve(nPads);
2692 ezOut[iZ].reserve(nPads);
2693 ephiOut[iZ].reserve(nPads);
2694 izOut[iZ].reserve(nPads);
2695 potentialOut[iZ].reserve(nPads);
2696 globalIdxOut[iZ].reserve(nPads);
2698 DataT zPos = getZMin(
side) + iZ * zSpacing;
2704 auto lx = padcentre.X();
2705 auto ly = padcentre.Y();
2708 auto x = globalPos.X();
2709 auto y = globalPos.Y();
2711 auto r = getRadiusFromCartesian(
x,
y);
2712 auto phi = getPhiFromCartesian(
x,
y);
2716 getCorrectionsCyl(zPos,
r, phi,
side, corrZ, corrR, corrRPhi);
2721 getElectricFieldsCyl(zPos,
r, phi,
side, eZ, eR, ePhi);
2723 potentialOut[iZ].emplace_back(getPotentialCyl(zPos,
r, phi,
side));
2724 erOut[iZ].emplace_back(eR);
2725 ezOut[iZ].emplace_back(eZ);
2726 ephiOut[iZ].emplace_back(ePhi);
2727 phiPosOut[iZ].emplace_back(phi);
2728 rPosOut[iZ].emplace_back(
r);
2729 zPosOut[iZ].emplace_back(zPos);
2730 corrZOut[iZ].emplace_back(corrZ);
2731 corrROut[iZ].emplace_back(corrR);
2732 corrRPhiOut[iZ].emplace_back(corrRPhi);
2734 lxOut[iZ].emplace_back(lx);
2735 lyOut[iZ].emplace_back(ly);
2736 xOut[iZ].emplace_back(
x);
2737 yOut[iZ].emplace_back(
y);
2738 izOut[iZ].emplace_back(iZ);
2740 globalIdxOut[iZ].emplace_back(idx);
2746 if (ROOT::IsImplicitMTEnabled() && (ROOT::GetThreadPoolSize() != sNThreads)) {
2747 ROOT::DisableImplicitMT();
2749 ROOT::EnableImplicitMT(sNThreads);
2750 ROOT::RDataFrame dFrame(nZPoints);
2753 auto dfStore = dFrame.DefineSlotEntry(
"phi", [&phiPosOut = phiPosOut](
unsigned int, ULong64_t
entry) {
return phiPosOut[
entry]; });
2754 dfStore = dfStore.DefineSlotEntry(
"r", [&rPosOut = rPosOut](
unsigned int, ULong64_t
entry) {
return rPosOut[
entry]; });
2755 dfStore = dfStore.DefineSlotEntry(
"z", [&zPosOut = zPosOut](
unsigned int, ULong64_t
entry) {
return zPosOut[
entry]; });
2756 dfStore = dfStore.DefineSlotEntry(
"iz", [&izOut = izOut](
unsigned int, ULong64_t
entry) {
return izOut[
entry]; });
2757 dfStore = dfStore.DefineSlotEntry(
"corrZ", [&corrZOut = corrZOut](
unsigned int, ULong64_t
entry) {
return corrZOut[
entry]; });
2758 dfStore = dfStore.DefineSlotEntry(
"corrR", [&corrROut = corrROut](
unsigned int, ULong64_t
entry) {
return corrROut[
entry]; });
2759 dfStore = dfStore.DefineSlotEntry(
"corrRPhi", [&corrRPhiOut = corrRPhiOut](
unsigned int, ULong64_t
entry) {
return corrRPhiOut[
entry]; });
2760 dfStore = dfStore.DefineSlotEntry(
"row", [&rowOut = rowOut](
unsigned int, ULong64_t
entry) {
return rowOut[
entry]; });
2761 dfStore = dfStore.DefineSlotEntry(
"lx", [&lxOut = lxOut](
unsigned int, ULong64_t
entry) {
return lxOut[
entry]; });
2762 dfStore = dfStore.DefineSlotEntry(
"ly", [&lyOut = lyOut](
unsigned int, ULong64_t
entry) {
return lyOut[
entry]; });
2763 dfStore = dfStore.DefineSlotEntry(
"x", [&xOut = xOut](
unsigned int, ULong64_t
entry) {
return xOut[
entry]; });
2764 dfStore = dfStore.DefineSlotEntry(
"y", [&yOut = yOut](
unsigned int, ULong64_t
entry) {
return yOut[
entry]; });
2765 dfStore = dfStore.DefineSlotEntry(
"er", [&erOut = erOut](
unsigned int, ULong64_t
entry) {
return erOut[
entry]; });
2766 dfStore = dfStore.DefineSlotEntry(
"ez", [&ezOut = ezOut](
unsigned int, ULong64_t
entry) {
return ezOut[
entry]; });
2767 dfStore = dfStore.DefineSlotEntry(
"ephi", [&ephiOut = ephiOut](
unsigned int, ULong64_t
entry) {
return ephiOut[
entry]; });
2768 dfStore = dfStore.DefineSlotEntry(
"potential", [&potentialOut = potentialOut](
unsigned int, ULong64_t
entry) {
return potentialOut[
entry]; });
2769 dfStore = dfStore.DefineSlotEntry(
"globalIndex", [&globalIdxOut = globalIdxOut](
unsigned int, ULong64_t
entry) {
return globalIdxOut[
entry]; });
2770 dfStore.Snapshot(
"tree", outFileName);
2774template <
typename DataT>
2777 const auto deltaPhi = histoIonsPhiRZ.GetXaxis()->GetBinWidth(1);
2778 const auto deltaZ = histoIonsPhiRZ.GetZaxis()->GetBinWidth(1);
2780 for (
int ir = 1;
ir <= histoIonsPhiRZ.GetNbinsY(); ++
ir) {
2781 const auto r0 = histoIonsPhiRZ.GetYaxis()->GetBinLowEdge(
ir);
2782 const auto r1 = histoIonsPhiRZ.GetYaxis()->GetBinUpEdge(
ir);
2783 const auto norm = fac * (r1 * r1 - r0 * r0);
2784 for (
int iphi = 1; iphi <= histoIonsPhiRZ.GetNbinsX(); ++iphi) {
2785 for (
int iz = 1; iz <= histoIonsPhiRZ.GetNbinsZ(); ++iz) {
2786 const auto charge = histoIonsPhiRZ.GetBinContent(iphi,
ir, iz);
2787 histoIonsPhiRZ.SetBinContent(iphi,
ir, iz,
charge / norm);
2793template <
typename DataT>
2796 if (!mAnaDistCorr.isValid()) {
2797 LOGP(info,
"============== analytical functions are not set! returning ==============");
2800 bool isOK = outf.WriteObject(&mAnaDistCorr,
"analyticalDistCorr");
2804template <
typename DataT>
2807 TFile fIn(inpf.data(),
"READ");
2808 const bool containsFormulas = fIn.GetListOfKeys()->Contains(
"analyticalDistCorr");
2809 if (!containsFormulas) {
2810 LOGP(info,
"============== analytical functions are not stored! returning ==============");
2813 LOGP(info,
"Using analytical corrections and distortions");
2814 setUseAnalyticalDistCorr(
true);
2816 mAnaDistCorr = *form;
2820template <
typename DataT>
2824 ddR = mC0 * localIntErOverEz + mC1 * localIntEPhiOverEz;
2825 ddPhi = (mC0 * localIntEPhiOverEz - mC1 * localIntErOverEz) / radius;
2829template <
typename DataT>
2833 ddR = mC2 * localIntBrOverBz - mC1 * localIntBPhiOverBz;
2834 ddPhi = (mC2 * localIntBPhiOverBz + mC1 * localIntBrOverBz) / radius;
2837template <
typename DataT>
2840 const std::unordered_map<int, std::pair<int, int>> field_to_current = {{2, {12000, 6000}},
2842 {-2, {-12000, -6000}},
2843 {-5, {-30000, -6000}},
2845 auto currents_iter = field_to_current.find(field);
2846 if (currents_iter == field_to_current.end()) {
2847 LOG(error) <<
" Could not lookup currents for fieldvalue " << field;
2850 mBField.setBField(field);
2854 setBFields(magField);
2857template <
typename DataT>
2862 float vDrift = gasParam.DriftV;
2863 const float omegaTau = -10. * bzField * vDrift / std::abs(getEzField(
Side::A));
2864 LOGP(detail,
"Setting omegaTau to {} for {}kG", omegaTau, bzField);
2865 const float t1 = 1.;
2866 const float t2 = 1.;
2867 setOmegaTauT1T2(omegaTau,
t1, t2);
2870template <
typename DataT>
2871template <
typename Fields>
2876 DataT localIntErOverEz = 0;
2877 DataT localIntEPhiOverEz = 0;
2878 DataT localIntDeltaEz = 0;
2880 DataT localIntBrOverBz = 0;
2881 DataT localIntBPhiOverBz = 0;
2882 DataT localIntDeltaBz = 0;
2887 switch (sNumericalIntegrationStrategy) {
2888 case IntegrationStrategy::SimpsonIterative:
2889 for (
int i = 0;
i < sSimpsonNIteratives; ++
i) {
2890 const DataT tmpZ = localDistCorr ? (p2z + ddZ) : regulateZ(p2z + ddZ, formulaStruct.getSide());
2891 if (mSimEDistortions) {
2892 integrateEFieldsSimpsonIterative(p1r, p1r + ddR + ddRExB, p1phi, p1phi + ddPhi + ddPhiExB, p1z, tmpZ, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2893 langevinCylindricalE(ddR, ddPhi, ddZ, (p1r + 0.5 * (ddR + ddRExB)), localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2895 if (mSimExBMisalignment) {
2896 integrateEFieldsSimpsonIterative(p1r, p1r + ddR + ddRExB, p1phi, p1phi + ddPhi + ddPhiExB, p1z, tmpZ, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2897 langevinCylindricalB(ddRExB, ddPhiExB, (p1r + 0.5 * (ddR + ddRExB)), localIntBrOverBz, localIntBPhiOverBz);
2901 case IntegrationStrategy::Simpson:
2902 if (mSimEDistortions) {
2903 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2904 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2906 if (mSimExBMisalignment) {
2907 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2908 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2911 case IntegrationStrategy::Trapezoidal:
2912 if (mSimEDistortions) {
2913 integrateEFieldsTrapezoidal(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2914 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2916 if (mSimExBMisalignment) {
2917 integrateEFieldsTrapezoidal(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2918 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2921 case IntegrationStrategy::Root:
2922 if (mSimEDistortions) {
2923 integrateEFieldsRoot(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2924 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2926 if (mSimExBMisalignment) {
2927 integrateEFieldsRoot(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2928 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2932 if (mSimEDistortions) {
2933 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz, formulaStruct, getEzField(
side),
side);
2934 langevinCylindricalE(ddR, ddPhi, ddZ, p1r, localIntErOverEz, localIntEPhiOverEz, localIntDeltaEz);
2936 if (mSimExBMisalignment) {
2937 integrateEFieldsSimpson(p1r, p1phi, p1z, p2z, localIntBrOverBz, localIntBPhiOverBz, localIntDeltaBz, mBField, 0,
side);
2938 langevinCylindricalB(ddRExB, ddPhiExB, p1r, localIntBrOverBz, localIntBPhiOverBz);
2943 o2::utils::DebugStreamer::instance()->getStreamer(
"debug_calcDistCorr",
"UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(
"debug_calcDistCorr").data()
2944 <<
"p1r=" << (*
const_cast<DataT*
>(&p1r))
2945 <<
"p1phi=" << (*
const_cast<DataT*
>(&p1phi))
2946 <<
"p1z=" << (*
const_cast<DataT*
>(&p1z))
2947 <<
"p2z=" << (*
const_cast<DataT*
>(&p2z))
2948 <<
"localIntErOverEz=" << localIntErOverEz
2949 <<
"localIntEPhiOverEz=" << localIntEPhiOverEz
2950 <<
"localIntDeltaEz=" << localIntDeltaEz
2952 <<
"ddPhi=" << ddPhi
2954 <<
"localIntBrOverBz=" << localIntBrOverBz
2955 <<
"localIntBPhiOverBz=" << localIntBPhiOverBz
2956 <<
"localIntDeltaBz=" << localIntDeltaBz
2957 <<
"ddRExB=" << ddRExB
2958 <<
"ddPhiExB=" << ddPhiExB
2966template <
typename DataT>
2969 if (!mElectricFieldEr[
side].getNDataPoints()) {
2970 LOGP(info,
"============== E-Fields are not set! returning ==============");
2973 const std::string sideName = getSideName(
side);
2974 const int er = mElectricFieldEr[
side].writeToFile(
file, option, fmt::format(
"fieldEr_side{}", sideName), sNThreads);
2975 const int ez = mElectricFieldEz[
side].writeToFile(
file,
"UPDATE", fmt::format(
"fieldEz_side{}", sideName), sNThreads);
2976 const int ephi = mElectricFieldEphi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"fieldEphi_side{}", sideName), sNThreads);
2977 dumpMetaData(
file,
"UPDATE",
false);
2978 return er + ez + ephi;
2981template <
typename DataT>
2984 const std::string sideName = getSideName(
side);
2985 std::string_view treeEr{fmt::format(
"fieldEr_side{}", sideName)};
2986 if (!checkGridFromFile(
file, treeEr)) {
2989 initContainer(mElectricFieldEr[
side],
true);
2990 initContainer(mElectricFieldEz[
side],
true);
2991 initContainer(mElectricFieldEphi[
side],
true);
2992 mElectricFieldEr[
side].initFromFile(
file, treeEr, sNThreads);
2993 mElectricFieldEz[
side].initFromFile(
file, fmt::format(
"fieldEz_side{}", sideName), sNThreads);
2994 mElectricFieldEphi[
side].initFromFile(
file, fmt::format(
"fieldEphi_side{}", sideName), sNThreads);
2998template <
typename DataT>
3001 if (!mGlobalDistdR[
side].getNDataPoints()) {
3002 LOGP(info,
"============== global distortions are not set! returning ==============");
3005 const std::string sideName = getSideName(
side);
3006 const int er = mGlobalDistdR[
side].writeToFile(
file, option, fmt::format(
"distR_side{}", sideName), sNThreads);
3007 const int ez = mGlobalDistdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"distZ_side{}", sideName), sNThreads);
3008 const int ephi = mGlobalDistdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"distRphi_side{}", sideName), sNThreads);
3009 dumpMetaData(
file,
"UPDATE",
false);
3010 return er + ez + ephi;
3013template <
typename DataT>
3016 const std::string sideName = getSideName(
side);
3017 std::string_view
tree{fmt::format(
"distR_side{}", sideName)};
3018 if (!checkGridFromFile(
file,
tree)) {
3021 initContainer(mGlobalDistdR[
side],
true);
3022 initContainer(mGlobalDistdZ[
side],
true);
3023 initContainer(mGlobalDistdRPhi[
side],
true);
3024 mGlobalDistdR[
side].initFromFile(
file,
tree, sNThreads);
3025 mGlobalDistdZ[
side].initFromFile(
file, fmt::format(
"distZ_side{}", sideName), sNThreads);
3026 mGlobalDistdRPhi[
side].initFromFile(
file, fmt::format(
"distRphi_side{}", sideName), sNThreads);
3030template <
typename DataT>
3031template <
typename DataTIn>
3034 initContainer(mGlobalDistdR[
side],
false);
3035 initContainer(mGlobalDistdZ[
side],
false);
3036 initContainer(mGlobalDistdRPhi[
side],
false);
3037 const std::string sideName = getSideName(
side);
3038 mGlobalDistdR[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distR_side{}", sideName).
data());
3039 mGlobalDistdZ[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distZ_side{}", sideName).
data());
3040 mGlobalDistdRPhi[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"distRphi_side{}", sideName).
data());
3043template <
typename DataT>
3046 if (!mGlobalCorrdR[
side].getNDataPoints()) {
3047 LOGP(info,
"============== global corrections are not set! returning ==============");
3050 const std::string sideName = getSideName(
side);
3051 const int er = mGlobalCorrdR[
side].writeToFile(
file, option, fmt::format(
"corrR_side{}", sideName), sNThreads);
3052 const int ez = mGlobalCorrdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"corrZ_side{}", sideName), sNThreads);
3053 const int ephi = mGlobalCorrdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"corrRPhi_side{}", sideName), sNThreads);
3054 dumpMetaData(
file,
"UPDATE",
false);
3055 return er + ez + ephi;
3058template <
typename DataT>
3061 const std::string sideName = getSideName(
side);
3062 const std::string_view treename{fmt::format(
"corrR_side{}", getSideName(
side))};
3063 if (!checkGridFromFile(
file, treename)) {
3067 initContainer(mGlobalCorrdR[
side],
true);
3068 initContainer(mGlobalCorrdZ[
side],
true);
3069 initContainer(mGlobalCorrdRPhi[
side],
true);
3070 mGlobalCorrdR[
side].initFromFile(
file, treename, sNThreads);
3071 mGlobalCorrdZ[
side].initFromFile(
file, fmt::format(
"corrZ_side{}", sideName), sNThreads);
3072 mGlobalCorrdRPhi[
side].initFromFile(
file, fmt::format(
"corrRPhi_side{}", sideName), sNThreads);
3076template <
typename DataT>
3077template <
typename DataTIn>
3080 initContainer(mGlobalCorrdR[
side],
false);
3081 initContainer(mGlobalCorrdZ[
side],
false);
3082 initContainer(mGlobalCorrdRPhi[
side],
false);
3083 const std::string sideName = getSideName(
side);
3084 mGlobalCorrdR[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrR_side{}", sideName).
data());
3085 mGlobalCorrdZ[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrZ_side{}", sideName).
data());
3086 mGlobalCorrdRPhi[
side].template initFromFile<DataTIn>(inpf, fmt::format(
"corrRPhi_side{}", sideName).
data());
3089template <
typename DataT>
3092 if (!mLocalCorrdR[
side].getNDataPoints()) {
3093 LOGP(info,
"============== local corrections are not set! returning ==============");
3096 const std::string sideName = getSideName(
side);
3097 const int lCorrdR = mLocalCorrdR[
side].writeToFile(
file, option, fmt::format(
"lcorrR_side{}", sideName), sNThreads);
3098 const int lCorrdZ = mLocalCorrdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lcorrZ_side{}", sideName), sNThreads);
3099 const int lCorrdRPhi = mLocalCorrdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lcorrRPhi_side{}", sideName), sNThreads);
3100 dumpMetaData(
file,
"UPDATE",
false);
3101 return lCorrdR + lCorrdZ + lCorrdRPhi;
3104template <
typename DataT>
3107 const std::string sideName = getSideName(
side);
3108 const std::string_view treename{fmt::format(
"lcorrR_side{}", getSideName(
side))};
3109 if (!checkGridFromFile(
file, treename)) {
3112 initContainer(mLocalCorrdR[
side],
true);
3113 initContainer(mLocalCorrdZ[
side],
true);
3114 initContainer(mLocalCorrdRPhi[
side],
true);
3115 const bool lCorrdR = mLocalCorrdR[
side].initFromFile(
file, treename, sNThreads);
3116 const bool lCorrdZ = mLocalCorrdZ[
side].initFromFile(
file, fmt::format(
"lcorrZ_side{}", sideName), sNThreads);
3117 const bool lCorrdRPhi = mLocalCorrdRPhi[
side].initFromFile(
file, fmt::format(
"lcorrRPhi_side{}", sideName), sNThreads);
3121template <
typename DataT>
3124 if (!mLocalDistdR[
side].getNDataPoints()) {
3125 LOGP(info,
"============== local distortions are not set! returning ==============");
3128 const std::string sideName = getSideName(
side);
3129 const int lDistdR = mLocalDistdR[
side].writeToFile(
file, option, fmt::format(
"ldistR_side{}", sideName), sNThreads);
3130 const int lDistdZ = mLocalDistdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"ldistZ_side{}", sideName), sNThreads);
3131 const int lDistdRPhi = mLocalDistdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"ldistRPhi_side{}", sideName), sNThreads);
3132 dumpMetaData(
file,
"UPDATE",
false);
3133 return lDistdR + lDistdZ + lDistdRPhi;
3136template <
typename DataT>
3139 if (!mLocalVecDistdR[
side].getNDataPoints()) {
3140 LOGP(info,
"============== local distortion vectors are not set! returning ==============");
3143 const std::string sideName = getSideName(
side);
3144 const int lVecDistdR = mLocalVecDistdR[
side].writeToFile(
file, option, fmt::format(
"lvecdistR_side{}", sideName), sNThreads);
3145 const int lVecDistdZ = mLocalVecDistdZ[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lvecdistZ_side{}", sideName), sNThreads);
3146 const int lVecDistdRPhi = mLocalVecDistdRPhi[
side].writeToFile(
file,
"UPDATE", fmt::format(
"lvecdistRPhi_side{}", sideName), sNThreads);
3147 dumpMetaData(
file,
"UPDATE",
false);
3148 return lVecDistdR + lVecDistdZ + lVecDistdRPhi;
3151template <
typename DataT>
3154 const std::string sideName = getSideName(
side);
3155 const std::string_view treename{fmt::format(
"ldistR_side{}", getSideName(
side))};
3156 if (!checkGridFromFile(
file, treename)) {
3159 initContainer(mLocalDistdR[
side],
true);
3160 initContainer(mLocalDistdZ[
side],
true);
3161 initContainer(mLocalDistdRPhi[
side],
true);
3162 const bool lDistdR = mLocalDistdR[
side].initFromFile(
file, treename, sNThreads);
3163 const bool lDistdZ = mLocalDistdZ[
side].initFromFile(
file, fmt::format(
"ldistZ_side{}", sideName), sNThreads);
3164 const bool lDistdRPhi = mLocalDistdRPhi[
side].initFromFile(
file, fmt::format(
"ldistRPhi_side{}", sideName), sNThreads);
3168template <
typename DataT>
3171 const std::string sideName = getSideName(
side);
3172 const std::string_view treename{fmt::format(
"lvecdistR_side{}", getSideName(
side))};
3173 if (!checkGridFromFile(
file, treename)) {
3176 initContainer(mLocalVecDistdR[
side],
true);
3177 initContainer(mLocalVecDistdZ[
side],
true);
3178 initContainer(mLocalVecDistdRPhi[
side],
true);
3179 const bool lVecDistdR = mLocalVecDistdR[
side].initFromFile(
file, treename, sNThreads);
3180 const bool lVecDistdZ = mLocalVecDistdZ[
side].initFromFile(
file, fmt::format(
"lvecdistZ_side{}", sideName), sNThreads);
3181 const bool lVecDistdRPhi = mLocalVecDistdRPhi[
side].initFromFile(
file, fmt::format(
"lvecdistRPhi_side{}", sideName), sNThreads);
3185template <
typename DataT>
3188 if (!mPotential[
side].getNDataPoints()) {
3189 LOGP(info,
"============== potential not set! returning ==============");
3192 int status = mPotential[
side].writeToFile(
file, option, fmt::format(
"potential_side{}", getSideName(
side)), sNThreads);
3193 dumpMetaData(
file,
"UPDATE",
false);
3197template <
typename DataT>
3200 const std::string_view treename{fmt::format(
"potential_side{}", getSideName(
side))};
3201 if (!checkGridFromFile(
file, treename)) {
3204 initContainer(mPotential[
side],
true);
3205 mPotential[
side].initFromFile(
file, treename, sNThreads);
3209template <
typename DataT>
3212 if (!mDensity[
side].getNDataPoints()) {
3213 LOGP(info,
"============== space charge density are not set! returning ==============");
3216 int status = mDensity[
side].writeToFile(
file, option, fmt::format(
"density_side{}", getSideName(
side)), sNThreads);
3217 dumpMetaData(
file,
"UPDATE",
false);
3221template <
typename DataT>
3224 unsigned short nr, nz, nphi;
3225 if (!DataContainer::getVertices(
tree,
file, nr, nz, nphi)) {
3230 if ((mParamGrid.NRVertices != nr) || (mParamGrid.NZVertices != nz) || (mParamGrid.NPhiVertices != nphi)) {
3231 LOGP(info,
"Different number of vertices found in input file. Initializing new space charge object with nR {} nZ {} nPhi {} vertices", nr, nz, nphi);
3236 *
this = std::move(scTmp);
3241template <
typename DataT>
3244 const std::string_view treename{fmt::format(
"density_side{}", getSideName(
side))};
3245 if (!checkGridFromFile(
file, treename)) {
3248 initContainer(mDensity[
side],
true);
3249 mDensity[
side].initFromFile(
file, treename, sNThreads);
3253template <
typename DataT>
3256 if (!mGlobalCorrdR[
side].getNDataPoints()) {
3257 LOGP(info,
"============== global corrections are not set! returning ==============");
3260 const std::string sideName = getSideName(
side);
3261 const int er = mGlobalCorrdR[
side].template writeToFile<float>(outf, fmt::format(
"corrR_side{}", sideName).
data());
3262 const int ez = mGlobalCorrdZ[
side].template writeToFile<float>(outf, fmt::format(
"corrZ_side{}", sideName).
data());
3263 const int ephi = mGlobalCorrdRPhi[
side].template writeToFile<float>(outf, fmt::format(
"corrRPhi_side{}", sideName).
data());
3264 return er + ez + ephi;
3267template <
typename DataT>
3270 if (option ==
"RECREATE") {
3272 gSystem->Unlink(
file.data());
3274 dumpElectricFields(
file,
side,
"UPDATE");
3275 dumpPotential(
file,
side,
"UPDATE");
3277 dumpGlobalDistortions(
file,
side,
"UPDATE");
3278 dumpGlobalCorrections(
file,
side,
"UPDATE");
3279 dumpLocalCorrections(
file,
side,
"UPDATE");
3280 dumpLocalDistortions(
file,
side,
"UPDATE");
3281 dumpLocalDistCorrVectors(
file,
side,
"UPDATE");
3284template <
typename DataT>
3291template <
typename DataT>
3294 TFile
f(
file.data(), option.data());
3295 if (!overwriteExisting &&
f.GetListOfKeys()->Contains(
"meta")) {
3301 std::vector<float>
params{
static_cast<float>(mC0),
static_cast<float>(mC1),
static_cast<float>(mC2)};
3302 auto helperA = mGrid3D[
Side::A].getHelper();
3303 auto helperC = mGrid3D[
Side::C].getHelper();
3306 ROOT::RDataFrame dFrame(1);
3307 auto dfStore = dFrame.DefineSlotEntry(
"paramsC", [&
params =
params](
unsigned int, ULong64_t
entry) {
return params; });
3308 dfStore = dfStore.DefineSlotEntry(
"grid_A", [&helperA = helperA](
unsigned int, ULong64_t
entry) {
return helperA; });
3309 dfStore = dfStore.DefineSlotEntry(
"grid_C", [&helperC = helperC](
unsigned int, ULong64_t
entry) {
return helperC; });
3310 dfStore = dfStore.DefineSlotEntry(
"BField", [field = mBField.getBField()](
unsigned int, ULong64_t
entry) { return field; });
3311 dfStore = dfStore.DefineSlotEntry(
"metaInf", [meta = mMeta](
unsigned int, ULong64_t
entry) {
return meta; });
3314 ROOT::RDF::RSnapshotOptions opt;
3316 opt.fOverwriteIfExists =
true;
3317 dfStore.Snapshot(
"meta",
file, {
"paramsC",
"grid_A",
"grid_C",
"BField",
"metaInf"}, opt);
3320template <
typename DataT>
3323 if (mReadMetaData) {
3328 TFile
f(
file.data(),
"READ");
3329 if (!
f.GetListOfKeys()->Contains(
"meta")) {
3338 mGrid3D[
Side::A] =
RegularGrid3D<DataT>(gridA.zmin, gridA.rmin, gridA.phimin, gridA.spacingZ, gridA.spacingR, gridA.spacingPhi, gridA.params);
3339 mGrid3D[
Side::C] =
RegularGrid3D<DataT>(gridC.zmin, gridC.rmin, gridC.phimin, gridC.spacingZ, gridC.spacingR, gridC.spacingPhi, gridC.params);
3340 mBField.setBField(field);
3343 ROOT::RDataFrame dFrame(
"meta",
file);
3344 dFrame.Foreach(readMeta, {
"paramsC",
"grid_A",
"grid_C",
"BField"});
3346 const auto&
cols = dFrame.GetColumnNames();
3347 if (std::find(
cols.begin(),
cols.end(),
"metaInf") !=
cols.end()) {
3348 auto readMetaInf = [&mMeta = mMeta](
const SCMetaData& meta) {
3351 dFrame.Foreach(readMetaInf, {
"metaInf"});
3354 LOGP(info,
"Setting meta data: mC0={} mC1={} mC2={}", mC0, mC1, mC2);
3355 mReadMetaData =
true;
3358template <
typename DataT>
3361 LOGP(warning,
"Use this feature only if you know what you are doing!");
3363 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, mParamGrid},
3364 {GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(
Side::C) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) /
SECTORSPERSIDE, mParamGrid}};
3365 mGrid3D[0] = gridTmp[0];
3366 mGrid3D[1] = gridTmp[1];
3369template <
typename DataT>
3375template <
typename DataT>
3380 setElectricFieldsFromFile(
file,
side);
3381 setLocalDistortionsFromFile(
file,
side);
3382 setLocalCorrectionsFromFile(
file,
side);
3383 setGlobalDistortionsFromFile(
file,
side);
3384 setGlobalCorrectionsFromFile(
file,
side);
3385 setLocalDistCorrVectorsFromFile(
file,
side);
3388template <
typename DataT>
3395template <
typename DataT>
3398 if (!
data.getNDataPoints()) {
3399 data.setGrid(getNZVertices(), getNRVertices(), getNPhiVertices(), initMem);
3403template <
typename DataT>
3406 const DataT wt0 = t2 * omegaTau;
3407 const DataT wt02 = wt0 * wt0;
3408 mC0 = 1 / (1 + wt02);
3409 const DataT wt1 =
t1 * omegaTau;
3410 mC1 = wt1 / (1 + wt1 * wt1);
3411 mC2 = wt02 / (1 + wt02);
3414template <
typename DataT>
3419 LOGP(warning,
"Space charge objects have different grid definition");
3427template <
typename DataT>
3430 TFile fInp(
file,
"READ");
3431 TH3F* hSCA = (TH3F*)fInp.Get(nameA);
3432 TH3F* hSCC = (TH3F*)fInp.Get(nameC);
3434 LOGP(error,
"Histogram {} not found", nameA);
3437 LOGP(error,
"Histogram {} not found", nameC);
3439 fillChargeDensityFromHisto(*hSCA, *hSCC);
3442template <
typename DataT>
3445 const int nPhiBinsTmp = hisSCDensity3D_A.GetXaxis()->GetNbins();
3446 const int nRBinsTmp = hisSCDensity3D_A.GetYaxis()->GetNbins();
3447 const int nZBins = hisSCDensity3D_A.GetZaxis()->GetNbins();
3448 const auto phiLow = hisSCDensity3D_A.GetXaxis()->GetBinLowEdge(1);
3449 const auto phiUp = hisSCDensity3D_A.GetXaxis()->GetBinUpEdge(nPhiBinsTmp);
3450 const auto rLow = hisSCDensity3D_A.GetYaxis()->GetBinLowEdge(1);
3451 const auto rUp = hisSCDensity3D_A.GetYaxis()->GetBinUpEdge(nRBinsTmp);
3452 const auto zUp = hisSCDensity3D_A.GetZaxis()->GetBinUpEdge(nZBins);
3454 TH3F hisSCMerged(
"hisMerged",
"hisMerged", nPhiBinsTmp, phiLow, phiUp, nRBinsTmp, rLow, rUp, 2 * nZBins, -zUp, zUp);
3456 for (
int iside = 0; iside < FNSIDES; ++iside) {
3457 const auto& hSC = (iside == 0) ? hisSCDensity3D_A : hisSCDensity3D_C;
3458#pragma omp parallel for num_threads(sNThreads)
3459 for (
int iz = 1; iz <= nZBins; ++iz) {
3460 const int izTmp = (iside == 0) ? (nZBins + iz) : iz;
3461 for (
int ir = 1;
ir <= nRBinsTmp; ++
ir) {
3462 for (
int iphi = 1; iphi <= nPhiBinsTmp; ++iphi) {
3463 hisSCMerged.SetBinContent(iphi,
ir, izTmp, hSC.GetBinContent(iphi,
ir, iz));
3468 fillChargeDensityFromHisto(hisSCMerged);
3471template <
typename DataT>
3475 const int nOrbits = 12;
3481 const int nIDCSlices = idcZero.size();
3484 const float idcsPerMS = nTimeStampsPerIDCInterval / idcIntegrationTimeMS;
3487 const float lengthZSliceMS = ionDriftTimeMS / nIDCSlices;
3490 const float scaleToIonDrift = lengthZSliceMS * idcsPerMS;
3496 const float conversionFactor = scaleToIonDrift / conversionADCToEle;
3497 LOGP(info,
"Converting IDCs to space-charge density with conversion factor of {}", conversionFactor);
3499 for (
auto& calIDC : idcZero) {
3500 if (normToPadArea) {
3506 float idcTmp = calIDC.getValue(sector, globalPad);
3507 calIDC.setValue(sector, globalPad, conversionFactor * idcTmp /
Mapper::INVPADAREA[region]);
3513 calIDC *= conversionFactor;
3521template <
typename DataT>
3524 convertIDCsToCharge(idcZero, mapIBF, ionDriftTimeMS, normToPadArea);
3525 fillChargeFromCalDet(idcZero);
3528template <
typename DataT>
3533 const int iside =
static_cast<int>(
side);
3534 initContainer(mPotential[iside],
true);
3535 const int phiVerticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3536 int phiVerticesEnd = phiVerticesPerSector;
3538 if (misalignmentType == MisalignmentType::RodShift) {
3539 const float rodDiameter = 1;
3540 const float rodRadius = rodDiameter / 2;
3542 int nPhiVerticesPerRod =
static_cast<int>(rodRadius * mParamGrid.NPhiVertices / (
TWOPI * radiusTmp) + 0.5);
3543 if (nPhiVerticesPerRod == 0) {
3544 nPhiVerticesPerRod = 1;
3546 phiVerticesEnd = nPhiVerticesPerRod;
3549 const int phiStart = sector * phiVerticesPerSector;
3550 const int phiEnd = phiStart + phiVerticesEnd;
3551 const int nRVertex = (fcType == FCType::IFC) ? 0 : (mParamGrid.NRVertices - 1);
3552 for (
size_t iPhi = phiStart; iPhi < phiEnd; ++iPhi) {
3553 const int iPhiSector = iPhi % phiVerticesPerSector;
3555 float potentialSector = 0;
3556 float potentialLastSector = 0;
3557 if ((misalignmentType == MisalignmentType::ShiftedClip) || (misalignmentType == MisalignmentType::RodShift)) {
3558 const float potentialShiftedClips = deltaPot - iPhiSector * deltaPot / phiVerticesEnd;
3559 potentialSector = potentialShiftedClips;
3560 potentialLastSector = potentialShiftedClips;
3561 }
else if (misalignmentType == MisalignmentType::RotatedClip) {
3563 if (iPhiSector == 0) {
3564 potentialSector = 0;
3565 potentialLastSector = 0;
3567 const float potentialRotatedClip = -deltaPot + (iPhiSector - 1) * deltaPot / (phiVerticesPerSector - 2);
3568 potentialSector = potentialRotatedClip;
3569 potentialLastSector = -potentialRotatedClip;
3573 for (
size_t iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3574 mPotential[iside](iZ, nRVertex, iPhi) += potentialSector;
3575 if (iPhiSector > 0) {
3576 const int iPhiMirror = ((phiStart - iPhiSector) + mParamGrid.NPhiVertices) % mParamGrid.NPhiVertices;
3577 mPotential[iside](iZ, nRVertex, iPhiMirror) += potentialLastSector;
3583template <
typename DataT>
3586 if (
other.mPotential[
side].getData().empty()) {
3587 LOGP(info,
"Other space-charge object is empty!");
3591 if ((mParamGrid.NRVertices !=
other.mParamGrid.NRVertices) || (mParamGrid.NZVertices !=
other.mParamGrid.NZVertices) || (mParamGrid.NPhiVertices !=
other.mParamGrid.NPhiVertices)) {
3592 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);
3597 *
this = std::move(scTmp);
3600 initContainer(mPotential[
side],
true);
3602 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3603 for (
size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) {
3604 const size_t iRFirst = 0;
3605 mPotential[
side](iZ, iRFirst, iPhi) += scaling *
other.mPotential[
side](iZ, iRFirst, iPhi);
3607 const size_t iRLast = mParamGrid.NRVertices - 1;
3608 mPotential[
side](iZ, iRLast, iPhi) += scaling *
other.mPotential[
side](iZ, iRLast, iPhi);
3612 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3613 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3614 const size_t iZFirst = 0;
3615 mPotential[
side](iZFirst, iR, iPhi) += scaling *
other.mPotential[
side](iZFirst, iR, iPhi);
3617 const size_t iZLast = mParamGrid.NZVertices - 1;
3618 mPotential[
side](iZLast, iR, iPhi) += scaling *
other.mPotential[
side](iZLast, iR, iPhi);
3623template <
typename DataT>
3626 const float zMaxAbs = std::abs(
zMax);
3627 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3628 for (
size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) {
3631 const size_t iRFirst = 0;
3632 mPotential[
side](iZ, iRFirst, iPhi) = 0;
3634 const size_t iRLast = mParamGrid.NRVertices - 1;
3635 mPotential[
side](iZ, iRLast, iPhi) = 0;
3640 for (
size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3641 for (
size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3642 const size_t iZFirst = 0;
3644 if ((zFirst <
zMin) || (zFirst >
zMax)) {
3645 mPotential[
side](iZFirst, iR, iPhi) = 0;
3648 const size_t iZLast = mParamGrid.NZVertices - 1;
3650 if ((zLast <
zMin) || (zLast >
zMax)) {
3651 mPotential[
side](iZLast, iR, iPhi) = 0;
3657template <
typename DataT>
3660 std::function<
DataT(
DataT)> chargeUpIFCLinear = [zStart,
type, offs, deltaPot, zMaxDeltaPot](
const DataT z) {
3661 const float absZ = std::abs(
z);
3662 const float absZMaxDeltaPot = std::abs(zMaxDeltaPot);
3663 if ((absZ <= absZMaxDeltaPot) && (absZ >= zStart)) {
3666 const float offsZ = 1;
3667 const float zMaxDeltaPotTmp = zMaxDeltaPot - zStart + offsZ;
3668 const float p1 = deltaPot / (1 / offsZ - 1 / zMaxDeltaPotTmp);
3669 const float p2 = -
p1 / zMaxDeltaPotTmp;
3670 const float absZShifted = zMaxDeltaPotTmp - (absZ - zStart);
3673 }
else if (
type == 0 ||
type == 4) {
3675 return static_cast<DataT>(deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + offs);
3676 }
else if (
type == 2) {
3678 return DataT(deltaPot);
3679 }
else if (
type == 3) {
3681 return static_cast<DataT>(-deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + deltaPot);
3685 }
else if (
type == 4) {
3692 setPotentialBoundaryInnerRadius(chargeUpIFCLinear,
side);
3695template <
typename DataT>
3699 const float absZ = std::abs(
z);
3700 const float absZMaxDeltaPot = std::abs(zMaxDeltaPot);
3702 bool check = (absZ >= absZMaxDeltaPot);
3704 check = (absZ >= absZMaxDeltaPot);
3707 if (
check && (absZ <= zEnd)) {
3710 const float p1 = (deltaPot - offs) / (1 / zMaxDeltaPot - 1 / zEnd);
3711 const float p2 = offs -
p1 / zEnd;
3714 }
else if (
type == 2) {
3716 const float offsZ = 1 + offs;
3717 const float zEndTmp = zEnd - zMaxDeltaPot + offsZ;
3718 const float p1 = deltaPot / (1 / offsZ - 1 / zEndTmp);
3719 const float p2 = -
p1 / zEndTmp;
3720 const float absZShifted = absZ - zMaxDeltaPot + offsZ;
3723 }
else if (
type == 0 ||
type == 3) {
3725 const float zPos = absZ - zEnd;
3726 return static_cast<DataT>(deltaPot / (absZMaxDeltaPot - zEnd) * zPos + offs);
3730 }
else if (
type == 3) {
3736 setPotentialBoundaryInnerRadius(chargeUpIFCLinear,
side);
3739template <
typename DataT>
3742 initContainer(mGlobalCorrdR[
side],
true);
3743 initContainer(mGlobalCorrdZ[
side],
true);
3744 initContainer(mGlobalCorrdRPhi[
side],
true);
3746#pragma omp parallel for num_threads(sNThreads)
3747 for (
unsigned int iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) {
3750 phi = o2::math_utils::detail::toPMPi(phi);
3752 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3754 const DataT x = getXFromPolar(radius, phi);
3755 const DataT y = getYFromPolar(radius, phi);
3757 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3764 gCorr(sector,
x,
y,
z, gCx, gCy, gCz);
3765 const DataT gCxCorr =
x + gCx;
3766 const DataT gCyCorr =
y + gCy;
3769 const DataT corrR = getRadiusFromCartesian(gCxCorr, gCyCorr) - radius;
3770 DataT phiDiff = getPhiFromCartesian(gCxCorr, gCyCorr) - phi;
3771 phiDiff = o2::math_utils::detail::toPMPi(phiDiff);
3772 const DataT corrRPhi = phiDiff * radius;
3775 mGlobalCorrdR[
side](iZ, iR, iPhi) = corrR;
3776 mGlobalCorrdZ[
side](iZ, iR, iPhi) = gCz;
3777 mGlobalCorrdRPhi[
side](iZ, iR, iPhi) = corrRPhi;
3783template <
typename DataT>
3786 setROCMisalignment(
type, 2, sector, potential, potential);
3789template <
typename DataT>
3792 setROCMisalignment(
type, 0, sector, potentialMin, potentialMax);
3795template <
typename DataT>
3798 setROCMisalignment(
type, 1, sector, potentialMin, potentialMax);
3801template <
typename DataT>
3804 initContainer(mPotential[
Sector(sector).
side()],
true);
3805 const auto indPhiTopIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
false,
Side::A,
false,
true);
3807 const auto rotationPoints = [](
const int regStart,
const int regEnd,
int misalignmentType,
const float potMax,
const float potMin) {
3808 if (misalignmentType == 0) {
3810 const float radStart = mapper.getPadRegionInfo(regStart).getRadiusFirstRow();
3811 const auto& padReg = mapper.getPadRegionInfo(regEnd);
3812 const float radEnd = padReg.getRadiusFirstRow() + padReg.getPadHeight() * padReg.getNumberOfPadRows() - radStart;
3813 const float rotationPoint = radStart + radEnd / 2;
3814 const float slope = (potMax - potMin) / radEnd;
3815 return std::pair<float, float>{rotationPoint,
slope};
3816 }
else if (misalignmentType == 1) {
3817 return std::pair<float, float>{0, (potMax - potMin) / 100};
3819 return std::pair<float, float>{0, (potMax + potMin) / 2};
3823 if (stackType == 0) {
3824 const auto deltaPotPar = rotationPoints(0, 3, misalignmentType, potMax, potMin);
3825 const auto indPhiBottomIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
true,
Side::A,
false,
true);
3826 fillROCMisalignment(indPhiTopIROC, indPhiBottomIROC, sector, misalignmentType, deltaPotPar);
3827 }
else if (stackType == 1) {
3828 const auto deltaPotPar = rotationPoints(4, 9, misalignmentType, potMax, potMin);
3829 const auto indPhiTopOROC3 = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::OROC3gem,
false,
Side::A,
false,
true);
3830 fillROCMisalignment(indPhiTopOROC3, indPhiTopIROC, sector, misalignmentType, deltaPotPar);
3831 }
else if (stackType == 2) {
3832 const auto deltaPotPar = rotationPoints(0, 9, misalignmentType, potMax, potMin);
3833 const auto indPhiBottomIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::IROCgem,
true,
Side::A,
false,
true);
3834 const auto indPhiTopOROC3 = getPotentialBoundaryGEMFrameAlongPhiIndices(
GEMstack::OROC3gem,
false,
Side::A,
false,
true);
3835 fillROCMisalignment(indPhiTopIROC, indPhiBottomIROC, sector, misalignmentType, deltaPotPar);
3836 fillROCMisalignment(indPhiTopOROC3, indPhiTopIROC, sector, misalignmentType, deltaPotPar);
3840template <
typename DataT>
3841void SpaceCharge<DataT>::fillROCMisalignment(
const std::vector<size_t>& indicesTop,
const std::vector<size_t>& indicesBottom,
int sector,
int misalignmentType,
const std::pair<float, float>& deltaPotPar)
3843 for (
const auto&
index : indicesTop) {
3849 if ((sector != -1) && (sectorTmp != sector)) {
3852 const Sector sec(sectorTmp);
3854 for (
size_t iR = iRStart; iR > 0; --iR) {
3855 const size_t currInd = (iZ + getNZVertices() * (iR + iPhi * getNRVertices()));
3856 const bool foundVertexBottom = std::binary_search(indicesBottom.begin(), indicesBottom.end(), currInd);
3857 if (foundVertexBottom) {
3862 const float rPos =
getRVertex(iR, sec.side());
3864 const float zPos =
getZVertex(iZ, sec.side());
3865 const float x = getXFromPolar(rPos, phiPos);
3866 const float y = getYFromPolar(rPos, phiPos);
3870 if (misalignmentType == 0) {
3871 deltaPot = (lPos.X() - deltaPotPar.first) * deltaPotPar.second;
3872 }
else if (misalignmentType == 1) {
3873 deltaPot = lPos.Y() * deltaPotPar.second;
3875 deltaPot = deltaPotPar.second;
3877 mPotential[sec.side()](iZ, iR, iPhi) += deltaPot;
3882template <
typename DataT>
3885 mGlobalCorrdR[
side] -= otherSC.mGlobalCorrdR[
side];
3886 mGlobalCorrdZ[
side] -= otherSC.mGlobalCorrdZ[
side];
3887 mGlobalCorrdRPhi[
side] -= otherSC.mGlobalCorrdRPhi[
side];
3890template <
typename DataT>
3893 mGlobalDistdR[
side] -= otherSC.mGlobalDistdR[
side];
3894 mGlobalDistdZ[
side] -= otherSC.mGlobalDistdZ[
side];
3895 mGlobalDistdRPhi[
side] -= otherSC.mGlobalDistdRPhi[
side];
3898template <
typename DataT>
3903 mGlobalCorrdRPhi[
side] *=
val;
3906template <
typename DataT>
3909 initContainer(mDensity[
side],
true);
3910 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3911 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3912 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3913 for (
unsigned int iPhi = 0; iPhi <= (verticesPerSector / 2); ++iPhi) {
3914 float meanDensity = 0;
3915 for (
int iter = 0; iter < 2; ++iter) {
3917 const int iPhiTmpA = iPhi + sec * verticesPerSector;
3918 const int iPhiTmpB = ((sec + 1) * verticesPerSector - iPhi) % mParamGrid.NPhiVertices;
3920 meanDensity += mDensity[
side](iZ, iR, iPhiTmpA);
3921 meanDensity += mDensity[
side](iZ, iR, iPhiTmpB);
3924 mDensity[
side](iZ, iR, iPhiTmpA) = densMean;
3925 mDensity[
side](iZ, iR, iPhiTmpB) = densMean;
3934template <
typename DataT>
3938 initContainer(mDensity[
side],
true);
3939 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3941 const int iPhiFirst = sectorInSide * verticesPerSector;
3942 const int iPhiLast = iPhiFirst + verticesPerSector;
3943 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3944 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3945 for (
unsigned int iPhi = iPhiFirst; iPhi < iPhiLast; ++iPhi) {
3946 mDensity[
side](iZ, iR, iPhi) *= scalingFactor;
3952template <
typename DataT>
3956 initContainer(mDensity[
side],
true);
3957 const int verticesPerSector = mParamGrid.NPhiVertices /
SECTORSPERSIDE;
3959 const int iPhiFirst = sectorInSide * verticesPerSector;
3960 const int iPhiLast = iPhiFirst + verticesPerSector;
3961 for (
unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) {
3963 for (
unsigned int iPhi = iPhiFirst; iPhi < iPhiLast; ++iPhi) {
3969 for (
unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) {
3970 mDensity[
side](iZ, iR, iPhi) *= scalingFactor;
3977template <
typename DataT>
3980 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);
3981 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);
3984template <
typename DataT>
3988 std::vector<float> dRphi;
3989 std::vector<float>
r;
3990 dRphi.reserve(nPoints);
3992 for (
int i = 0;
i < nPoints; ++
i) {
3993 float radius = rmin +
i;
3994 float z = tgl * radius;
3999 dRphi.emplace_back(distRPhi);
4000 r.emplace_back(radius);
4003 TF1 fPol(
"pol2",
"pol2", rmin,
r.back());
4004 fPol.SetParameter(0, 0);
4005 fPol.SetParameter(1, 0);
4006 fPol.SetParameter(2, 0);
4007 TGraph gr(
r.size(),
r.data(), dRphi.data());
4008 gr.Fit(&fPol,
"QNRC");
4009 float dca = fPol.Eval(0);
4011 std::vector<double>
params{fPol.GetParameter(0), fPol.GetParameter(1), fPol.GetParameter(2)};
4012 std::vector<float> rInterpol;
4013 std::vector<float> dRPhiInterpol;
4014 std::vector<float> distanceInterpol;
4016 for (
int i = 0;
i < 500; ++
i) {
4017 float radius = rmin + float(
i) / 10;
4018 rInterpol.emplace_back(radius);
4019 dRPhiInterpol.emplace_back(fPol.Eval(radius));
4020 distanceInterpol.emplace_back(std::sqrt(rInterpol.back() * rInterpol.back() + dRPhiInterpol.back() * dRPhiInterpol.back()));
4023 for (
int i = -200;
i < 200; ++
i) {
4024 float radius = float(
i) / 10;
4025 rInterpol.emplace_back(radius);
4026 dRPhiInterpol.emplace_back(fPol.Eval(radius));
4027 distanceInterpol.emplace_back(std::sqrt(rInterpol.back() * rInterpol.back() + dRPhiInterpol.back() * dRPhiInterpol.back()));
4029 (*pcstream) <<
"tree"
4031 <<
"dRphi=" << dRphi
4034 <<
"rInterpol=" << rInterpol
4035 <<
"dRPhiInterpol=" << dRPhiInterpol
4036 <<
"distanceInterpol=" << distanceInterpol