Skip to content
Snippets Groups Projects
Commit f9c4f980 authored by David Gutiérrez Menéndez's avatar David Gutiérrez Menéndez Committed by Pierre-Alain Loizeau
Browse files

Correct STS channel mapping

parent 2431097a
No related branches found
No related tags found
1 merge request!1959Correct STS channel mapping
Pipeline #31955 passed
/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: David Gutierrez [committer], Dario Ramirez */
#pragma once
#include "Definitions.h"
#include <cassert>
#include <cstdlib>
#include <optional>
namespace cbm::algo::sts
{
/** @brief STS Module parameters
**/
class Module {
public:
static constexpr u16 CHANNELS_PER_ASIC = 128;
static constexpr u16 ASICS_PER_MODULE = 16;
static constexpr u16 CHANNELS_PER_MODULE = CHANNELS_PER_ASIC * ASICS_PER_MODULE;
static_assert(CHANNELS_PER_ASIC > 0, "ASICs must have at least one chanhel.");
static_assert(ASICS_PER_MODULE > 0, "Modules must have at least one asic.");
static constexpr u16 ZSTRIP_ASIC = 8;
static constexpr u16 ZSTRIP_HW_CHANNEL = 127;
static constexpr u16 ZSTRIP_SW_CHANNEL = 2046;
static constexpr u16 ZSTRIP_OFFSET = ZSTRIP_SW_CHANNEL - 1022;
/** @brief Channel HW to SW conversion
** @param elink_chn Channel number in elink (HW)
** @param asic_idx ASIC index in module
** @return channel Channel number in SW
**/
static inline std::optional<u16> ChannelInModule(const u16 elink_chn, const u16 asic_idx)
{
if (elink_chn >= CHANNELS_PER_ASIC || asic_idx >= ASICS_PER_MODULE) return std::nullopt;
const u16 channel =
CHANNELS_PER_ASIC * asic_idx + elink_chn // n side
+ (2 * asic_idx >= ASICS_PER_MODULE)
* ( // p side
CHANNELS_PER_ASIC - 1 - 2 * elink_chn // revert channels in asic
- (elink_chn & 0b1) * 2 // shift odd channels to the left
+ (elink_chn == ZSTRIP_HW_CHANNEL && asic_idx == ZSTRIP_ASIC) * ZSTRIP_OFFSET // correct z-strip 1
);
return (channel < CHANNELS_PER_MODULE) ? std::make_optional(channel) : std::nullopt;
}
/** @brief Channel SW to HW conversion
** @param channel Channel number in module (SW)
** @param chan_per_asic Channels per ASIC
** @param asic_per_module ASICs per module
** @return elink_chn, asic_idx Channel number in elink (HW) and asic ASIC in module
**/
static inline std::optional<std::pair<u16, u16>> ChannelInAsic(const u16 channel)
{
if (channel >= CHANNELS_PER_MODULE) return std::nullopt;
auto [asic_idx, elink_chn] =
std::div(channel // n side
+ (2 * channel >= CHANNELS_PER_MODULE)
* ( // p side
-(channel == ZSTRIP_SW_CHANNEL) * ZSTRIP_OFFSET // correct z-strip 1
+ (!(channel & 0b1)) * 2 // shift even channels to the right
),
CHANNELS_PER_ASIC);
elink_chn += (2 * asic_idx >= ASICS_PER_MODULE)
* ( // p side
CHANNELS_PER_ASIC - 1 - 2 * elink_chn // revert channels in asic
);
return (asic_idx < ASICS_PER_MODULE || elink_chn < CHANNELS_PER_ASIC)
? std::make_optional(std::make_pair(elink_chn, asic_idx))
: std::nullopt;
}
};
} // namespace cbm::algo::sts
......@@ -5,10 +5,12 @@
#include "UnpackMS.h"
#include "AlgoFairloggerCompat.h"
#include "StsRecoUtils.h"
#include "StsXyterMessage.h"
#include <cassert>
#include <cmath>
#include <cstdint>
#include <utility>
#include <vector>
......@@ -122,18 +124,14 @@ namespace cbm::algo::sts
}
// --- Check for masked channel
if (!elinkPar.fChanMask.empty() && elinkPar.fChanMask[message.GetHitChannel()] == true) {
const uint16_t msg_channel = message.GetHitChannel();
if (!elinkPar.fChanMask.empty() && elinkPar.fChanMask[msg_channel] == true) {
return;
}
// --- Hardware-to-software address
uint32_t channel = 0;
if (asicNr < fParams.fNumAsicsPerModule / 2) { // front side (n side); channels counted upward
channel = message.GetHitChannel() + fParams.fNumChansPerAsic * asicNr;
}
else { // back side (p side); channels counted downward
channel = fParams.fNumChansPerAsic * (asicNr + 1) - message.GetHitChannel() - 1;
}
const auto maybe_channel = Module::ChannelInModule(msg_channel, asicNr);
if (!maybe_channel.has_value()) return;
// --- Expand time stamp to time within timeslice (in clock cycle)
uint64_t messageTime = message.GetHitTimeBinning() + time.currentEpochTime;
......@@ -159,10 +157,11 @@ namespace cbm::algo::sts
}
// --- Create output digi
digiVec.emplace_back(elinkPar.fAddress, channel, messageTime, charge);
digiVec.emplace_back(elinkPar.fAddress, *maybe_channel, messageTime, charge);
if (fParams.fWriteAux) {
aux.fQaDigis.emplace_back(message.IsHitMissedEvts(), elinkPar.fAddress, channel, messageTime, charge, elink);
aux.fQaDigis.emplace_back(message.IsHitMissedEvts(), elinkPar.fAddress, *maybe_channel, messageTime, charge,
elink);
}
}
// --------------------------------------------------------------------------
......
......@@ -22,6 +22,7 @@ AddBasicTest(_GTestYamlConfig)
AddBasicTest(_GTestPartitionedVector)
AddBasicTest(_GTestPartitionedSpan)
AddBasicTest(_GTestTrdClusterizer)
AddBasicTest(_GTestChannelMapping)
if (DEFINED ENV{RAW_DATA_PATH})
set(RAW_DATA_PATH $ENV{RAW_DATA_PATH})
......
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: David Gutierrez [committer], Dario Ramirez */
#include "Definitions.h"
#include "detectors/sts/StsRecoUtils.h"
#include <array>
#include <optional>
#include <gtest.h>
#include <gtest/gtest-death-test.h>
#include <gtest/gtest.h>
#define EXPECT_OPT(maybe_val1, val2) \
ASSERT_TRUE(maybe_val1.has_value()); \
EXPECT_EQ(*maybe_val1, val2)
using namespace cbm::algo;
using namespace cbm::algo::sts;
TEST(_ChannelMapping, FailOnValueLimits)
{
EXPECT_EQ(Module::ChannelInModule(Module::CHANNELS_PER_ASIC + 1, 0), std::nullopt);
EXPECT_EQ(Module::ChannelInModule(0, Module::ASICS_PER_MODULE + 1), std::nullopt);
}
TEST(_ChannelMapping, ReverseFailOnValueLimits)
{
EXPECT_EQ(Module::ChannelInAsic(Module::CHANNELS_PER_MODULE + 1), std::nullopt);
}
TEST(_ChannelMapping, ModuleEdgesMapping)
{
EXPECT_OPT(Module::ChannelInModule(0, 0), 0);
EXPECT_OPT(Module::ChannelInModule(127, 7), 1023);
EXPECT_OPT(Module::ChannelInModule(127, 8), 2046);
EXPECT_OPT(Module::ChannelInModule(125, 8), 1024);
EXPECT_OPT(Module::ChannelInModule(0, 15), 2047);
}
TEST(_ChannelMapping, ReverseModuleEdgesMapping)
{
{
const auto expect = std::make_pair<u16, u16>(0, 0);
EXPECT_OPT(Module::ChannelInAsic(0), expect);
}
{
const auto expect = std::make_pair<u16, u16>(127, 7);
EXPECT_OPT(Module::ChannelInAsic(1023), expect);
}
{
const auto expect = std::make_pair<u16, u16>(127, 8);
EXPECT_OPT(Module::ChannelInAsic(2046), expect);
}
{
const auto expect = std::make_pair<u16, u16>(125, 8);
EXPECT_OPT(Module::ChannelInAsic(1024), expect);
}
{
const auto expect = std::make_pair<u16, u16>(0, 15);
EXPECT_OPT(Module::ChannelInAsic(2047), expect);
}
}
TEST(_ChannelMapping, ExaustiveMapping)
{
for (u16 channel = 0; channel < Module::CHANNELS_PER_MODULE; channel++) {
const auto maybe_hw = Module::ChannelInAsic(channel);
ASSERT_TRUE(maybe_hw.has_value());
const auto maybe_sh = Module::ChannelInModule(maybe_hw->first, maybe_hw->second);
EXPECT_OPT(maybe_sh, channel);
}
}
TEST(_ChannelMapping, Compatibility)
{
for (u16 asic = 0; asic < Module::ASICS_PER_MODULE / 2; asic++) { // n side
for (u16 chn = 0; chn < Module::CHANNELS_PER_ASIC; chn++) {
const auto legacy = asic * Module::CHANNELS_PER_ASIC + chn;
const auto maybe_sw = Module::ChannelInModule(chn, asic);
EXPECT_OPT(maybe_sw, legacy);
}
}
for (u16 asic = Module::ASICS_PER_MODULE / 2; asic < Module::ASICS_PER_MODULE; asic++) { // p side
for (u16 chn = 0; chn < Module::CHANNELS_PER_ASIC; chn += 2) { // even channels
const auto legacy = (asic + 1) * Module::CHANNELS_PER_ASIC - chn - 1;
const auto maybe_sw = Module::ChannelInModule(chn, asic);
EXPECT_OPT(maybe_sw, legacy);
}
for (u16 chn = 1; chn < Module::CHANNELS_PER_ASIC; chn += 2) { // odd channels
const auto legacy = (asic + 1) * Module::CHANNELS_PER_ASIC - chn - 1;
const auto maybe_sw = Module::ChannelInModule(chn, asic);
if ((asic == 8) && (chn == 127)) { // z-strip
EXPECT_OPT(maybe_sw, 2046);
EXPECT_EQ(1024, legacy);
}
else {
EXPECT_OPT(maybe_sw, legacy - 2);
}
}
}
}
TEST(_ChannelMapping, Completness)
{
std::array<bool, Module::CHANNELS_PER_MODULE> visited = {false};
for (u16 asic = 0; asic < Module::ASICS_PER_MODULE; asic++) {
for (u16 chn = 0; chn < Module::CHANNELS_PER_ASIC; chn++) {
const auto maybe_sw = Module::ChannelInModule(chn, asic);
ASSERT_TRUE(maybe_sw.has_value());
ASSERT_LT(*maybe_sw, visited.size());
visited[*maybe_sw] = true;
}
}
for (const auto chn : visited) {
EXPECT_TRUE(chn);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment