ATLAS Offline Software
ColumnarToolWrapper.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 
8 //
9 // includes
10 //
11 
13 
17 #include <algorithm>
18 #include <cstdint>
19 #include <stdexcept>
20 #include <typeindex>
21 
22 //
23 // method implementations
24 //
25 
26 namespace columnar
27 {
30  : m_tool (val_tool)
31  {
32  constexpr unsigned numpySigned = 0;
33  constexpr unsigned numpyUnsigned = 1;
34  constexpr unsigned numpyFloat = 2;
35  std::unordered_map<std::type_index, std::pair<int,unsigned>> numpyTypes;
36  numpyTypes[typeid (float)] = { numpyFloat, sizeof (float) * 8 };
37  numpyTypes[typeid (char)] = { std::is_signed_v<char> ? numpySigned : numpyUnsigned, sizeof (char) * 8 };
38  numpyTypes[typeid (int)] = { numpySigned, sizeof (int) * 8 };
39  numpyTypes[typeid (std::uint8_t)] = { numpyUnsigned, sizeof (std::uint8_t) * 8 };
40  numpyTypes[typeid (std::uint16_t)] = { numpyUnsigned, sizeof (std::uint16_t) * 8 };
41  numpyTypes[typeid (std::uint32_t)] = { numpyUnsigned, sizeof (std::uint32_t) * 8 };
42  numpyTypes[typeid (std::uint64_t)] = { numpyUnsigned, sizeof (std::uint64_t) * 8 };
43 
44 
45  auto toolColumns = m_tool->getColumnInfo();
46  unsigned nextIndex = 1u;
47  for (auto& column : toolColumns)
48  {
49  MyColumnInfo myinfo;
50  myinfo.index = nextIndex++;
51  val_tool->setColumnIndex (column.name, myinfo.index);
52  myinfo.type = column.type;
53  switch (column.accessMode)
54  {
56  myinfo.isConst = true;
57  break;
59  myinfo.isConst = false;
60  break;
62  myinfo.isConst = false;
63  break;
64  }
65  for (unsigned dim : column.fixedDimensions)
66  myinfo.fixedDimensions *= dim;
67  myinfo.isOffset = column.isOffset;
68  myinfo.isOptional = column.isOptional;
69 
70  if (auto iter = numpyTypes.find (*column.type); iter != numpyTypes.end())
71  {
72  myinfo.numpyType = iter->second.first;
73  myinfo.numpyBits = iter->second.second;
74  }
75  const auto infoIdx = myinfo.index;
76  auto [iter, success] = m_columns.emplace (column.name, std::move (myinfo));
77  if (!success)
78  throw std::runtime_error ("column name already registered: " + column.name);
79 
80  if (m_numColumns <= infoIdx)
81  m_numColumns = infoIdx + 1;
82  }
83 
84  for (auto& column : toolColumns)
85  {
86  if (!column.offsetName.empty())
87  {
88  auto offsetIter = m_columns.find (column.offsetName);
89  if (offsetIter == m_columns.end())
90  throw std::runtime_error ("offset column name not found: " + column.offsetName);
91  if (*offsetIter->second.type != typeid (ColumnarOffsetType))
92  throw std::runtime_error ("offset column has wrong type: " + column.offsetName);
93  if (!offsetIter->second.isOffset)
94  throw std::runtime_error ("offset column is not registered as offset: " + column.offsetName);
95  m_columns.at (column.name).offsets = &*offsetIter;
96  }
97  }
98  }
99 
100 
101 
103  ColumnarToolWrapper (std::shared_ptr<IColumnarTool> val_tool)
104  : ColumnarToolWrapper (val_tool.get())
105  {
106  m_toolOwn = std::move (val_tool);
107  }
108 
109 
110 
112  ColumnarToolWrapperData (const ColumnarToolWrapper *val_wrapper) noexcept
113  : m_wrapper (val_wrapper),
114  m_data (m_wrapper->m_numColumns, nullptr),
115  m_dataSize (m_wrapper->m_numColumns, 0u),
116  m_columnIsChecked (m_wrapper->m_numColumns, false),
117  m_columnIsFilled (m_wrapper->m_numColumns, false)
118  {}
119 
120 
121 
123  setColumnVoid (const std::string& name, std::size_t size, const void *dataPtr, const std::type_info& type, bool isConst)
124  {
125  // If dataPtr is null, we use a dummy value to avoid issues in which
126  // we check whether a column exists by checking for a null pointer,
127  // which would return false for columns that were set with a
128  // nullptr.
129  if (dataPtr == nullptr)
130  {
131  if (size != 0) [[unlikely]]
132  throw std::runtime_error ("dataPtr is null but size is not zero for column: " + name);
133  static const unsigned dummyValue = 0;
134  dataPtr = &dummyValue;
135  }
136 
137  auto column = m_wrapper->m_columns.find (name);
138  if (column == m_wrapper->m_columns.end())
139  throw std::runtime_error ("unknown column name: " + name);
140 
141  if (type != *column->second.type)
142  throw std::runtime_error ("invalid type for column: " + name);
143  if (isConst && !column->second.isConst)
144  throw std::runtime_error ("assigning const vector to a non-const column: " + name);
145  if (column->second.index == 0)
146  throw std::runtime_error ("column has no index assigned: " + name);
147  if (m_columnIsFilled[column->second.index])
148  throw std::runtime_error ("column filled multiple times: " + name);
149  m_columnIsFilled[column->second.index] = true;
150  auto *castDataPtr ATLAS_THREAD_SAFE = const_cast<void*>(dataPtr);
151  m_data[column->second.index] = castDataPtr;
152  m_dataSize[column->second.index] = size;
153  }
154 
155 
156 
158  setColumnNumpy (const std::string& name, std::size_t size, const void *dataPtr, int type, unsigned bits, bool isConst)
159  {
160  auto column = m_wrapper->m_columns.find (name);
161  if (column == m_wrapper->m_columns.end())
162  throw std::runtime_error ("unknown column name: " + name);
163 
164  if (type != column->second.numpyType || bits != column->second.numpyBits)
165  throw std::runtime_error ("invalid type for column: " + name + " (expected " + std::to_string (column->second.numpyType) + "/" + std::to_string (column->second.numpyBits) + " but got " + std::to_string (type) + "/" + std::to_string (bits) + ")");
166  if (isConst && !column->second.isConst)
167  throw std::runtime_error ("assigning const vector to a non-const column: " + name);
168  if (column->second.index == 0)
169  throw std::runtime_error ("column has no index assigned: " + name);
170  if (m_columnIsFilled[column->second.index])
171  throw std::runtime_error ("column filled multiple times: " + name);
172  m_columnIsFilled[column->second.index] = true;
173  auto *castDataPtr ATLAS_THREAD_SAFE = const_cast<void*>(dataPtr);
174  m_data[column->second.index] = castDataPtr;
175  m_dataSize[column->second.index] = size;
176  }
177 
178 
179 
180  std::pair<std::size_t,const void*> ColumnarToolWrapperData ::
181  getColumnVoid (const std::string& name, const std::type_info *type, bool isConst)
182  {
183  auto column = m_wrapper->m_columns.find (name);
184  if (column == m_wrapper->m_columns.end())
185  throw std::runtime_error ("unknown column name: " + name);
186 
187  if (*type != *column->second.type)
188  throw std::runtime_error ("invalid type for column: " + name);
189  if (!isConst && column->second.isConst)
190  throw std::runtime_error ("retrieving non-const vector from a const column: " + name);
191  if (m_data[column->second.index] != nullptr)
192  return std::make_pair (m_dataSize[column->second.index],
193  m_data[column->second.index]);
194  else
195  return std::make_pair (0u, nullptr);
196  }
197 
198 
199 
202  {
203  for (auto& column : m_wrapper->m_columns)
205  }
206 
207 
208 
210  call ()
211  {
213  m_wrapper->m_tool->callVoid (m_data.data());
214  }
215 
216 
217 
219  checkColumn (const std::pair<const std::string,ColumnarToolWrapper::MyColumnInfo>& column)
220  {
221  if (m_columnIsChecked.at(column.second.index))
222  return;
223  if (!m_columnIsFilled.at(column.second.index))
224  {
225  if (!column.second.isOptional)
226  throw std::runtime_error ("column not filled: " + column.first);
227  m_columnIsChecked[column.second.index] = true;
228  return;
229  }
230 
231  ColumnarOffsetType expectedSize = 1u;
232  if (column.second.offsets)
233  {
234  checkColumn (*column.second.offsets);
235  if (m_data[column.second.offsets->second.index] == nullptr)
236  throw std::runtime_error ("offset column not filled: " + column.second.offsets->first);
237  const auto offsetIndex = column.second.offsets->second.index;
238  auto *offsetsPtr = static_cast<const ColumnarOffsetType*>(m_data[offsetIndex]);
239  expectedSize = offsetsPtr[m_dataSize[offsetIndex]-1];
240  }
241  expectedSize *= column.second.fixedDimensions;
242 
243  if (column.second.isOffset)
244  expectedSize += 1u;
245 
246  if (m_dataSize[column.second.index] != expectedSize)
247  throw std::runtime_error ("column size doesn't match expected size: " + column.first + ", found " + std::to_string (m_dataSize[column.second.index]) + " vs exptected=" + std::to_string (expectedSize) + " isOffset=" + std::to_string (column.second.isOffset));
248 
249  if (column.second.isOffset)
250  {
251  auto *dataPtr = static_cast<const ColumnarOffsetType*>(m_data[column.second.index]);
252  if (dataPtr[0] != 0)
253  throw std::runtime_error ("offset column doesn't start with 0: " + column.first);
254  }
255 
256  m_columnIsChecked[column.second.index] = true;
257  }
258 
259 
260 
261  std::vector<std::string> ColumnarToolWrapper ::
262  getColumnNames () const
263  {
264  std::vector<std::string> result;
265  for (auto& column : m_columns)
266  result.push_back (column.first);
267  std::sort (result.begin(), result.end());
268  return result;
269  }
270 
271 
272 
273  [[nodiscard]] std::vector<ColumnInfo> ColumnarToolWrapper ::
274  getColumnInfo () const
275  {
276  return m_tool->getColumnInfo();
277  }
278 }
columnar::ColumnarToolWrapperData::m_wrapper
const ColumnarToolWrapper * m_wrapper
Definition: ColumnarToolWrapper.h:211
createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:62
columnar::IColumnarTool::callVoid
virtual void callVoid(void **data) const =0
run the tool on the data vector
columnar::IColumnarTool::setColumnIndex
virtual void setColumnIndex(const std::string &name, std::size_t index)=0
set the index for the column
columnar::IColumnarTool
an interface for tools that operate on columnar data
Definition: IColumnarTool.h:214
columnar::ColumnAccessMode::input
@ input
an input column
yodamerge_tmp.dim
dim
Definition: yodamerge_tmp.py:239
get_generator_info.result
result
Definition: get_generator_info.py:21
columnar::ColumnarToolWrapperData::getColumnVoid
std::pair< std::size_t, const void * > getColumnVoid(const std::string &name, const std::type_info *type, bool isConst)
get the data for the given column in a type-erased manner
Definition: ColumnarToolWrapper.cxx:181
columnar::ColumnarToolWrapper::MyColumnInfo::index
unsigned index
Definition: ColumnarToolWrapper.h:91
columnar::ColumnarToolWrapper::MyColumnInfo::isOffset
bool isOffset
Definition: ColumnarToolWrapper.h:95
xAOD::uint8_t
uint8_t
Definition: Muon_v1.cxx:558
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
columnar::ColumnarToolWrapper::m_toolOwn
std::shared_ptr< const IColumnarTool > m_toolOwn
the owning pointer to the tool
Definition: ColumnarToolWrapper.h:81
m_data
std::vector< T > m_data
Definition: TrackTruthMatchingBaseAlg.cxx:660
columnar::ColumnarToolWrapperData::checkColumnsValid
void checkColumnsValid()
check that all columns are valid
Definition: ColumnarToolWrapper.cxx:201
columnar::ColumnarToolWrapper::MyColumnInfo::isOptional
bool isOptional
Definition: ColumnarToolWrapper.h:97
xAOD::char
char
Definition: TrigDecision_v1.cxx:38
columnar::ColumnarToolWrapper::getColumnNames
std::vector< std::string > getColumnNames() const
get information on all defined columns
Definition: ColumnarToolWrapper.cxx:262
DeMoUpdate.column
dictionary column
Definition: DeMoUpdate.py:1110
columnar::ColumnarToolWrapperData::m_data
std::vector< void * > m_data
Definition: ColumnarToolWrapper.h:213
Analysis::dummyValue
const double dummyValue
Definition: CalibrationDataInterfaceBase.h:33
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:77
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
columnar::ColumnarToolWrapper::MyColumnInfo::type
const std::type_info * type
Definition: ColumnarToolWrapper.h:87
columnar::ColumnAccessMode::output
@ output
an output column
columnar::ColumnarToolWrapperData::checkColumn
void checkColumn(const std::pair< const std::string, ColumnarToolWrapper::MyColumnInfo > &column)
Definition: ColumnarToolWrapper.cxx:219
columnar::ColumnarToolWrapper::MyColumnInfo::numpyType
int numpyType
Definition: ColumnarToolWrapper.h:99
columnar::ColumnarToolWrapperData::setColumnNumpy
void setColumnNumpy(const std::string &name, std::size_t size, const void *dataPtr, int type, unsigned bits, bool isConst)
set the data for the given column with the user passing in the type information from numpy
Definition: ColumnarToolWrapper.cxx:158
xAOD::uint16_t
setWord1 uint16_t
Definition: eFexEMRoI_v1.cxx:93
IColumnarTool.h
columnar::ColumnarToolWrapperData::setColumnVoid
void setColumnVoid(const std::string &name, std::size_t size, const void *dataPtr, const std::type_info &type, bool isConst)
set the data for the given column with the user passing in the type
Definition: ColumnarToolWrapper.cxx:123
columnar::IColumnarTool::getColumnInfo
virtual std::vector< ColumnInfo > getColumnInfo() const =0
the meta-information for the columns
columnar::ColumnarToolWrapperData::m_dataSize
std::vector< std::size_t > m_dataSize
Definition: ColumnarToolWrapper.h:214
columnar::ColumnarToolWrapperData::m_columnIsChecked
std::vector< bool > m_columnIsChecked
Definition: ColumnarToolWrapper.h:215
columnar::ColumnarToolWrapper::ColumnarToolWrapper
ColumnarToolWrapper(IColumnarTool *val_tool)
constructor: wrap the given tool (non-owning)
Definition: ColumnarToolWrapper.cxx:29
xAOD::uint64_t
uint64_t
Definition: EventInfo_v1.cxx:123
columnar::size
std::size_t size() const noexcept
Definition: ObjectRange.h:166
columnar::ColumnAccessMode::update
@ update
an updateable column
ColumnarToolWrapper.h
columnar::ColumnarToolWrapperData::m_columnIsFilled
std::vector< bool > m_columnIsFilled
Definition: ColumnarToolWrapper.h:216
columnar::ColumnarToolWrapper::getColumnInfo
std::vector< ColumnInfo > getColumnInfo() const
Definition: ColumnarToolWrapper.cxx:274
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
columnar::ColumnarToolWrapper::MyColumnInfo::numpyBits
unsigned numpyBits
Definition: ColumnarToolWrapper.h:101
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
columnar::ColumnarToolWrapper
a class that wraps an IColumnarTool for use in Python
Definition: ColumnarToolWrapper.h:36
columnar::ColumnarToolWrapper::m_tool
const IColumnarTool * m_tool
the wrapped tool
Definition: ColumnarToolWrapper.h:78
columnar::ColumnarToolWrapper::MyColumnInfo::fixedDimensions
unsigned fixedDimensions
Definition: ColumnarToolWrapper.h:93
columnar::ColumnarToolWrapperData::ColumnarToolWrapperData
ColumnarToolWrapperData(const ColumnarToolWrapper *val_wrapper) noexcept
constructor: wrap the given tool
Definition: ColumnarToolWrapper.cxx:112
unlikely
#define unlikely(x)
Definition: dictionary.h:41
columnar::ColumnarToolWrapper::m_columns
std::unordered_map< std::string, MyColumnInfo > m_columns
Definition: ColumnarToolWrapper.h:105
columnar::ColumnarToolWrapper::m_numColumns
unsigned m_numColumns
the number of columns that the tool expects (equal to the greatest column index + 1)
Definition: ColumnarToolWrapper.h:110
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
columnar
Definition: ClusterDef.h:16
columnar::ColumnarToolWrapper::MyColumnInfo::isConst
bool isConst
Definition: ColumnarToolWrapper.h:89
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:127
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
ColumnInfo.h
checker_macros.h
Define macros for attributes used to control the static checker.
columnar::ColumnarOffsetType
std::size_t ColumnarOffsetType
the type used for the size and offsets in the columnar data
Definition: IColumnarTool.h:20
columnar::ColumnarToolWrapper::MyColumnInfo
my cached information for the various columns needed
Definition: ColumnarToolWrapper.h:86
columnar::ColumnarToolWrapperData::call
void call()
call the tool
Definition: ColumnarToolWrapper.cxx:210
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65