TopoSteeringStructure.cxx 17.7 KB
Newer Older
1
/*
2
  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3
*/
4
5
6
7
8
9
10
11
12
13
14
#include "L1TopoCoreSim/TopoSteeringStructure.h"

#include "L1TopoCommon/StringUtils.h"
#include "L1TopoCommon/Exception.h"
#include "L1TopoCommon/Types.h"

#include "L1TopoConfig/LayoutConstraints.h"
#include "L1TopoConfig/L1TopoMenu.h"

#include "L1TopoInterfaces/DecisionAlg.h"
#include "L1TopoInterfaces/SortingAlg.h"
15
#include "L1TopoInterfaces/CountingAlg.h"
16
17
18
19
20

#include "L1TopoCoreSim/Connector.h"
#include "L1TopoCoreSim/InputConnector.h"
#include "L1TopoCoreSim/SortingConnector.h"
#include "L1TopoCoreSim/DecisionConnector.h"
21
#include "L1TopoCoreSim/CountingConnector.h"
22
23
24

#include "L1TopoHardware/L1TopoHardware.h"

25
26
#include "TrigConfData/L1Menu.h"

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <set>
#include <iomanip>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace TCS;
using boost::lexical_cast;

namespace {
   uint32_t interpretGenericParam(const std::string& parvalue) {
      uint32_t val;
      try {
         val  = lexical_cast<uint32_t, string>(parvalue);
      }
      catch(const boost::bad_lexical_cast & bc) {
         if( parvalue.size()>=3 && parvalue[0]==':' and parvalue[parvalue.size()-1]==':' ) {

44
            auto x = L1TopoHWParameters::get().find(parvalue.substr(1,parvalue.size()-2));
45
46
47

            string parname = parvalue.substr(1,parvalue.size()-2);

48
            if( x != L1TopoHWParameters::get().end()) {
49
50
51
               val = x->second.value;
            } else {
               cout << "Hardware constrained parameters are" << endl;
52
               for(auto & x : L1TopoHWParameters::get())
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
                  cout << "   " << x.first << endl;

               TCS_EXCEPTION("Generic parameter value " << parvalue << " has the hardware contrained parameter format, but '" << parname << "' is not listed in L1TopoHardware.cxx");
            }
         } else {
            TCS_EXCEPTION("Generic parameter value " << parvalue << " is not a uint32_t and does not match the hardware contrained parameter specification ':<parname>:' ");
         }
      }
      return val;
   }
}


TCS::TopoSteeringStructure::TopoSteeringStructure() :
   m_parameters(2 * LayoutConstraints::maxComponents(), nullptr)
{}


TopoSteeringStructure::~TopoSteeringStructure() {
   for( Connector* c: m_connectors ) 
      delete c;
74
75
   for( ParameterSpace * ps : m_parameters )
      delete ps;
76
77
}

78
TCS::StatusCode
79
80
81
TopoSteeringStructure::reset() {
   for(Connector* conn: m_connectors)
      conn->reset();
82
   return TCS::StatusCode::SUCCESS;
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
}


void
TCS::TopoSteeringStructure::print(std::ostream & o) const {
   o << "Topo Steering Structure" << endl
     << "-----------------------" << endl;

   o << "Output summary:" << endl;
   for(auto conn: outputConnectors() ) {
      o << "  " << *conn.second << endl;
   }

   o << endl 
     << "Algorithm detail:" << endl;
   for(auto nc: outputConnectors() ) {
      DecisionConnector * conn = nc.second;
      unsigned int firstBit          = conn->decision().firstBit();
      unsigned int lastBit           = conn->numberOutputBits() + firstBit - 1;
      const ConfigurableAlg* alg     = conn->algorithm();
      const Connector* inputconn     = conn->inputConnectors().back();
      const ConfigurableAlg* sortalg = inputconn->algorithm();
      o << std::setw(2) << "bits " << firstBit << "-" << lastBit << ": " << conn->name() << " [input " << inputconn->name() <<"]" << endl;
      o << *alg << endl << endl;
      o << *sortalg << endl;
   }
}


void
TCS::TopoSteeringStructure::printParameters(std::ostream & o) const {
   unsigned int idx(0);
   for(const ParameterSpace* ps: m_parameters) {
      if(ps && ps->isInitialized())
         o << "pos " << std::setw(2) << idx << ": " << ps << endl;
      idx++;
   }
}


TCS::StatusCode
124
TCS::TopoSteeringStructure::setupFromMenu(const TrigConf::L1Menu& l1menu, bool legacy, bool debug) {
125

126
127
128
129
   if(debug)
      cout << "/***************************************************************************/" << endl
           << "           L1Topo steering structure: configuring from L1 Topo Menu          " << endl
           << "/***************************************************************************/" << endl;
130

131
132
133
   //   set<TCS::inputTOBType_t> neededInputs; // Stores inputs for DecisionConnectors
   vector<string> storedConn; // Stores decision connectors in order to avoid double counting
   vector<vector<string>> confAlgorithms; // Stores algorithm name/category that have been configured in L1Menu to be used for setting the parameters
134
   vector<string> confMultAlgorithms; // Stores algorithm names that have been configured in L1Menu to be used for setting the multiplicity thresholds
135
136
137
138
139
140
141
142
143
144
145
146
147
148
   // Loop over boards in L1Menu and skip the ones that are not TOPO. Use Run-2 boards if legacy flag is on
   for (const string & boardName : l1menu.boardNames() ){
     
     auto & l1board = l1menu.board(boardName);

     if (l1board.type() != "TOPO") continue;
     if (l1board.legacy() != legacy) continue;

     // Access the connectors in the boards

     for (const string & connName : l1board.connectorNames() ){

       auto & l1conn = l1menu.connector(connName);

149
150
151
        // First configure decision algorithms
        // Look at all Topo algorithms in each connector, and get inputs from each algorithm to configure SortingConnectors
         if ( l1conn.connectorType() == TrigConf::L1Connector::ConnectorType::ELECTRICAL ) {
152

153
154
155
          for( size_t fpga : { 0, 1} ) {
	          for( size_t clock : { 0, 1} ) {
	            for( auto & tl : l1conn.triggerLines(fpga, clock) ) {
156
	     
157
158
	              const string & tlName = tl.name();
	              auto & algo = l1menu.algorithmFromTriggerline(tlName);
159
		      const string algoName = (legacy?"R2_"+algo.name():algo.name());
160
161

	              // One algorithm can have multiple trigger lines. Check the connector/algorithm has not been stored already
162
	              auto it = find(storedConn.begin(), storedConn.end(), algoName);
163
164
	              if (it == storedConn.end()) { // Algorithm/Connector does not exist: create and store it

165
	                storedConn.push_back(algoName);
166
167
168
169
170
	                vector<string> inputNames;
	                for( auto & input : algo.inputs() ) {
		                if( sortingConnector(input) == 0 ) { // if connector does not exist, create it
		                  if(debug) 
		                    cout << "L1TopoSteering: Decision algo( " << algo.name() << " ) input is not defined: " << input << ". Creating sortingConnector" << endl;
171
		   
172
173
174
175
176
177
178
179
180
181
182
183
184
185
		                  auto & sortAlgo = l1menu.algorithm(input, algo.category());
		                  if(!(sortAlgo.type() == TrigConf::L1TopoAlgorithm::AlgorithmType::SORTING ) )
		                    TCS_EXCEPTION("L1TopoSteering: Decision algo " << algo.name() << ") has as input " << input << " which is not associated to a sorting algorithm");

		                  // Create connector
		                  SortingConnector * sortConn = new SortingConnector(sortAlgo.inputs().at(0), sortAlgo.klass()+"/"+input, sortAlgo.outputs().at(0));
		                  if(debug)
		                    cout << "Adding sorting connector " << "[" << *sortConn << "]" << endl;
		                  addSortingConnector( sortConn );
		                  confAlgorithms.push_back({sortAlgo.name(), sortAlgo.category()});

		                  } // if connector does not exist
		 
		                inputNames.push_back(input);
186

187
	                } // loop over inputs
188

189
	                DecisionConnector * conn = new DecisionConnector(algoName, inputNames, algo.klass()+"/"+algoName, algo.outputs());
190
	                conn->m_decision.setNBits( algo.outputs().size() );
191

192
193
	                if(tl.name() != "UNDEF")
		                conn->m_triggers.push_back(tl);
194

195
196
197
198
	                if(debug)
		                cout << "Adding decision connector " << "[" << *conn << "]" << endl;
	                addDecisionConnector( conn );
	                confAlgorithms.push_back({algo.name(), algo.category()});
199

200
201
202
203
204
205
206
207
208
209
210
	              } else { // Connector already exists: look for it and add the trigger line
	                for(auto out : algo.outputs()){
		                auto c = m_outputLookup.find(out);
		                if (c != m_outputLookup.end()){
		                  auto conn = c->second;
		                  if(tl.name() != "UNDEF")
		                  conn->m_triggers.push_back(tl);
		                  break;
		                }
	                }
	              }
211

212
	            } // Trigger Line
213

214
	          } // Clock
215

216
          } // FPGA
217

218
         } else { // Configure optical connectors - multiplicity algorithms
219

220
221
          // In multiplicity boards all trigger lines are copied into the L1Menu::Connector 4 times (fpga 0,1 and clock 0,1)
          // Take (fpga, clock) = (0, 0)
222

223
            for( auto & tl : l1conn.triggerLines(0, 0) ) {
224

225
226
	      const string & tlName = tl.name();
	      auto & algo = l1menu.algorithmFromTriggerline(tlName);
227

228
	      if ( (algo.klass() != "eEmMultiplicity") && (algo.klass() != "eTauMultiplicity") ) continue; // Only available multiplicity algorithms so far
229
            
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
	      auto it = find(storedConn.begin(), storedConn.end(), algo.name());
	      if (it == storedConn.end()) { // Algorithm/Connector does not exist: create and store it

		storedConn.push_back(algo.name());
		if(debug)
		  cout << "L1TopoSteering: Multiplicity algo( " << algo.name() << " ) has as input " << algo.inputs().at(0) << endl;
		     
		CountingConnector * conn = new CountingConnector(algo.name(), algo.inputs().at(0), algo.klass()+"/"+algo.name(), algo.outputs().at(0));
		conn->m_count.setNBits( tl.nbits() );
		conn->m_count.setFirstBit( tl.startbit() );
		
		if(tl.name() != "UNDEF")
		  conn->m_triggers.push_back(tl);
		
		if(debug)
		  cout << "Adding count connector " << "[" << *conn << "]" << endl;
		addCountingConnector( conn );
		confMultAlgorithms.push_back( algo.name() );
	      }
	      
	    } // Trigger Line
	    
	 } // Optical connectors - multiplicities
	 
     } // Connector in l1board
     
256
257
258
   } // Board in l1menu

  
259
   if(debug)
260
     cout << "... building input connectors" << endl;
261
   for(auto sortConn : m_sortedLookup) {
262
263
264
265
266
267
268
269
270
     const string & in = sortConn.second->inputNames()[0]; // name of input
     
     if( m_inputLookup.count(in) > 0 ) continue; // InputConnector already exists

     InputConnector * conn = new InputConnector(in);
     m_connectors.push_back(conn);
     m_inputLookup[in] = conn;
     if(debug)
       cout << "Adding input connector " << "[" << *conn << "]" << endl;
271
   }
272
273
   for(auto countConn : m_countLookup) {
     const string & in = countConn.second->inputNames()[0]; // name of input
274

275
276
277
278
279
280
281
282
283
     if( m_inputLookup.count(in) > 0 ) continue; // InputConnector already exists

     InputConnector * conn = new InputConnector(in);
     m_connectors.push_back(conn);
     m_inputLookup[in] = conn;
     if(debug)
       cout << "Adding input connector " << "[" << *conn << "]" << endl;
   }
   
284
   // link the connector objects together
285
286
   TCS::StatusCode sc = linkConnectors();

287
   // instantiate the algorithms from the algorithm names in the connectors
288
   if(debug)
289
     cout << "... instantiating algorithms" << endl;
290
   sc &= instantiateAlgorithms(debug);
291

292

293
   // set algorithm parameters
294
   if(debug)
295
     cout << "... setting algorithm parameters" << endl;
296

297
298
   for ( auto & confAlgo : confAlgorithms ) {
     
299
      auto & l1algo = l1menu.algorithm(confAlgo.at(0), confAlgo.at(1));
300
301
302
303
      auto l1algoName = confAlgo.at(0);
      if (l1algo.type() == TrigConf::L1TopoAlgorithm::AlgorithmType::DECISION && legacy)
	      l1algoName ="R2_"+confAlgo.at(0);

304
      if(debug)
305
306
         cout << "TopoSteeringStructure: Parameters for algorithm with name " << l1algoName << " going to be configured." << endl;
      ConfigurableAlg * alg = AlgFactory::instance().algorithm(l1algoName);
307
     
308
309
      if(alg->isDecisionAlg())
         ( dynamic_cast<DecisionAlg *>(alg) )->setNumberOutputBits(l1algo.outputs().size());
310

311
312
      // create ParameterSpace for this algorithm
      ParameterSpace * ps = new ParameterSpace(alg->name());
313

314
      for(auto & pe : l1algo.parameters()) {
315
	 
316
317
318
         auto & pname = pe.name();
         uint32_t val = pe.value();
         uint32_t sel = pe.selection();
319

320
         if(debug)
Anil Sonay's avatar
Anil Sonay committed
321
	   cout << "Algo Name: " << l1algoName << " parameter " << ": " << setw(20) << left << pname << " value = " << setw(3) << left << val << " (selection " << sel << ")" << endl;
322
         ps->addParameter( pname, val, sel);
323
	 
324
      }
325
       
326
      for(auto & gen : l1algo.generics().getKeys()) {
327
	 
328
329
330
331
332
333
334
335
336
337
338
339
      auto pe = l1algo.generics().getObject(gen);
         string pname = gen;
         uint32_t val = interpretGenericParam(pe.getAttribute("value"));
         if (pname == "NumResultBits"){
	         if(val != l1algo.outputs().size()) {
	            TCS_EXCEPTION("Algorithm " << pname << " parameter OutputBits (" << val << ") is different from output size (" << l1algo.outputs().size() << ")");
	         }
	      continue; // ignore this, because it is defined through the output list
         }
         if(debug)
	         cout << " fixed parameter : " << setw(20) << left << pname << " value = " << setw(3) << left << val << endl;
         ps->addParameter( pname, val );
340
	 
341
      }
342
343
       
       
344
345
346
      if(debug)
         cout << " (setting parameters)";
      alg->setParameters( *ps );
347
       
348
349
      if(debug)
         cout << " --> (parameters set)";
350
351
352
       
     if(debug)
       cout << " --> (parameters stored)" << endl;
353
354
355
356
357
358
359
   } // Set parameters for Sorting/Decision algorithms

   // // set thresholds for multiplicity algorithms
   for ( auto & multAlgo : confMultAlgorithms ) {

      auto & l1algo = l1menu.algorithm(multAlgo, "MULTTOPO");

360
      if ( (l1algo.klass() != "eEmMultiplicity") && (l1algo.klass() != "eTauMultiplicity") ) continue; // Only available multiplicities for now
361
362
363
364
365
366
367
368
369
370

      ConfigurableAlg * alg = AlgFactory::instance().algorithm(l1algo.name());

      // Get L1Threshold object and pass it to CountingAlg, from where it will be propagated to and decoded in each algorithm
      // The output of each algorithm and the threshold name is the same - use output name to retrieve L1Threshold object
      auto & l1thr = l1menu.threshold( l1algo.outputs().at(0) );
      ( dynamic_cast<CountingAlg *>(alg) )->setThreshold(l1thr);

   } // Set thresholds for multiplicity algorithms
   
371
   
372
   m_isConfigured = true;
373
   
374
   if(debug)
375
     cout << "... L1TopoSteering successfully configured" << endl;
376
377
378
379
   
   return sc;
}

380

381
382
383
384
385
TCS::StatusCode
TopoSteeringStructure::addSortingConnector(SortingConnector * conn) {
   m_connectors.push_back(conn);
   for( const string & output : conn->outputNames() )
      m_sortedLookup[output] = conn;
386
   return TCS::StatusCode::SUCCESS;
387
388
389
390
}

TCS::StatusCode
TopoSteeringStructure::addDecisionConnector(DecisionConnector * conn) {
391
   m_connectors.push_back(conn); 
392
   for( const string & output : conn->outputNames() )
393
394
     m_outputLookup[output] = conn;     
   return TCS::StatusCode::SUCCESS;
395
396
397
}


398
399
400
401
402
403
404
405
406
TCS::StatusCode
TopoSteeringStructure::addCountingConnector(CountingConnector * conn) {
   m_connectors.push_back(conn);
   for( const string & output : conn->outputNames() )
      m_countLookup[output] = conn;
   return TCS::StatusCode::SUCCESS;
}


407
408
409
410
411
412
413
TCS::StatusCode
TopoSteeringStructure::linkConnectors() {

   for(TCS::Connector * conn: m_connectors)
      for(const std::string & inconn: conn->inputNames())
         conn->inputConnectors().push_back( connector(inconn) );

414
   return TCS::StatusCode::SUCCESS;
415
416
417
418
}


TCS::StatusCode
419
TCS::TopoSteeringStructure::instantiateAlgorithms(bool debug) {
420
421
422
423
424
425
426
427
428
429
430
431
432
433

   for(TCS::Connector* conn: m_connectors) {

      if(conn->isInputConnector()) continue;

      // for each connector instantiate the algorithm and add to connector
      const std::string & alg = conn->algorithmName();
       
      // split into name and type
      std::string algType(alg, 0, alg.find('/'));
      std::string algName(alg, alg.find('/')+1);

      ConfigurableAlg * algInstance = TCS::AlgFactory::instance().algorithm(algName);
      if(algInstance==0) {
434
435
         if(debug)
            cout << "Instantiating " << alg << endl;
436
437
438
439
440
441
442
443
         algInstance = TCS::AlgFactory::create(algType, algName);
      } else {
         if(algInstance->className() != algType) {
            TCS_EXCEPTION("L1 TopoSteering: duplicate algorithm names:  algorithm " << algName << " has already been instantiated but with different type");
         }
      }
      conn->setAlgorithm(algInstance);
   }
444
   return TCS::StatusCode::SUCCESS;
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
}


TCS::Connector *
TCS::TopoSteeringStructure::connector(const std::string & connectorName) const {
   for( TCS::Connector* conn: m_connectors ) {
      if( conn->name() == connectorName )
         return conn;
   }
   TCS_EXCEPTION("L1Topo Steering: can not find connector of name " << connectorName << ". Need to abort!");
   return 0;
}


SortingConnector* 
TopoSteeringStructure::sortingConnector(const std::string & connectorName) const {
   SortingConnector * sc = nullptr;
   for( TCS::Connector* conn: m_connectors ) {
      if( conn->name() == connectorName ) {
         sc = dynamic_cast<SortingConnector*>(conn);
         if(sc==nullptr) {
            TCS_EXCEPTION("TopoSteeringStructure: connector of name " << connectorName << " exists, but is not a SortingConnector. Need to abort!");            
         }
      }
   }
470
   
471
472
473
474
475
   return sc;
}


TCS::DecisionConnector *
476
TCS::TopoSteeringStructure::outputConnector(const std::string & output) {
477
478
479
480
481
482
   auto c = m_outputLookup.find(output);
   if( c != m_outputLookup.end() )
      return c->second;
   TCS_EXCEPTION("L1Topo Steering: can not find output connector of that produces " << output << ". Need to abort!");
   return 0;
}
483

484

485
TCS::CountingConnector *
486
TCS::TopoSteeringStructure::countingConnector(const std::string & output) {
487
488
489
490
491
492
   auto c = m_countLookup.find(output);
   if( c != m_countLookup.end() )
      return c->second;
   TCS_EXCEPTION("L1Topo Steering: can not find counting connector of that produces " << output << ". Need to abort!");
   return 0;
}