7 #include <unordered_map>
17 struct SubMatrixData {
18 enum EEdgeLocation {kXmin, kXmax, kYmin, kYmax, kNEdgeLocations};
19 enum EEdgeType {kOuter,kInner,kInternal, kDeadZoneOuter, kDeadZoneInner};
20 static double invOrZero(
double a) {
return a>0 ? 1./
a : 0.; }
25 const std::array<unsigned int,2> &
idx,
26 const std::array<unsigned int,2> &
dim,
27 const std::array<unsigned int,2> &chip_dim,
28 const std::array<SubMatrixData::EEdgeType, SubMatrixData::kNEdgeLocations> &edge_type,
30 unsigned int submatrix_idx,
31 unsigned int split_idx) :
43 const std::array<unsigned int,2> &
dim,
44 const std::array<unsigned int,2> &chip_dim)
47 std::array<SubMatrixData::EEdgeType, SubMatrixData::kNEdgeLocations>{kOuter,kOuter,kOuter,kOuter},
48 s_defaultMatrixAttribute,
55 std::array<unsigned int,2>
m_idx;
56 std::array<unsigned int,2>
m_dim;
65 void splitMatrix(
const SubMatrixData &matrix_data,
66 std::array<unsigned int,2> split_idx,
67 const std::array<PixelDiodeTree::Vector2D,2> &
width,
68 const std::array<std::array<unsigned int, 2>,2> &split_chip_dim,
69 const std::array<bool,2> &dead_zone_split,
70 const std::array<std::array<PixelDiodeTree::AttributeType, 2>,2> &attribute,
72 std::vector<SubMatrixData> &sub_matrix_list,
73 PixelDiodeTree &diode_tree,
74 std::ostream *debug_out,
75 const std::array<std::string,SubMatrixData::kDeadZoneInner+1> *edgeName)
77 std::array<std::array<unsigned int,2>,2> new_dim;
78 for (
unsigned int axis_i=0; axis_i<2; ++axis_i) {
79 if (split_idx[axis_i] < matrix_data.m_idx[axis_i]+matrix_data.m_dim[axis_i]) {
82 new_dim[0][axis_i]=split_idx[axis_i]-matrix_data.m_idx[axis_i];
83 new_dim[1][axis_i]=matrix_data.m_idx[axis_i] + matrix_data.m_dim[axis_i] - split_idx[axis_i];
88 new_dim[0][axis_i]=matrix_data.m_dim[axis_i];
94 (*debug_out) <<
"Split (sub) matrix "
95 << matrix_data.m_idx[0] <<
" , " << matrix_data.m_idx[1] <<
" "
96 << matrix_data.m_dim[0] <<
"x" << matrix_data.m_dim[1] <<
" : "
97 << split_idx[0] <<
" < " << matrix_data.m_dim[0]+matrix_data.m_idx[0]
98 <<
" , " << split_idx[1] <<
" < " << matrix_data.m_dim[1]+matrix_data.m_idx[1]
99 <<
" -> " << (*edgeName)[matrix_data.m_edgeType[ 0 + 2*0]] <<
" | "
100 << new_dim[0][0] <<
" | " << new_dim[1][0] <<
" | " << (*edgeName)[matrix_data.m_edgeType[ 1 + 2*0]]
101 <<
" , " << (*edgeName)[matrix_data.m_edgeType[ 0 + 2*1]] <<
" | " << new_dim[0][1]
102 <<
" | " << new_dim[1][1] <<
" | " << (*edgeName)[matrix_data.m_edgeType[ 1 + 2*1]]
107 std::array<unsigned int,2> axis_split_i;
110 for (axis_split_i[0]=0; axis_split_i[0]<2; ++axis_split_i[0]) {
111 if (new_dim[axis_split_i[0]][0]==0) {
continue; }
112 for (axis_split_i[1]=0; axis_split_i[1]<2; ++axis_split_i[1]) {
113 if (new_dim[axis_split_i[1]][1]==0)
continue;
115 std::array<unsigned int,2>
idx(matrix_data.m_idx);
116 std::array<SubMatrixData::EEdgeType, SubMatrixData::kNEdgeLocations> edge_type;
117 for (
unsigned int axis_i=0; axis_i<2; ++axis_i) {
118 if (axis_split_i[axis_i]>0) {
120 idx[axis_i] = split_idx[axis_i];
122 edge_type[axis_split_i[axis_i] + 2*axis_i] = matrix_data.m_edgeType[ axis_split_i[axis_i] + 2*axis_i];
123 unsigned int other_side_i=axis_split_i[axis_i]^1;
126 edge_type[other_side_i + 2*axis_i] = (new_dim[other_side_i][axis_i]>0
127 ? (split_chip_dim[axis_split_i[axis_i]][axis_i]>0
128 ? SubMatrixData::kInner
129 : SubMatrixData::kInternal )
130 : matrix_data.m_edgeType[ other_side_i + 2*axis_i] );
133 if (dead_zone_split[axis_i]) {
134 for (
unsigned int side_i=0; side_i<2; ++side_i) {
135 if (edge_type[side_i+2*axis_i]==SubMatrixData::kInternal) {
136 unsigned int other_side_i=(side_i^1);
137 edge_type[side_i+2*axis_i]=( ( matrix_data.m_edgeType[side_i+2*axis_i] == SubMatrixData::kInner
138 || matrix_data.m_edgeType[other_side_i+2*axis_i] == SubMatrixData::kInner)
139 ? SubMatrixData::kDeadZoneInner
140 : (( matrix_data.m_edgeType[side_i+2*axis_i] == SubMatrixData::kOuter
141 || matrix_data.m_edgeType[other_side_i+2*axis_i] == SubMatrixData::kOuter)
142 ? SubMatrixData::kDeadZoneOuter
143 : SubMatrixData::kInternal));
144 if (edge_type[side_i+2*axis_i]==SubMatrixData::kInternal) {
145 throw std::logic_error(
"Deadzone not next to an inner or outer edge." );
157 matrix_data.m_pos+
width[0],
158 matrix_data.m_attribute,
159 matrix_data.m_subMatrixIdx,
160 matrix_data.m_splitIdx);
162 unsigned int split_i= axis_split_i[0]+axis_split_i[1]*2;
164 (*debug_out) <<
"new sub matrix : "
165 << sub_matrix_idx <<
" . " << split_i <<
" axis sides "
166 << axis_split_i[0] <<
" , " << axis_split_i[1] <<
" : "
167 << std::setw(4) <<
idx[0] <<
", " << std::setw(4) <<
idx[1]
168 <<
" dim " << std::setw(4) << new_dim[axis_split_i[0]][0] <<
" , " << std::setw(4) << new_dim[axis_split_i[1]][1]
169 <<
" " << std::setw(6) <<
pos[0] <<
", " << std::setw(6) <<
pos[1]
170 <<
" w " << std::setw(6) <<
width[axis_split_i[0]][0] <<
" , " << std::setw(6) <<
width[axis_split_i[1]][1]
171 <<
" chips " << split_chip_dim[axis_split_i[0]][0] <<
" , " << split_chip_dim[axis_split_i[1]][1]
172 <<
" edges " << (*edgeName)[edge_type[0]] <<
"|" << (*edgeName)[edge_type[1]] <<
" , "
173 << (*edgeName)[edge_type[2]] <<
"|" << (*edgeName)[edge_type[3]]
178 if (new_dim[axis_split_i[0]][0] > matrix_data.m_dim[0] && new_dim[axis_split_i[1]][1] > matrix_data.m_dim[1]) {
179 throw std::logic_error(
"splitter increased size.");
183 width[axis_split_i[1]][1]},
184 idx, std::array<unsigned int,2>{new_dim[axis_split_i[0]][0],new_dim[axis_split_i[1]][1]},
185 std::array<unsigned int, 2>{split_chip_dim[axis_split_i[0]][0],split_chip_dim[axis_split_i[1]][1]},
187 attribute[axis_split_i[0]][axis_split_i[1]],
210 unsigned int diodeIndex()
const {
return m_idx; }
225 const std::array<unsigned int,2> &chip_matrix_dim,
227 const std::array<std::array<unsigned int,2>,2> &edge_dim,
228 const std::array<PixelDiodeTree::Vector2D,2> &edge_pitch,
229 const std::array<std::array<unsigned int,2>,2> &dead_zone,
231 std::ostream *debug_out) {
245 std::array<unsigned int,2>
dim{};
248 for (
unsigned int axis_i=0; axis_i<2; ++axis_i) {
249 dim[axis_i] = chip_dim[axis_i] * chip_matrix_dim[axis_i];
250 unsigned int n_inner_edges = chip_dim[axis_i]*2-2 ;
251 constexpr
unsigned int n_outer_edges = 2;
252 width[axis_i] = ( ( chip_dim[axis_i]*chip_matrix_dim[axis_i]
253 - edge_dim[kInner][axis_i]*n_inner_edges
254 - edge_dim[kOuter][axis_i]*n_outer_edges ) * pitch[axis_i]
255 + edge_dim[kInner][axis_i]*edge_pitch[kInner][axis_i]*n_inner_edges
256 + edge_dim[kOuter][axis_i]*edge_pitch[kOuter][axis_i]*n_outer_edges);
259 std::unordered_map<unsigned int, DiodeInfo > diode_idx;
261 std::array<std::string,SubMatrixData::kDeadZoneInner+1> edgeName {
262 std::string(
"Outer"),
263 std::string(
"Inner"),
264 std::string(
"Internal"),
265 std::string(
"DeadZoneOuter"),
266 std::string(
"DeadZoneInner")
270 std::vector< SubMatrixData > stack;
271 stack.emplace_back(
width,
dim, chip_dim);
272 while (!stack.empty()) {
273 SubMatrixData current_submatrix = std::move(stack.back());
274 const std::array<unsigned int,2 > &split_chip_dim = current_submatrix.m_chipDim;
277 std::array<PixelDiodeTree::Vector2D,2> split_width{current_submatrix.m_width,
279 std::array<unsigned int,2> split_idx{current_submatrix.m_idx[0]+current_submatrix.m_dim[0],
280 current_submatrix.m_idx[1]+current_submatrix.m_dim[1]};
281 std::array<std::array<unsigned int,2>,2 > new_chip_dim{ split_chip_dim, split_chip_dim};
282 unsigned int n_sub_matrices=0;
285 *debug_out <<
"Split : " << std::setw(4) << current_submatrix.m_idx[0] <<
", " << std::setw(4) << current_submatrix.m_idx[1]
286 <<
" " << std::setw(4) << current_submatrix.m_dim[0] <<
" x " << std::setw(4) << current_submatrix.m_dim[1]
287 <<
" pos " << std::setw(6) << current_submatrix.m_pos[0] <<
" , " << std::setw(6) << current_submatrix.m_pos[1]
288 <<
" w " << std::setw(6) << current_submatrix.m_width[0] <<
" , " << std::setw(6) << current_submatrix.m_width[1]
289 <<
" chips " << current_submatrix.m_chipDim[0] <<
" x " << current_submatrix.m_chipDim[1]
290 <<
" edges: " << edgeName[current_submatrix.m_edgeType[0] ] <<
" | " << edgeName[current_submatrix.m_edgeType[1] ]
291 <<
" , " << edgeName[current_submatrix.m_edgeType[2] ] <<
" | " << edgeName[current_submatrix.m_edgeType[3] ]
296 for (
unsigned int axis_i=0; axis_i<2; ++axis_i) {
297 if (current_submatrix.m_chipDim[axis_i]>1) {
299 unsigned int odd = current_submatrix.m_chipDim[axis_i] & 1;
300 unsigned int axis_idx= current_submatrix.m_idx[axis_i];
302 for (
unsigned int part_i=0; part_i<2; ++part_i) {
303 unsigned n_chips = (current_submatrix.m_chipDim[axis_i] + odd)/2;
304 new_chip_dim[part_i][axis_i]=n_chips;
305 unsigned int n_outer_edges=(current_submatrix.m_edgeType[axis_i*2+part_i]==SubMatrixData::kOuter);
306 unsigned int n_inner_edges=n_chips*2-n_outer_edges;
307 split_idx[axis_i]=axis_idx;
308 split_width[part_i][axis_i] = ( n_chips*chip_matrix_dim[axis_i]
309 - edge_dim[kInner][axis_i]*n_inner_edges
310 - edge_dim[kOuter][axis_i]*n_outer_edges ) * pitch[axis_i]
311 + n_inner_edges*edge_dim[kInner][axis_i]*edge_pitch[kInner][axis_i]
312 + n_outer_edges*edge_dim[kOuter][axis_i]*edge_pitch[kOuter][axis_i];
313 axis_idx += n_chips * chip_matrix_dim[axis_i];
318 std::array<bool,2> dead_zone_split{};
320 if (n_sub_matrices<=1) {
322 (*debug_out) <<
"Split circuit arrays into " << n_sub_matrices <<
" sub arrays." << std::endl;
325 for (
unsigned int axis_i=0; axis_i<2; ++axis_i) {
327 std::array<unsigned int, 2> axis_edge_dim{0,0};
328 for (
unsigned int side_i=0; side_i<2; ++side_i) {
329 new_chip_dim[side_i][axis_i]=0
u;
330 if (current_submatrix.m_edgeType[axis_i*2+side_i]<SubMatrixData::kInternal) {
331 axis_edge_dim[side_i]=edge_dim[ kOuter + (current_submatrix.m_edgeType[axis_i*2+side_i]==SubMatrixData::kInner) ][axis_i];
336 (*debug_out) <<
"Split submatrix " << (axis_i == 0 ?
"x: " :
"y: ")
337 << edgeName[current_submatrix.m_edgeType[axis_i*2]]
339 << edgeName[current_submatrix.m_edgeType[axis_i*2+1]]
340 <<
" -> " << axis_edge_dim[0] <<
" , " << axis_edge_dim[1]
343 unsigned int axis_dim =
std::min(current_submatrix.m_dim[axis_i],chip_matrix_dim[axis_i]);
344 split_idx[axis_i]=current_submatrix.m_idx[axis_i]+axis_dim;
347 if (axis_edge_dim[0]+axis_edge_dim[1]>0 ) {
348 for (
unsigned int side_i=0; side_i<2; ++side_i) {
349 split_width[side_i][axis_i]=0.;
350 if (axis_edge_dim[side_i] > 0 ) {
351 unsigned int inner_outer = kOuter + (current_submatrix.m_edgeType[axis_i*2+side_i]==SubMatrixData::kInner);
353 split_idx[axis_i]=current_submatrix.m_idx[axis_i];
355 split_idx[axis_i] +=
std::min(axis_edge_dim[side_i], current_submatrix.m_dim[axis_i]);
357 if (split_idx[axis_i] == current_submatrix.m_idx[axis_i] + axis_dim
358 && axis_dim == edge_dim[inner_outer][axis_i]
359 && dead_zone[inner_outer][axis_i]>0
u ) {
360 split_idx[axis_i] = current_submatrix.m_idx[axis_i] + dead_zone[inner_outer][axis_i];
361 split_width[side_i][axis_i]=dead_zone[inner_outer][axis_i]*edge_pitch[inner_outer][axis_i];
362 split_width[side_i^1][axis_i]=(edge_dim[inner_outer][axis_i] - dead_zone[inner_outer][axis_i])*edge_pitch[inner_outer][axis_i];
363 dead_zone_split[axis_i]=
true;
368 split_idx[axis_i] += axis_dim -
std::min(axis_edge_dim[side_i],current_submatrix.m_dim[axis_i]) ;
370 if (split_idx[axis_i] == current_submatrix.m_idx[axis_i]
371 && axis_dim == axis_edge_dim[side_i]
372 && dead_zone[inner_outer][axis_i]>0
u ) {
373 split_idx[axis_i] = current_submatrix.m_idx[axis_i] + current_submatrix.m_dim[axis_i] - dead_zone[inner_outer][axis_i];
374 split_width[side_i][axis_i]=dead_zone[inner_outer][axis_i]*edge_pitch[inner_outer][axis_i];
375 split_width[side_i^1][axis_i]=(edge_dim[inner_outer][axis_i] - dead_zone[inner_outer][axis_i])*edge_pitch[inner_outer][axis_i];
376 dead_zone_split[axis_i]=
true;
381 if (split_idx[axis_i]<current_submatrix.m_idx[axis_i]
382 || split_idx[axis_i]>current_submatrix.m_idx[axis_i]+current_submatrix.m_dim[axis_i]
383 || (current_submatrix.m_dim[axis_i] < edge_dim[kOuter][axis_i] && current_submatrix.m_dim[axis_i] < edge_dim[kInner][axis_i])
385 throw std::logic_error(
"invalid split index.");
387 split_width[side_i][axis_i]=axis_edge_dim[side_i] * edge_pitch[inner_outer][axis_i];
389 unsigned int n_inner_edges = current_submatrix.m_edgeType[axis_i*2+(side_i^1)]==SubMatrixData::kInner;
390 unsigned int n_outer_edges = current_submatrix.m_edgeType[axis_i*2+(side_i^1)]==SubMatrixData::kOuter;
391 split_width[side_i^1][axis_i] = ( ( axis_dim
393 - edge_dim[kInner][axis_i]*(n_inner_edges+current_submatrix.m_edgeType[axis_i*2+side_i]==SubMatrixData::kInner)
394 - edge_dim[kOuter][axis_i]*(n_outer_edges+current_submatrix.m_edgeType[axis_i*2+side_i]==SubMatrixData::kOuter))
396 + edge_dim[kInner][axis_i]*edge_pitch[kInner][axis_i]*n_inner_edges
397 + edge_dim[kOuter][axis_i]*edge_pitch[kOuter][axis_i]*n_outer_edges);
403 if (n_sub_matrices>0) {
404 if( (split_idx[0]>=current_submatrix.m_idx[0]+current_submatrix.m_dim[0] || split_idx[0]==current_submatrix.m_idx[0])
405 && (split_idx[1]>=current_submatrix.m_idx[1]+current_submatrix.m_dim[1] || split_idx[1]==current_submatrix.m_idx[1])) {
412 if (n_sub_matrices>0)
416 (*debug_out) <<
"Split : " << current_submatrix.m_idx[0] <<
" , " << current_submatrix.m_idx[1] <<
" " << current_submatrix.m_dim[0] <<
"x" << current_submatrix.m_dim[1]
417 <<
" split at " << split_idx[0] <<
", " << split_idx[1]
418 <<
" " << (split_idx[0] - current_submatrix.m_idx[0]) <<
"|" << (current_submatrix.m_idx[0]+current_submatrix.m_dim[0]-split_idx[0])
419 <<
", " << (split_idx[1] - current_submatrix.m_idx[1]) <<
"|" << (current_submatrix.m_idx[1]+current_submatrix.m_dim[1]-split_idx[1])
420 <<
" width " << split_width[0][0] <<
", " << split_width[0][1] <<
"; " << split_width[1][0] <<
", " << split_width[1][1]
423 std::size_t stack_size=stack.size();
424 splitMatrix(current_submatrix,
429 std::array<std::array<PixelDiodeTree::AttributeType, 2>,2> {std::array<PixelDiodeTree::AttributeType, 2>{SubMatrixData::s_defaultMatrixAttribute,
430 SubMatrixData::s_defaultMatrixAttribute},
431 std::array<PixelDiodeTree::AttributeType, 2>{SubMatrixData::s_defaultMatrixAttribute,
432 SubMatrixData::s_defaultMatrixAttribute}},
437 if (stack_size == stack.size()) {
445 if (n_sub_matrices==0) {
449 if (diode_tree.
empty()) {
450 assert( stack.empty() );
451 assert( chip_dim[0]==1 && chip_dim[1]==1);
453 current_submatrix.m_subMatrixIdx
456 current_submatrix.m_pos+current_submatrix.m_width,
457 current_submatrix.m_attribute);
463 for (
unsigned int axis_i=0; axis_i<2; ++axis_i) {
465 unsigned int axis_inner_edges = ( (current_submatrix.m_edgeType[axis_i*2] == SubMatrixData::kInner)
466 + (current_submatrix.m_edgeType[axis_i*2+1] == SubMatrixData::kInner));
467 unsigned int axis_outer_edges = ( (current_submatrix.m_edgeType[axis_i*2] == SubMatrixData::kOuter)
468 + (current_submatrix.m_edgeType[axis_i*2+1] == SubMatrixData::kOuter));
472 unsigned int diode_type = ((axis_inner_edges * edge_dim[kInner][axis_i]) > 0) << (kInner+1);
473 diode_type |= ((axis_outer_edges * edge_dim[kOuter][axis_i]) > 0) << (kOuter+1);
478 if ( current_submatrix.m_edgeType[axis_i*2]>SubMatrixData::kInternal
479 || current_submatrix.m_edgeType[axis_i*2+1]>SubMatrixData::kInternal) {
480 diode_type = ((current_submatrix.m_edgeType[axis_i*2]==SubMatrixData::kDeadZoneInner) << (kInner+1))
481 | ((current_submatrix.m_edgeType[axis_i*2+1]==SubMatrixData::kDeadZoneInner) << (kInner+1))
482 | ((current_submatrix.m_edgeType[axis_i*2]==SubMatrixData::kDeadZoneOuter) << (kOuter+1))
483 | ((current_submatrix.m_edgeType[axis_i*2+1]==SubMatrixData::kDeadZoneOuter) << (kOuter+1));
487 n = current_submatrix.m_dim[axis_i] - edge_dim[kOuter][axis_i] *axis_outer_edges - edge_dim[kInner][axis_i] * axis_inner_edges;
489 diode_type |= (
n>0) << 0
u;
491 *debug_out << (axis_i==0 ?
"x: " :
"y:" )
492 <<
" outer " << axis_outer_edges <<
" * " << edge_dim[kOuter][axis_i] <<
" * " << edge_pitch[kOuter][axis_i]
493 <<
" inner " << axis_inner_edges <<
" * " << edge_dim[kInner][axis_i] <<
" * " << edge_pitch[kInner][axis_i]
495 <<
" -> " << diode_type
499 switch (diode_type) {
501 diode_width[axis_i]=pitch[axis_i];
503 case (1
u<<(kOuter+1)):
504 diode_width[axis_i]=edge_pitch[kOuter][axis_i];
506 case (1
u<<(kInner+1)):
507 diode_width[axis_i]=edge_pitch[kInner][axis_i];
510 throw std::logic_error(
"Invalid diode type. Matrix not fully split.");
515 diode_type|=ganged<<3
u;
516 full_diode_type|=(diode_type&0xff);
521 std::array<bool,4> ganged_flags{ (
static_cast<std::size_t
>(full_diode_type) & (1
u<<3
u)) != 0
u,
522 (
static_cast<std::size_t
>(full_diode_type) & (1
u<<(3
u+8
u))) != 0
u,
523 current_submatrix.m_edgeType[0]==SubMatrixData::kInner
524 || current_submatrix.m_edgeType[0+1]==SubMatrixData::kInner
525 || current_submatrix.m_edgeType[0]==SubMatrixData::kOuter
526 || current_submatrix.m_edgeType[0+1]==SubMatrixData::kOuter,
527 current_submatrix.m_edgeType[2]==SubMatrixData::kInner
528 || current_submatrix.m_edgeType[2+1]==SubMatrixData::kInner
529 || current_submatrix.m_edgeType[2]==SubMatrixData::kOuter
530 || current_submatrix.m_edgeType[2+1]==SubMatrixData::kOuter};
532 ganged_flags[2]=ganged_flags[2]&ganged_flags[0];
533 ganged_flags[3]=ganged_flags[3]&ganged_flags[1];
536 auto [new_sub_matrix_attribute, new_diode_attribute]
537 = func_compute_attribute(std::array<PixelDiodeTree::CellIndexType,2>{
static_cast<PixelDiodeTree::CellIndexType>(current_submatrix.m_idx[0]),
541 current_submatrix.m_splitIdx,
542 current_sub_matrix_attribute,
548 unsigned int diode_idx = diode_tree.
addDiode(diode_width,
549 new_diode_attribute);
551 ret.first->second.setIndex( diode_idx );
553 assert( ret.second || ret.first->second.attributeAgrees(new_diode_attribute) );
554 diode_tree.
setAttribute(current_submatrix.m_subMatrixIdx, new_sub_matrix_attribute);
555 assert( current_sub_matrix_attribute==SubMatrixData::s_defaultMatrixAttribute
556 || current_sub_matrix_attribute==new_sub_matrix_attribute);
558 diode_tree.
setDiodeForSubMatrix(current_submatrix.m_subMatrixIdx, current_submatrix.m_splitIdx,ret.first->second.diodeIndex());
560 (*debug_out) <<
"Created Diode "
561 << current_submatrix.m_idx[0] <<
", " << current_submatrix.m_idx[1] <<
" "
562 << current_submatrix.m_dim[0] <<
" x " << current_submatrix.m_dim[1]
563 <<
" attr: " << new_sub_matrix_attribute
564 <<
" : diode_pitch " << diode_width[0] <<
", " << diode_width[1]
565 <<
" sub-matrix index " << current_submatrix.m_subMatrixIdx
566 <<
" split index " << current_submatrix.m_splitIdx
568 <<
" attribute " << full_diode_type <<
" -> " << new_diode_attribute
574 throw std::logic_error(
"Some splits have invalid indices. That should not happen.");