Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-11-15 23:40:46

0001 #include <vector>
0002 #include <utility>
0003 #include <set>
0004 #include <cmath>
0005 #include <iostream>
0006 #include <fstream>
0007 #include <sstream>
0008 #include <cstdlib>
0009 #include <cassert>
0010 #include <mutex>
0011 
0012 #include "L1Trigger/TrackFindingTracklet/interface/TrackletConfigBuilder.h"
0013 #include "L1Trigger/TrackFindingTracklet/interface/Settings.h"
0014 #ifdef CMSSW_GIT_HASH
0015 #include "L1Trigger/TrackFindingTracklet/interface/Util.h"
0016 #include "L1Trigger/TrackTrigger/interface/Setup.h"
0017 #endif
0018 
0019 using namespace std;
0020 using namespace trklet;
0021 
0022 TrackletConfigBuilder::TrackletConfigBuilder(const Settings& settings, const tt::Setup* setup) : settings_(settings) {
0023   NSector_ = N_SECTOR;
0024   rcrit_ = settings.rcrit();
0025 
0026   duplicateMPs_ = settings.duplicateMPs();
0027   combinedmodules_ = settings.combined();
0028 
0029   extended_ = settings.extended();
0030 
0031   rinvmax_ = settings.rinvmax();
0032 
0033   rmaxdisk_ = settings.rmaxdisk();
0034   zlength_ = settings.zlength();
0035 
0036   for (int i = 0; i < N_LAYER; i++) {
0037     rmean_[i] = settings.rmean(i);
0038   }
0039 
0040   for (int i = 0; i < N_DISK; i++) {
0041     zmean_[i] = settings.zmean(i);
0042   }
0043 
0044   dphisectorHG_ = settings.dphisectorHG();
0045 
0046   for (int layerdisk = 0; layerdisk < N_LAYER + N_DISK; layerdisk++) {
0047     NRegions_[layerdisk] = settings.nallstubs(layerdisk);
0048     NVMME_[layerdisk] = settings.nvmme(layerdisk);
0049   }
0050 
0051   for (unsigned int iseed = 0; iseed < N_SEED_PROMPT; iseed++) {
0052     NVMTE_[iseed] = std::pair<unsigned int, unsigned int>(settings.nvmte(0, iseed), settings.nvmte(1, iseed));
0053     NTC_[iseed] = settings.NTC(iseed);
0054   }
0055 
0056   initGeom();
0057 
0058   buildTE();
0059 
0060   buildTC();
0061 
0062   buildProjections();
0063 
0064   setDTCphirange(setup);
0065 
0066   if (settings_.writeConfig()) {
0067     static std::once_flag runOnce;  // Only one thread should call this.
0068     std::call_once(runOnce, &TrackletConfigBuilder::writeDTCphirange, this);
0069   }
0070 }
0071 
0072 //--- Calculate phi range of modules read by each DTC.
0073 
0074 #ifdef CMSSW_GIT_HASH
0075 
0076 void TrackletConfigBuilder::setDTCphirange(const tt::Setup* setup) {
0077   list<DTCinfo> vecDTCinfo_unsorted;
0078 
0079   // Loop over DTCs in this tracker nonant.
0080   unsigned int numDTCsPerSector = setup->numDTCsPerRegion();
0081   for (unsigned int dtcId = 0; dtcId < numDTCsPerSector; dtcId++) {
0082     typedef std::pair<float, float> PhiRange;
0083     std::map<int, PhiRange> dtcPhiRange;
0084 
0085     // Loop over all tracker nonants, taking worst case not all identical.
0086     for (unsigned int iSector = 0; iSector < N_SECTOR; iSector++) {
0087       unsigned int dtcId_regI = iSector * numDTCsPerSector + dtcId;
0088       const std::vector<tt::SensorModule*>& dtcModules = setup->dtcModules(dtcId_regI);
0089       for (const tt::SensorModule* sm : dtcModules) {
0090         // Convert layer number to Hybrid convention.
0091         int layer = sm->layerId();  // Barrel = 1-6, Endcap = 11-15;
0092         if (sm->barrel()) {
0093           layer--;  // Barrel 0-5
0094         } else {
0095           const int endcapOffsetHybrid = 5;
0096           layer -= endcapOffsetHybrid;  // Layer 6-19
0097         }
0098         // Inner radius of module.
0099         float r = sm->r() - 0.5 * sm->numColumns() * sm->pitchCol() * fabs(sm->sinTilt());
0100         // phi with respect to tracker nonant centre.
0101         float phiMin = sm->phi() - 0.5 * sm->numRows() * sm->pitchRow() / r;
0102         float phiMax = sm->phi() + 0.5 * sm->numRows() * sm->pitchRow() / r;
0103         // Hybrid measures phi w.r.t. lower edge of tracker nonant.
0104         const float phiOffsetHybrid = 0.5 * dphisectorHG_;
0105         phiMin += phiOffsetHybrid;
0106         phiMax += phiOffsetHybrid;
0107         if (dtcPhiRange.find(layer) == dtcPhiRange.end()) {
0108           dtcPhiRange[layer] = {phiMin, phiMax};
0109         } else {
0110           dtcPhiRange.at(layer).first = std::min(phiMin, dtcPhiRange.at(layer).first);
0111           dtcPhiRange.at(layer).second = std::max(phiMax, dtcPhiRange.at(layer).second);
0112         }
0113       }
0114     }
0115     for (const auto& p : dtcPhiRange) {
0116       const unsigned int numSlots = setup->numATCASlots();
0117       std::string dtcName = settings_.slotToDTCname(dtcId % numSlots);
0118       if (dtcId >= numSlots)
0119         dtcName = "neg" + dtcName;
0120       DTCinfo info;
0121       info.name = dtcName;
0122       info.layer = p.first;
0123       info.phimin = p.second.first;
0124       info.phimax = p.second.second;
0125       vecDTCinfo_unsorted.push_back(info);
0126     }
0127   }
0128 
0129   // Put DTCinfo vector in traditional order (PS first). (Needed?)
0130   for (const DTCinfo& info : vecDTCinfo_unsorted) {
0131     string dtcname = info.name;
0132     if (dtcname.find("PS") != std::string::npos) {
0133       vecDTCinfo_.push_back(info);
0134     }
0135   }
0136   for (const DTCinfo& info : vecDTCinfo_unsorted) {
0137     string dtcname = info.name;
0138     if (dtcname.find("PS") == std::string::npos) {
0139       vecDTCinfo_.push_back(info);
0140     }
0141   }
0142 }
0143 
0144 //--- Write DTC phi ranges to file to support stand-alone emulation.
0145 //--- (Only needed to support stand-alone emulation)
0146 
0147 void TrackletConfigBuilder::writeDTCphirange() const {
0148   bool first = true;
0149   for (const DTCinfo& info : vecDTCinfo_) {
0150     string dirName = settings_.tablePath();
0151     string fileName = dirName + "../dtcphirange.dat";
0152     std::ofstream out;
0153     openfile(out, first, dirName, fileName, __FILE__, __LINE__);
0154     if (first) {
0155       out << "// layer & phi ranges of modules read by each DTC" << endl;
0156       out << "// (Used by stand-alone emulation)" << endl;
0157     }
0158     out << info.name << " " << info.layer << " " << info.phimin << " " << info.phimax << endl;
0159     out.close();
0160     first = false;
0161   }
0162 }
0163 
0164 #else
0165 
0166 //--- Set DTC phi ranges from .txt file (stand-alone operation only)
0167 
0168 void TrackletConfigBuilder::setDTCphirange(const tt::Setup* setup) {
0169   // This file previously written by writeDTCphirange().
0170   const string fname = "../data/dtcphirange.txt";
0171   if (vecDTCinfo_.empty()) {  // Only run once per thread.
0172     std::ifstream str_dtc;
0173     str_dtc.open(fname);
0174     assert(str_dtc.good());
0175     string line;
0176     while (ifstream, getline(line)) {
0177       std::istringstream iss(line);
0178       DTCinfo info;
0179       iss >> info.name >> info.layer >> info.phimin >> info.phimax;
0180       vecDTCinfo_.push_back(info);
0181     }
0182     str_dtc.close();
0183   }
0184 }
0185 
0186 #endif
0187 
0188 //--- Helper fcn. to get the layers/disks for a seed
0189 
0190 std::pair<unsigned int, unsigned int> TrackletConfigBuilder::seedLayers(unsigned int iSeed) {
0191   return std::pair<unsigned int, unsigned int>(settings_.seedlayers(0, iSeed), settings_.seedlayers(1, iSeed));
0192 }
0193 
0194 //--- Method to initialize the regions and VM in each layer
0195 
0196 void TrackletConfigBuilder::initGeom() {
0197   for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0198     double dphi = dphisectorHG_ / NRegions_[ilayer];
0199     for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
0200       std::vector<std::pair<unsigned int, unsigned int> > emptyVec;
0201       projections_[ilayer].push_back(emptyVec);
0202       // FIX: sector doesn't have hourglass shape
0203       double phimin = dphi * iReg;
0204       double phimax = phimin + dphi;
0205       std::pair<double, double> tmp(phimin, phimax);
0206       allStubs_[ilayer].push_back(tmp);
0207       double dphiVM = dphi / NVMME_[ilayer];
0208       for (unsigned int iVM = 0; iVM < NVMME_[ilayer]; iVM++) {
0209         double phivmmin = phimin + iVM * dphiVM;
0210         double phivmmax = phivmmin + dphiVM;
0211         std::pair<double, double> tmp(phivmmin, phivmmax);
0212         VMStubsME_[ilayer].push_back(tmp);
0213       }
0214     }
0215   }
0216   for (unsigned int iseed = 0; iseed < N_SEED_PROMPT; iseed++) {
0217     unsigned int l1 = seedLayers(iseed).first;
0218     unsigned int l2 = seedLayers(iseed).second;
0219     unsigned int nVM1 = NVMTE_[iseed].first;
0220     unsigned int nVM2 = NVMTE_[iseed].second;
0221     double dphiVM = dphisectorHG_ / (nVM1 * NRegions_[l1]);
0222     for (unsigned int iVM = 0; iVM < nVM1 * NRegions_[l1]; iVM++) {
0223       double phivmmin = iVM * dphiVM;
0224       double phivmmax = phivmmin + dphiVM;
0225       std::pair<double, double> tmp(phivmmin, phivmmax);
0226       VMStubsTE_[iseed].first.push_back(tmp);
0227     }
0228     dphiVM = dphisectorHG_ / (nVM2 * NRegions_[l2]);
0229     for (unsigned int iVM = 0; iVM < nVM2 * NRegions_[l2]; iVM++) {
0230       double phivmmin = iVM * dphiVM;
0231       double phivmmax = phivmmin + dphiVM;
0232       std::pair<double, double> tmp(phivmmin, phivmmax);
0233       VMStubsTE_[iseed].second.push_back(tmp);
0234     }
0235   }
0236 }
0237 
0238 //--- Helper fcn to get the radii of the two layers in a seed
0239 
0240 std::pair<double, double> TrackletConfigBuilder::seedRadii(unsigned int iseed) {
0241   std::pair<unsigned int, unsigned int> seedlayers = seedLayers(iseed);
0242 
0243   unsigned int l1 = seedlayers.first;
0244   unsigned int l2 = seedlayers.second;
0245 
0246   double r1, r2;
0247 
0248   if (iseed < 4) {  //barrel seeding
0249     r1 = rmean_[l1];
0250     r2 = rmean_[l2];
0251   } else if (iseed < 6) {   //disk seeding
0252     r1 = rmean_[0] + 40.0;  //FIX: Somewhat of a hack - but allows finding all the regions
0253     //when projecting to L1
0254     r2 = r1 * zmean_[l2 - 6] / zmean_[l1 - 6];
0255   } else {  //overlap seeding
0256     r1 = rmean_[l1];
0257     r2 = r1 * zmean_[l2 - 6] / zlength_;
0258   }
0259 
0260   return std::pair<double, double>(r1, r2);
0261 }
0262 
0263 //--- Helper function to determine if a pair of VM memories form valid TE
0264 
0265 bool TrackletConfigBuilder::validTEPair(unsigned int iseed, unsigned int iTE1, unsigned int iTE2) {
0266   double rinvmin = 999.9;
0267   double rinvmax = -999.9;
0268 
0269   double phi1[2] = {VMStubsTE_[iseed].first[iTE1].first, VMStubsTE_[iseed].first[iTE1].second};
0270   double phi2[2] = {VMStubsTE_[iseed].second[iTE2].first, VMStubsTE_[iseed].second[iTE2].second};
0271 
0272   std::pair<double, double> seedradii = seedRadii(iseed);
0273 
0274   for (unsigned int i1 = 0; i1 < 2; i1++) {
0275     for (unsigned int i2 = 0; i2 < 2; i2++) {
0276       double arinv = rinv(seedradii.first, phi1[i1], seedradii.second, phi2[i2]);
0277       if (arinv < rinvmin)
0278         rinvmin = arinv;
0279       if (arinv > rinvmax)
0280         rinvmax = arinv;
0281     }
0282   }
0283 
0284   if (rinvmin > rinvmax_)
0285     return false;
0286   if (rinvmax < -rinvmax_)
0287     return false;
0288 
0289   return true;
0290 }
0291 
0292 //--- Builds the list of TE for each seeding combination
0293 
0294 void TrackletConfigBuilder::buildTE() {
0295   for (unsigned int iseed = 0; iseed < N_SEED_PROMPT; iseed++) {
0296     for (unsigned int i1 = 0; i1 < VMStubsTE_[iseed].first.size(); i1++) {
0297       for (unsigned int i2 = 0; i2 < VMStubsTE_[iseed].second.size(); i2++) {
0298         if (validTEPair(iseed, i1, i2)) {
0299           std::pair<unsigned int, unsigned int> tmp(i1, i2);
0300           // Contains pairs of indices of all valid VM pairs in seeding layers
0301           TE_[iseed].push_back(tmp);
0302         }
0303       }
0304     }
0305   }
0306 }
0307 
0308 //--- Builds the lists of TC for each seeding combination
0309 
0310 void TrackletConfigBuilder::buildTC() {
0311   for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
0312     unsigned int nTC = NTC_[iSeed];
0313     std::vector<std::pair<unsigned int, unsigned int> >& TEs = TE_[iSeed];
0314     std::vector<std::vector<unsigned int> >& TCs = TC_[iSeed];
0315 
0316     //Very naive method to group TEs in TC
0317 
0318     double invnTC = nTC * (1.0 / TEs.size());
0319 
0320     for (unsigned int iTE = 0; iTE < TEs.size(); iTE++) {
0321       int iTC = invnTC * iTE;
0322       assert(iTC < (int)nTC);
0323       if (iTC >= (int)TCs.size()) {
0324         std::vector<unsigned int> tmp;
0325         tmp.push_back(iTE);
0326         TCs.push_back(tmp);
0327       } else {
0328         TCs[iTC].push_back(iTE);
0329       }
0330     }
0331   }
0332 }
0333 
0334 //--- Helper fcn to return the phi range of a projection of a tracklet from a TC
0335 
0336 std::pair<double, double> TrackletConfigBuilder::seedPhiRange(double rproj, unsigned int iSeed, unsigned int iTC) {
0337   std::vector<std::vector<unsigned int> >& TCs = TC_[iSeed];
0338 
0339   std::pair<double, double> seedradii = seedRadii(iSeed);
0340 
0341   double phimin = 999.0;
0342   double phimax = -999.0;
0343   for (unsigned int iTE = 0; iTE < TCs[iTC].size(); iTE++) {
0344     unsigned int theTE = TCs[iTC][iTE];
0345     unsigned int l1TE = TE_[iSeed][theTE].first;
0346     unsigned int l2TE = TE_[iSeed][theTE].second;
0347     double phi1[2] = {VMStubsTE_[iSeed].first[l1TE].first, VMStubsTE_[iSeed].first[l1TE].second};
0348     double phi2[2] = {VMStubsTE_[iSeed].second[l2TE].first, VMStubsTE_[iSeed].second[l2TE].second};
0349     for (unsigned int i1 = 0; i1 < 2; i1++) {
0350       for (unsigned int i2 = 0; i2 < 2; i2++) {
0351         double aphi = phi(seedradii.first, phi1[i1], seedradii.second, phi2[i2], rproj);
0352         if (aphi < phimin)
0353           phimin = aphi;
0354         if (aphi > phimax)
0355           phimax = aphi;
0356       }
0357     }
0358   }
0359   return std::pair<double, double>(phimin, phimax);
0360 }
0361 
0362 //--- Finds the projections needed for each seeding combination
0363 
0364 void TrackletConfigBuilder::buildProjections() {
0365   set<string> emptyProjStandard = {
0366       "TPROJ_L1L2H_L3PHIB", "TPROJ_L1L2E_L3PHIC", "TPROJ_L1L2K_L3PHIC", "TPROJ_L1L2H_L3PHID", "TPROJ_L1L2F_L5PHIA",
0367       "TPROJ_L1L2G_L5PHID", "TPROJ_L1L2A_L6PHIA", "TPROJ_L1L2J_L6PHIB", "TPROJ_L1L2C_L6PHIC", "TPROJ_L1L2L_L6PHID",
0368       "TPROJ_L3L4D_D1PHIB", "TPROJ_L2L3A_D1PHIC", "TPROJ_L3L4A_D1PHIC", "TPROJ_L1L2G_D2PHIA", "TPROJ_L1D1D_D2PHIA",
0369       "TPROJ_L1D1E_D2PHIA", "TPROJ_L1L2J_D2PHIB", "TPROJ_L3L4D_D2PHIB", "TPROJ_L1D1A_D2PHIB", "TPROJ_L1D1F_D2PHIB",
0370       "TPROJ_L1D1G_D2PHIB", "TPROJ_L1L2C_D2PHIC", "TPROJ_L2L3A_D2PHIC", "TPROJ_L3L4A_D2PHIC", "TPROJ_L1D1B_D2PHIC",
0371       "TPROJ_L1D1C_D2PHIC", "TPROJ_L1D1H_D2PHIC", "TPROJ_L2D1A_D2PHIC", "TPROJ_L1L2F_D2PHID", "TPROJ_L1D1D_D2PHID",
0372       "TPROJ_L1D1E_D2PHID", "TPROJ_L1L2G_D3PHIA", "TPROJ_L1D1D_D3PHIA", "TPROJ_L1D1E_D3PHIA", "TPROJ_L1L2J_D3PHIB",
0373       "TPROJ_L1D1A_D3PHIB", "TPROJ_L1D1F_D3PHIB", "TPROJ_L1D1G_D3PHIB", "TPROJ_L1L2C_D3PHIC", "TPROJ_L2L3A_D3PHIC",
0374       "TPROJ_L1D1B_D3PHIC", "TPROJ_L1D1C_D3PHIC", "TPROJ_L1D1H_D3PHIC", "TPROJ_L2D1A_D3PHIC", "TPROJ_L1L2F_D3PHID",
0375       "TPROJ_L1D1D_D3PHID", "TPROJ_L1D1E_D3PHID", "TPROJ_L1L2G_D4PHIA", "TPROJ_L1D1D_D4PHIA", "TPROJ_L1D1E_D4PHIA",
0376       "TPROJ_L1L2J_D4PHIB", "TPROJ_L1D1G_D4PHIB", "TPROJ_L1L2C_D4PHIC", "TPROJ_L2L3A_D4PHIC", "TPROJ_L1D1B_D4PHIC",
0377       "TPROJ_L2D1A_D4PHIC", "TPROJ_L1L2F_D4PHID", "TPROJ_L1D1D_D4PHID", "TPROJ_L1D1E_D5PHIA", "TPROJ_L1D1G_D5PHIB",
0378       "TPROJ_L1D1B_D5PHIC", "TPROJ_L1D1D_D5PHID"};
0379 
0380   set<string> emptyProjCombined = {
0381       "TPROJ_L1L2J_L6PHIB", "TPROJ_L1L2C_L6PHIC", "TPROJ_L1L2G_D1PHIA", "TPROJ_L1L2J_D1PHIB", "TPROJ_L2L3D_D1PHIB",
0382       "TPROJ_L3L4D_D1PHIB", "TPROJ_L1L2C_D1PHIC", "TPROJ_L2L3A_D1PHIC", "TPROJ_L3L4A_D1PHIC", "TPROJ_L1L2F_D1PHID",
0383       "TPROJ_L1L2G_D2PHIA", "TPROJ_L1D1E_D2PHIA", "TPROJ_L1L2J_D2PHIB", "TPROJ_L2L3D_D2PHIB", "TPROJ_L3L4D_D2PHIB",
0384       "TPROJ_L1D1G_D2PHIB", "TPROJ_L1L2C_D2PHIC", "TPROJ_L2L3A_D2PHIC", "TPROJ_L3L4A_D2PHIC", "TPROJ_L1D1B_D2PHIC",
0385       "TPROJ_L2D1A_D2PHIC", "TPROJ_L1L2F_D2PHID", "TPROJ_L1D1D_D2PHID", "TPROJ_L1L2G_D3PHIA", "TPROJ_L1D1E_D3PHIA",
0386       "TPROJ_L1L2J_D3PHIB", "TPROJ_L2L3D_D3PHIB", "TPROJ_L1D1G_D3PHIB", "TPROJ_L1L2C_D3PHIC", "TPROJ_L2L3A_D3PHIC",
0387       "TPROJ_L1D1B_D3PHIC", "TPROJ_L2D1A_D3PHIC", "TPROJ_L1L2F_D3PHID", "TPROJ_L1D1D_D3PHID", "TPROJ_L1L2G_D4PHIA",
0388       "TPROJ_L1D1E_D4PHIA", "TPROJ_L1L2J_D4PHIB", "TPROJ_L2L3D_D4PHIB", "TPROJ_L1D1G_D4PHIB", "TPROJ_L1L2C_D4PHIC",
0389       "TPROJ_L2L3A_D4PHIC", "TPROJ_L1D1B_D4PHIC", "TPROJ_L2D1A_D4PHIC", "TPROJ_L1L2F_D4PHID", "TPROJ_L1D1D_D4PHID",
0390       "TPROJ_L1D1E_D5PHIA", "TPROJ_L1D1G_D5PHIB", "TPROJ_L1D1B_D5PHIC", "TPROJ_L1D1D_D5PHID"};
0391 
0392   for (unsigned int iseed = 0; iseed < N_SEED_PROMPT; iseed++) {
0393     std::vector<std::vector<unsigned int> >& TCs = TC_[iseed];
0394 
0395     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0396       if (matchport_[iseed][ilayer] == -1)
0397         continue;
0398       for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
0399         for (unsigned int iTC = 0; iTC < TCs.size(); iTC++) {
0400           double rproj = rmaxdisk_;
0401           if (ilayer < 6)
0402             rproj = rmean_[ilayer];
0403           std::pair<double, double> phiRange = seedPhiRange(rproj, iseed, iTC);
0404           if (phiRange.first < allStubs_[ilayer][iReg].second && phiRange.second > allStubs_[ilayer][iReg].first) {
0405             std::pair<unsigned int, unsigned int> tmp(iseed, iTC);  //seedindex and TC
0406             string projName = TPROJName(iseed, iTC, ilayer, iReg);
0407             if (combinedmodules_) {
0408               if (emptyProjCombined.find(projName) == emptyProjCombined.end()) {
0409                 projections_[ilayer][iReg].push_back(tmp);
0410               }
0411             } else {
0412               if (emptyProjStandard.find(projName) == emptyProjStandard.end()) {
0413                 projections_[ilayer][iReg].push_back(tmp);
0414               }
0415             }
0416           }
0417         }
0418       }
0419     }
0420   }
0421 }
0422 
0423 //--- Helper function to calculate the phi position of a seed at radius r that is formed
0424 //--- by two stubs at (r1,phi1) and (r2, phi2)
0425 
0426 double TrackletConfigBuilder::phi(double r1, double phi1, double r2, double phi2, double r) {
0427   double rhoinv = rinv(r1, phi1, r2, phi2);
0428   if (std::abs(rhoinv) > rinvmax_) {
0429     rhoinv = rinvmax_ * rhoinv / std::abs(rhoinv);
0430   }
0431   return phi1 + asin(0.5 * r * rhoinv) - asin(0.5 * r1 * rhoinv);
0432 }
0433 
0434 //--- Helper function to calculate rinv for two stubs at (r1,phi1) and (r2,phi2)
0435 
0436 double TrackletConfigBuilder::rinv(double r1, double phi1, double r2, double phi2) {
0437   double deltaphi = phi1 - phi2;
0438   return 2 * sin(deltaphi) / sqrt(r2 * r2 + r1 * r1 - 2 * r1 * r2 * cos(deltaphi));
0439 }
0440 
0441 std::string TrackletConfigBuilder::iSeedStr(unsigned int iSeed) const {
0442   static std::string name[8] = {"L1L2", "L2L3", "L3L4", "L5L6", "D1D2", "D3D4", "L1D1", "L2D1"};
0443 
0444   assert(iSeed < 8);
0445   return name[iSeed];
0446 }
0447 
0448 std::string TrackletConfigBuilder::numStr(unsigned int i) {
0449   static std::string num[32] = {"1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9",  "10", "11",
0450                                 "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22",
0451                                 "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"};
0452   assert(i < 32);
0453   return num[i];
0454 }
0455 
0456 std::string TrackletConfigBuilder::iTCStr(unsigned int iTC) const {
0457   static std::string name[12] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"};
0458 
0459   assert(iTC < 12);
0460   return name[iTC];
0461 }
0462 
0463 std::string TrackletConfigBuilder::iRegStr(unsigned int iReg, unsigned int iSeed) const {
0464   static std::string name[8] = {"A", "B", "C", "D", "E", "F", "G", "H"};
0465 
0466   static std::string nameOverlap[8] = {"X", "Y", "Z", "W", "Q", "R", "S", "T"};
0467 
0468   static std::string nameL2L3[4] = {"I", "J", "K", "L"};
0469 
0470   if (iSeed == Seed::L2L3) {
0471     assert(iReg < 4);
0472     return nameL2L3[iReg];
0473   }
0474   if (iSeed == Seed::L1D1 || iSeed == Seed::L2D1) {
0475     assert(iReg < 8);
0476     return nameOverlap[iReg];
0477   }
0478   assert(iReg < 8);
0479   return name[iReg];
0480 }
0481 
0482 std::string TrackletConfigBuilder::TCName(unsigned int iSeed, unsigned int iTC) const {
0483   if (combinedmodules_) {
0484     return "TP_" + iSeedStr(iSeed) + iTCStr(iTC);
0485   } else {
0486     return "TC_" + iSeedStr(iSeed) + iTCStr(iTC);
0487   }
0488 }
0489 
0490 std::string TrackletConfigBuilder::LayerName(unsigned int ilayer) {
0491   return ilayer < 6 ? ("L" + numStr(ilayer)) : ("D" + numStr(ilayer - 6));
0492 }
0493 
0494 std::string TrackletConfigBuilder::TPROJName(unsigned int iSeed,
0495                                              unsigned int iTC,
0496                                              unsigned int ilayer,
0497                                              unsigned int ireg) const {
0498   return "TPROJ_" + iSeedStr(iSeed) + iTCStr(iTC) + "_" + LayerName(ilayer) + "PHI" + iTCStr(ireg);
0499 }
0500 
0501 std::string TrackletConfigBuilder::PRName(unsigned int ilayer, unsigned int ireg) const {
0502   if (combinedmodules_) {
0503     return "MP_" + LayerName(ilayer) + "PHI" + iTCStr(ireg);
0504   } else {
0505     return "PR_" + LayerName(ilayer) + "PHI" + iTCStr(ireg);
0506   }
0507 }
0508 
0509 void TrackletConfigBuilder::writeProjectionMemories(std::ostream& os, std::ostream& memories, std::ostream&) {
0510   // Each TC (e.g. TC_L1L2D) writes a projection memory (TPROJ) for each layer the seed projects to,
0511   // with name indicating the TC and which layer & phi region it projects to (e.g. TPROJ_L1L2D_L3PHIA).
0512   //
0513   // Each PR (e.g. PR_L3PHIA) reads all TPROJ memories for the given layer & phi region.
0514 
0515   for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0516     for (unsigned int ireg = 0; ireg < projections_[ilayer].size(); ireg++) {
0517       for (unsigned int imem = 0; imem < projections_[ilayer][ireg].size(); imem++) {
0518         unsigned int iSeed = projections_[ilayer][ireg][imem].first;
0519         unsigned int iTC = projections_[ilayer][ireg][imem].second;
0520         if (combinedmodules_) {
0521           if (duplicateMPs_) {
0522             if ((settings_.layersDisksDuplicatedEqualProjBalance()[ilayer]) && (ireg == 1 || ireg == 2)) {
0523               memories << "TrackletProjections: " + TPROJName(iSeed, iTC, ilayer, ireg) + " [54]" << std::endl;
0524               if (imem < projections_[ilayer][ireg].size() / 2) {
0525                 os << TPROJName(iSeed, iTC, ilayer, ireg) << " input=> " << TCName(iSeed, iTC) << ".projout"
0526                    << LayerName(ilayer) << "PHI" << iTCStr(ireg) << " output=> " << PRName(ilayer, ireg) << ".projin"
0527                    << std::endl;
0528               } else {
0529                 os << TPROJName(iSeed, iTC, ilayer, ireg) << " input=> " << TCName(iSeed, iTC) << ".projout"
0530                    << LayerName(ilayer) << "PHI" << iTCStr(ireg) << " output=> " << PRName(ilayer, ireg) + "_E"
0531                    << ".projin"  // duplicate MPs denoted by extra _E
0532                    << std::endl;
0533               }
0534             } else if ((settings_.layersDisksDuplicatedWeightedProjBalance()[ilayer]) && (ireg == 1 || ireg == 2)) {
0535               memories << "TrackletProjections: " + TPROJName(iSeed, iTC, ilayer, ireg) + " [54]" << std::endl;
0536               if (imem < 4 ||
0537                   imem >
0538                       9) {  // FIXME need to replace magic numbers, corresponds to allowing MP1 4 L1L2 TCs, 3 L5L6 TCs, MP2 3 L1L2 3 L3L4 TCs
0539                 os << TPROJName(iSeed, iTC, ilayer, ireg) << " input=> " << TCName(iSeed, iTC) << ".projout"
0540                    << LayerName(ilayer) << "PHI" << iTCStr(ireg) << " output=> " << PRName(ilayer, ireg) << ".projin"
0541                    << std::endl;
0542               } else {
0543                 os << TPROJName(iSeed, iTC, ilayer, ireg) << " input=> " << TCName(iSeed, iTC) << ".projout"
0544                    << LayerName(ilayer) << "PHI" << iTCStr(ireg) << " output=> " << PRName(ilayer, ireg) + "_E"
0545                    << ".projin"  // duplicate MPs
0546                    << std::endl;
0547               }
0548             } else {
0549               memories << "TrackletProjections: " + TPROJName(iSeed, iTC, ilayer, ireg) + " [54]" << std::endl;
0550               os << TPROJName(iSeed, iTC, ilayer, ireg) << " input=> " << TCName(iSeed, iTC) << ".projout"
0551                  << LayerName(ilayer) << "PHI" << iTCStr(ireg) << " output=> " << PRName(ilayer, ireg) << ".projin"
0552                  << std::endl;
0553             }
0554           } else {  // non-duplicate MPs configuration
0555             memories << "TrackletProjections: " + TPROJName(iSeed, iTC, ilayer, ireg) + " [54]" << std::endl;
0556             os << TPROJName(iSeed, iTC, ilayer, ireg) << " input=> " << TCName(iSeed, iTC) << ".projout"
0557                << LayerName(ilayer) << "PHI" << iTCStr(ireg) << " output=> " << PRName(ilayer, ireg) << ".projin"
0558                << std::endl;
0559           }
0560         } else {  // non-combined modules
0561           memories << "TrackletProjections: " + TPROJName(iSeed, iTC, ilayer, ireg) + " [54]" << std::endl;
0562           os << TPROJName(iSeed, iTC, ilayer, ireg) << " input=> " << TCName(iSeed, iTC) << ".projout"
0563              << LayerName(ilayer) << "PHI" << iTCStr(ireg) << " output=> " << PRName(ilayer, ireg) << ".projin"
0564              << std::endl;
0565         }
0566       }
0567     }
0568   }
0569 }
0570 
0571 std::string TrackletConfigBuilder::SPName(unsigned int l1,
0572                                           unsigned int ireg1,
0573                                           unsigned int ivm1,
0574                                           unsigned int l2,
0575                                           unsigned int ireg2,
0576                                           unsigned int ivm2,
0577                                           unsigned int iseed) const {
0578   return "SP_" + LayerName(l1) + "PHI" + iRegStr(ireg1, iseed) + numStr(ivm1) + "_" + LayerName(l2) + "PHI" +
0579          iRegStr(ireg2, iseed) + numStr(ivm2);
0580 }
0581 
0582 std::string TrackletConfigBuilder::SPDName(unsigned int l1,
0583                                            unsigned int ireg1,
0584                                            unsigned int ivm1,
0585                                            unsigned int l2,
0586                                            unsigned int ireg2,
0587                                            unsigned int ivm2,
0588                                            unsigned int l3,
0589                                            unsigned int ireg3,
0590                                            unsigned int ivm3,
0591                                            unsigned int iseed) const {
0592   return "SPD_" + LayerName(l1) + "PHI" + iRegStr(ireg1, iseed) + numStr(ivm1) + "_" + LayerName(l2) + "PHI" +
0593          iRegStr(ireg2, iseed) + numStr(ivm2) + "_" + LayerName(l3) + "PHI" + iRegStr(ireg3, iseed) + numStr(ivm3);
0594 }
0595 
0596 std::string TrackletConfigBuilder::TEName(unsigned int l1,
0597                                           unsigned int ireg1,
0598                                           unsigned int ivm1,
0599                                           unsigned int l2,
0600                                           unsigned int ireg2,
0601                                           unsigned int ivm2,
0602                                           unsigned int iseed) const {
0603   return "TE_" + LayerName(l1) + "PHI" + iRegStr(ireg1, iseed) + numStr(ivm1) + "_" + LayerName(l2) + "PHI" +
0604          iRegStr(ireg2, iseed) + numStr(ivm2);
0605 }
0606 
0607 std::string TrackletConfigBuilder::TEDName(unsigned int l1,
0608                                            unsigned int ireg1,
0609                                            unsigned int ivm1,
0610                                            unsigned int l2,
0611                                            unsigned int ireg2,
0612                                            unsigned int ivm2,
0613                                            unsigned int iseed) const {
0614   return "TED_" + LayerName(l1) + "PHI" + iRegStr(ireg1, iseed) + numStr(ivm1) + "_" + LayerName(l2) + "PHI" +
0615          iRegStr(ireg2, iseed) + numStr(ivm2);
0616 }
0617 
0618 std::string TrackletConfigBuilder::TParName(unsigned int l1, unsigned int l2, unsigned int l3, unsigned int itc) const {
0619   return "TPAR_" + LayerName(l1) + LayerName(l2) + LayerName(l3) + iTCStr(itc);
0620 }
0621 
0622 std::string TrackletConfigBuilder::TCDName(unsigned int l1, unsigned int l2, unsigned int l3, unsigned int itc) const {
0623   return "TCD_" + LayerName(l1) + LayerName(l2) + LayerName(l3) + iTCStr(itc);
0624 }
0625 
0626 std::string TrackletConfigBuilder::TPROJName(unsigned int l1,
0627                                              unsigned int l2,
0628                                              unsigned int l3,
0629                                              unsigned int itc,
0630                                              unsigned int projlayer,
0631                                              unsigned int projreg) const {
0632   return "TPROJ_" + LayerName(l1) + LayerName(l2) + LayerName(l3) + iTCStr(itc) + "_" + LayerName(projlayer) + "PHI" +
0633          iTCStr(projreg);
0634 }
0635 
0636 std::string TrackletConfigBuilder::FTName(unsigned int l1, unsigned int l2, unsigned int l3) const {
0637   return "FT_" + LayerName(l1) + LayerName(l2) + LayerName(l3);
0638 }
0639 
0640 std::string TrackletConfigBuilder::TREName(unsigned int l1,
0641                                            unsigned int ireg1,
0642                                            unsigned int l2,
0643                                            unsigned int ireg2,
0644                                            unsigned int iseed,
0645                                            unsigned int count) const {
0646   return "TRE_" + LayerName(l1) + iRegStr(ireg1, iseed) + LayerName(l2) + iRegStr(ireg2, iseed) + "_" + numStr(count);
0647 }
0648 
0649 std::string TrackletConfigBuilder::STName(unsigned int l1,
0650                                           unsigned int ireg1,
0651                                           unsigned int l2,
0652                                           unsigned int ireg2,
0653                                           unsigned int l3,
0654                                           unsigned int ireg3,
0655                                           unsigned int iseed,
0656                                           unsigned int count) const {
0657   return "ST_" + LayerName(l1) + iRegStr(ireg1, iseed) + LayerName(l2) + iRegStr(ireg2, iseed) + "_" + LayerName(l3) +
0658          iRegStr(ireg3, iseed) + "_" + numStr(count);
0659 }
0660 
0661 void TrackletConfigBuilder::writeSPMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
0662   // Each TE reads one VM in two seed layers, finds stub pairs & writes to a StubPair ("SP") memory.
0663   //
0664   // Each TC reads several StubPair (SP) memories, each containing a pair of VMs of two seeding layers.
0665   // Several TC are created for each layer pair, and the SP distributed between them.
0666   // If TC name is TC_L1L2C, "C" indicates this is the 3rd TC in L1L2.
0667 
0668   if (combinedmodules_)
0669     return;
0670 
0671   for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
0672     for (unsigned int iTC = 0; iTC < TC_[iSeed].size(); iTC++) {
0673       for (unsigned int iTE = 0; iTE < TC_[iSeed][iTC].size(); iTE++) {
0674         unsigned int theTE = TC_[iSeed][iTC][iTE];
0675 
0676         unsigned int TE1 = TE_[iSeed][theTE].first;
0677         unsigned int TE2 = TE_[iSeed][theTE].second;
0678 
0679         unsigned int l1 = seedLayers(iSeed).first;
0680         unsigned int l2 = seedLayers(iSeed).second;
0681 
0682         memories << "StubPairs: "
0683                  << SPName(l1, TE1 / NVMTE_[iSeed].first, TE1, l2, TE2 / NVMTE_[iSeed].second, TE2, iSeed) << " [12]"
0684                  << std::endl;
0685         modules << "TrackletEngine: "
0686                 << TEName(l1, TE1 / NVMTE_[iSeed].first, TE1, l2, TE2 / NVMTE_[iSeed].second, TE2, iSeed) << std::endl;
0687 
0688         os << SPName(l1, TE1 / NVMTE_[iSeed].first, TE1, l2, TE2 / NVMTE_[iSeed].second, TE2, iSeed) << " input=> "
0689            << TEName(l1, TE1 / NVMTE_[iSeed].first, TE1, l2, TE2 / NVMTE_[iSeed].second, TE2, iSeed)
0690            << ".stubpairout output=> " << TCName(iSeed, iTC) << ".stubpairin" << std::endl;
0691       }
0692     }
0693   }
0694 }
0695 
0696 void TrackletConfigBuilder::writeSPDMemories(std::ostream& wires, std::ostream& memories, std::ostream& modules) {
0697   // Similar to writeSPMemories, but for displaced (=extended) tracking,
0698   // with seeds based on triplets of layers.
0699 
0700   if (!extended_)
0701     return;
0702 
0703   vector<string> stubTriplets[N_SEED];
0704 
0705   for (unsigned int iSeed = N_SEED_PROMPT; iSeed < N_SEED; iSeed++) {
0706     int layerdisk1 = settings_.seedlayers(0, iSeed);
0707     int layerdisk2 = settings_.seedlayers(1, iSeed);
0708     int layerdisk3 = settings_.seedlayers(2, iSeed);
0709 
0710     unsigned int nallstub1 = settings_.nallstubs(layerdisk1);
0711     unsigned int nallstub2 = settings_.nallstubs(layerdisk2);
0712     unsigned int nallstub3 = settings_.nallstubs(layerdisk3);
0713 
0714     unsigned int nvm1 = settings_.nvmte(0, iSeed);
0715     unsigned int nvm2 = settings_.nvmte(1, iSeed);
0716     unsigned int nvm3 = settings_.nvmte(2, iSeed);
0717 
0718     int count = 0;
0719     for (unsigned int ireg1 = 0; ireg1 < nallstub1; ireg1++) {
0720       for (unsigned int ireg2 = 0; ireg2 < nallstub2; ireg2++) {
0721         for (unsigned int ireg3 = 0; ireg3 < nallstub3; ireg3++) {
0722           count++;
0723           memories << "StubTriplets: " << STName(layerdisk1, ireg1, layerdisk2, ireg2, layerdisk3, ireg3, iSeed, count)
0724                    << " [18]" << std::endl;
0725           stubTriplets[iSeed].push_back(STName(layerdisk1, ireg1, layerdisk2, ireg2, layerdisk3, ireg3, iSeed, count));
0726         }
0727       }
0728     }
0729 
0730     for (unsigned int ireg1 = 0; ireg1 < nallstub1; ireg1++) {
0731       for (unsigned int ivm1 = 0; ivm1 < nvm1; ivm1++) {
0732         for (unsigned int ireg2 = 0; ireg2 < nallstub2; ireg2++) {
0733           for (unsigned int ivm2 = 0; ivm2 < nvm2; ivm2++) {
0734             int count = 0;
0735 
0736             modules << "TrackletEngineDisplaced: "
0737                     << TEDName(layerdisk1, ireg1, ireg1 * nvm1 + ivm1, layerdisk2, ireg2, ireg2 * nvm2 + ivm2, iSeed)
0738                     << std::endl;
0739 
0740             for (unsigned int ireg3 = 0; ireg3 < nallstub3; ireg3++) {
0741               for (unsigned int ivm3 = 0; ivm3 < nvm3; ivm3++) {
0742                 count++;
0743 
0744                 memories << "StubPairsDisplaced: "
0745                          << SPDName(layerdisk1,
0746                                     ireg1,
0747                                     ireg1 * nvm1 + ivm1,
0748                                     layerdisk2,
0749                                     ireg2,
0750                                     ireg2 * nvm2 + ivm2,
0751                                     layerdisk3,
0752                                     ireg3,
0753                                     ireg3 * nvm3 + ivm3,
0754                                     iSeed)
0755                          << " [12]" << std::endl;
0756 
0757                 modules << "TripletEngine: " << TREName(layerdisk1, ireg1, layerdisk2, ireg2, iSeed, count)
0758                         << std::endl;
0759 
0760                 wires << SPDName(layerdisk1,
0761                                  ireg1,
0762                                  ireg1 * nvm1 + ivm1,
0763                                  layerdisk2,
0764                                  ireg2,
0765                                  ireg2 * nvm2 + ivm2,
0766                                  layerdisk3,
0767                                  ireg3,
0768                                  ireg3 * nvm3 + ivm3,
0769                                  iSeed)
0770                       << " input=> "
0771                       << TEDName(layerdisk1, ireg1, ireg1 * nvm1 + ivm1, layerdisk2, ireg2, ireg2 * nvm2 + ivm2, iSeed)
0772                       << ".stubpairout output=> " << TREName(layerdisk1, ireg1, layerdisk2, ireg2, iSeed, count)
0773                       << ".stubpair"
0774                       << "1"
0775                       << "in" << std::endl;
0776               }
0777             }
0778           }
0779         }
0780       }
0781     }
0782 
0783     unsigned int nTC = 10;
0784     for (unsigned int itc = 0; itc < nTC; itc++) {
0785       for (int iproj = 0; iproj < 4; iproj++) {
0786         int ilay = settings_.projlayers(iSeed, iproj);
0787         if (ilay > 0) {
0788           unsigned int nallstub = settings_.nallstubs(ilay - 1);
0789           for (unsigned int ireg = 0; ireg < nallstub; ireg++) {
0790             memories << "TrackletProjections: " << TPROJName(layerdisk1, layerdisk2, layerdisk3, itc, ilay - 1, ireg)
0791                      << " [54]" << std::endl;
0792           }
0793         }
0794 
0795         int idisk = settings_.projdisks(iSeed, iproj);
0796         if (idisk > 0) {
0797           unsigned int nallstub = settings_.nallstubs(idisk + 5);
0798           for (unsigned int ireg = 0; ireg < nallstub; ireg++) {
0799             memories << "TrackletProjections: " << TPROJName(layerdisk1, layerdisk2, layerdisk3, itc, idisk + 5, ireg)
0800                      << " [54]" << std::endl;
0801 
0802             wires << TPROJName(layerdisk1, layerdisk2, layerdisk3, itc, idisk + 5, ireg) << " input=> "
0803                   << TCDName(layerdisk1, layerdisk2, layerdisk3, itc) << ".projout" << LayerName(idisk + 1) << "PHI"
0804                   << iTCStr(ireg) << " output=> "
0805                   << "PR_" << LayerName(idisk + 1) << "PHI" << iTCStr(ireg) << ".projin" << std::endl;
0806           }
0807         }
0808       }
0809 
0810       memories << "TrackletParameters: " << TParName(layerdisk1, layerdisk2, layerdisk3, itc) << " [56]" << std::endl;
0811 
0812       modules << "TrackletCalculatorDisplaced: " << TCDName(layerdisk1, layerdisk2, layerdisk3, itc) << std::endl;
0813     }
0814 
0815     unsigned int nST = stubTriplets[iSeed].size();
0816     for (unsigned int iST = 0; iST < nST; iST++) {
0817       unsigned int iTC = (iST * nTC) / nST;
0818       assert(iTC < nTC);
0819       string stname = stubTriplets[iSeed][iST];
0820       string trename = "TRE_" + stname.substr(3, 6) + "_";
0821       unsigned int stlen = stname.size();
0822       if (stname[stlen - 2] == '_')
0823         trename += stname.substr(stlen - 1, 1);
0824       if (stname[stlen - 3] == '_')
0825         trename += stname.substr(stlen - 2, 2);
0826       wires << stname << " input=> " << trename << ".stubtripout output=> "
0827             << TCDName(layerdisk1, layerdisk2, layerdisk3, iTC) << ".stubtriplet" << ((iST * nTC) % nST) << "in"
0828             << std::endl;
0829     }
0830 
0831     modules << "FitTrack: " << FTName(layerdisk1, layerdisk2, layerdisk3) << std::endl;
0832   }
0833 }
0834 
0835 void TrackletConfigBuilder::writeAPMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
0836   // The AllProjection memories (e.g. AP_L2PHIA) contain the intercept point of the projection to
0837   // a layer. Each is written by one PR module of similar name (e.g. PR_L2PHIA), and read by
0838   // a MC (e.g. MC_L2PHIA).
0839 
0840   if (combinedmodules_)
0841     return;
0842 
0843   for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0844     for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
0845       memories << "AllProj: AP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << " [56]" << std::endl;
0846       modules << "ProjectionRouter: PR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
0847 
0848       os << "AP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << " input=> PR_" << LayerName(ilayer) << "PHI"
0849          << iTCStr(iReg) << ".allprojout output=> MC_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allprojin"
0850          << std::endl;
0851     }
0852   }
0853 }
0854 
0855 void TrackletConfigBuilder::writeCMMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
0856   // The CandidateMatch memory (e.g. CM_L1PHIA1) are each written by ME module of similar name
0857   // (e.g. ME_L1PHIA1) and contain indices of matching (tracklet projections,stubs) in the specified
0858   // VM region.
0859   // All CM memories in a given phi region (e.g. L1PHIA) are read by a MC module (e.g. MC_L1PHIA) that
0860   // does more precise matching.
0861 
0862   if (combinedmodules_)
0863     return;
0864 
0865   for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0866     for (unsigned int iME = 0; iME < NVMME_[ilayer] * NRegions_[ilayer]; iME++) {
0867       memories << "CandidateMatch: CM_" << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << iME + 1
0868                << " [12]" << std::endl;
0869       modules << "MatchEngine: ME_" << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << iME + 1
0870               << std::endl;
0871 
0872       os << "CM_" << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << iME + 1 << " input=> ME_"
0873          << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << iME + 1 << ".matchout output=> MC_"
0874          << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << ".matchin" << std::endl;
0875     }
0876   }
0877 }
0878 
0879 void TrackletConfigBuilder::writeVMPROJMemories(std::ostream& os, std::ostream& memories, std::ostream&) {
0880   // The VMPROJ memories (e.g. VMPROJ_L2PHIA1) written by a PR module each correspond to projections to
0881   // a single VM region in a layer. Each is filled by the PR using all projections (TPROJ) to this VM
0882   // from different seeding layers.
0883   //
0884   // Each VMPROJ memory is read by a ME module, which matches the projection to stubs.
0885 
0886   if (combinedmodules_)
0887     return;
0888 
0889   for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0890     for (unsigned int iME = 0; iME < NVMME_[ilayer] * NRegions_[ilayer]; iME++) {
0891       memories << "VMProjections: VMPROJ_" << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << iME + 1
0892                << " [13]" << std::endl;
0893 
0894       os << "VMPROJ_" << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << iME + 1 << " input=> PR_"
0895          << LayerName(ilayer) << "PHI" << iTCStr(iME / NVMME_[ilayer]) << ".vmprojout"
0896          << "PHI" << iTCStr(iME / NVMME_[ilayer]) << iME + 1 << " output=> ME_" << LayerName(ilayer) << "PHI"
0897          << iTCStr(iME / NVMME_[ilayer]) << iME + 1 << ".vmprojin" << std::endl;
0898     }
0899   }
0900 }
0901 
0902 void TrackletConfigBuilder::writeFMMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
0903   // All FullMatch (e.g. FM_L2L3_L1PHIA) memories corresponding to a matches between stubs & tracklets
0904   // in a given region (e.g. L1PHIA) from all seeding layers, are written by a MC module (e.g. MC_L1PHIA).
0905   //
0906   // All FullMatch memories corresponding to a given seed pair are read by the TrackBuilder (e.g. FT_L1L2),
0907   // which checks if the track has stubs in enough layers.
0908 
0909   if (combinedmodules_) {
0910     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0911       for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
0912         if (duplicateMPs_) {
0913           if ((settings_.layersDisksDuplicatedEqualProjBalance()[ilayer] ||
0914                settings_.layersDisksDuplicatedWeightedProjBalance()[ilayer]) &&
0915               (iReg == 1 || iReg == 2)) {  // regions with worst truncation
0916             modules << "MatchProcessor: MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
0917             modules << "MatchProcessor: MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) + "_E" << std::endl;
0918             for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
0919               if (matchport_[iSeed][ilayer] == -1)
0920                 continue;
0921               memories << "FullMatch: FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg)
0922                        << " [36]" << std::endl;
0923               memories << "FullMatch: FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI"
0924                        << iTCStr(iReg) + "_E"
0925                        << " [36]" << std::endl;
0926               os << "FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << " input=> MP_"
0927                  << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".matchout1 output=> FT_" << iSeedStr(iSeed)
0928                  << ".fullmatch" << matchport_[iSeed][ilayer] << "in" << iReg + 1 << std::endl;
0929               os << "FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) + "_E"
0930                  << " input=> MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) + "_E"
0931                  << ".matchout1 output=> FT_" << iSeedStr(iSeed) << ".fullmatch" << matchport_[iSeed][ilayer] << "in"
0932                  << iReg + 1 << std::endl;
0933             }
0934           } else {
0935             modules << "MatchProcessor: MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
0936             for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
0937               if (matchport_[iSeed][ilayer] == -1)
0938                 continue;
0939               memories << "FullMatch: FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg)
0940                        << " [36]" << std::endl;
0941               os << "FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << " input=> MP_"
0942                  << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".matchout1 output=> FT_" << iSeedStr(iSeed)
0943                  << ".fullmatch" << matchport_[iSeed][ilayer] << "in" << iReg + 1 << std::endl;
0944             }
0945           }
0946         } else {  // non-duplicate MPs configuration
0947           modules << "MatchProcessor: MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
0948           for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
0949             if (matchport_[iSeed][ilayer] == -1)
0950               continue;
0951             memories << "FullMatch: FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg)
0952                      << " [36]" << std::endl;
0953             os << "FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << " input=> MP_"
0954                << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".matchout1 output=> FT_" << iSeedStr(iSeed)
0955                << ".fullmatch" << matchport_[iSeed][ilayer] << "in" << iReg + 1 << std::endl;
0956           }
0957         }
0958       }
0959     }
0960   } else {
0961     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0962       for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
0963         modules << "MatchCalculator: MC_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
0964         for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
0965           if (matchport_[iSeed][ilayer] == -1)
0966             continue;
0967           memories << "FullMatch: FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg)
0968                    << " [36]" << std::endl;
0969           os << "FM_" << iSeedStr(iSeed) << "_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << " input=> MC_"
0970              << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".matchout1 output=> FT_" << iSeedStr(iSeed)
0971              << ".fullmatch" << matchport_[iSeed][ilayer] << "in" << iReg + 1 << std::endl;
0972         }
0973       }
0974     }
0975   }
0976 }
0977 
0978 void TrackletConfigBuilder::writeASMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
0979   // Each VMR writes AllStub memories (AS) for a single phi region (e.g. PHIC),
0980   // merging data from all DTCs related to this phi region. It does so by merging data from
0981   // the IL memories written by all IRs for this phi region. The wiring map lists all
0982   // IL memories that feed (">") into a single VMR ("VMR_L1PHIC") that writes to the
0983   // an AS memory ("AS_L1PHIC").
0984   // Multiple copies of each AS memory exist where several modules in chain want to read it.
0985 
0986   if (combinedmodules_) {
0987     //First write AS memories used by MatchProcessor
0988     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
0989       for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
0990         if (duplicateMPs_) {
0991           if ((settings_.layersDisksDuplicatedEqualProjBalance()[ilayer] ||
0992                settings_.layersDisksDuplicatedWeightedProjBalance()[ilayer]) &&
0993               (iReg == 1 || iReg == 2)) {
0994             memories << "AllStubs: AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
0995                      << " [42]" << std::endl;
0996             memories << "AllStubs: AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n2"
0997                      << " [42]" << std::endl;
0998             if (combinedmodules_) {
0999               modules << "VMRouterCM: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1000             } else {
1001               modules << "VMRouter: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1002             }
1003             os << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1004                << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubout output=> MP_"
1005                << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubin" << std::endl;
1006             os << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n2"
1007                << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubout output=> MP_"
1008                << LayerName(ilayer) << "PHI" << iTCStr(iReg) + "_E"
1009                << ".allstubin" << std::endl;
1010           } else {
1011             memories << "AllStubs: AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1012                      << " [42]" << std::endl;
1013             if (combinedmodules_) {
1014               modules << "VMRouterCM: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1015             } else {
1016               modules << "VMRouter: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1017             }
1018             os << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1019                << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubout output=> MP_"
1020                << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubin" << std::endl;
1021           }
1022         } else {  // non duplicate MPs configuration
1023           memories << "AllStubs: AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1024                    << " [42]" << std::endl;
1025           if (combinedmodules_) {
1026             modules << "VMRouterCM: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1027           } else {
1028             modules << "VMRouter: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1029           }
1030           os << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1031              << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubout output=> MP_"
1032              << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubin" << std::endl;
1033         }
1034       }
1035     }
1036 
1037     //Next write AS memories used by TrackletProcessor
1038     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
1039       for (int iReg = 0; iReg < (int)NRegions_[ilayer]; iReg++) {
1040         for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1041           unsigned int l1 = seedLayers(iSeed).first;
1042           unsigned int l2 = seedLayers(iSeed).second;
1043 
1044           if (ilayer != l1 && ilayer != l2)
1045             continue;
1046 
1047           bool inner = ilayer == l1;
1048 
1049           for (unsigned int iTC = 0; iTC < TC_[iSeed].size(); iTC++) {
1050             int nTCReg = TC_[iSeed].size() / NRegions_[l2];
1051 
1052             int iTCReg = iTC / nTCReg;
1053 
1054             int jTCReg = iTC % nTCReg;
1055 
1056             if (ilayer == l2) {
1057               if (iTCReg != iReg)
1058                 continue;
1059             }
1060 
1061             string ext = "";
1062 
1063             if (ilayer == l1) {
1064               int ratio = NRegions_[l1] / NRegions_[l2];
1065               int min = iTCReg * ratio - 1 + jTCReg;
1066               int max = (iTCReg + 1) * ratio - (nTCReg - jTCReg - 1);
1067               if ((int)iReg < min || (int)iReg > max)
1068                 continue;
1069 
1070               if (max - min >= 2) {
1071                 ext = "M";
1072                 if (iReg == min)
1073                   ext = "R";
1074                 if (iReg == max)
1075                   ext = "L";
1076               }
1077 
1078               if (max - min == 1) {
1079                 if (nTCReg == 2) {
1080                   assert(0);
1081                   if (jTCReg == 0) {
1082                     if (iReg == min)
1083                       ext = "R";
1084                     if (iReg == max)
1085                       ext = "B";
1086                   }
1087                   if (jTCReg == 1) {
1088                     if (iReg == min)
1089                       ext = "A";
1090                     if (iReg == max)
1091                       ext = "L";
1092                   }
1093                 }
1094                 if (nTCReg == 3) {
1095                   if (jTCReg == 0) {
1096                     if (iReg == min)
1097                       ext = "A";
1098                     if (iReg == max)
1099                       ext = "F";
1100                   }
1101                   if (jTCReg == 1) {
1102                     if (iReg == min)
1103                       ext = "E";
1104                     if (iReg == max)
1105                       ext = "D";
1106                   }
1107                   if (jTCReg == 2) {
1108                     if (iReg == min)
1109                       ext = "C";
1110                     if (iReg == max)
1111                       ext = "B";
1112                   }
1113                 }
1114               }
1115               assert(!ext.empty());
1116             }
1117 
1118             if (ext.empty()) {
1119               ext = "_" + LayerName(l1) + iTCStr(iTC);
1120             }
1121 
1122             if (iSeed < 4) {  //Barrel seeding
1123               ext = "_B" + ext;
1124             } else if (iSeed > 5) {
1125               ext = "_O" + ext;
1126             } else {
1127               ext = "_D" + ext;
1128             }
1129 
1130             if (inner) {
1131               memories << "AllInnerStubs: ";
1132             } else {
1133               memories << "AllStubs: ";
1134             }
1135             memories << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ext << " [42]" << std::endl;
1136             os << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ext << " input=> VMR_" << LayerName(ilayer)
1137                << "PHI" << iTCStr(iReg) << ".all" << (inner ? "inner" : "") << "stubout output=> TP_" << iSeedStr(iSeed)
1138                << iTCStr(iTC);
1139             if (inner) {
1140               os << ".innerallstubin" << std::endl;
1141             } else {
1142               os << ".outerallstubin" << std::endl;
1143             }
1144           }
1145         }
1146       }
1147     }
1148 
1149   } else {
1150     //First write AS memories used by MatchCalculator
1151     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
1152       for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
1153         memories << "AllStubs: AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1154                  << " [42]" << std::endl;
1155         if (combinedmodules_) {
1156           modules << "VMRouterCM: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1157         } else {
1158           modules << "VMRouter: VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << std::endl;
1159         }
1160         os << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1161            << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubout output=> MC_"
1162            << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubin" << std::endl;
1163       }
1164     }
1165 
1166     //Next write AS memories used by TrackletCalculator
1167     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
1168       for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
1169         unsigned int nmem = 1;
1170 
1171         for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1172           unsigned int l1 = seedLayers(iSeed).first;
1173           unsigned int l2 = seedLayers(iSeed).second;
1174 
1175           if (ilayer != l1 && ilayer != l2)
1176             continue;
1177 
1178           for (unsigned int iTC = 0; iTC < TC_[iSeed].size(); iTC++) {
1179             bool used = false;
1180             // Each TC processes data from several TEs.
1181             for (unsigned int iTE = 0; iTE < TC_[iSeed][iTC].size(); iTE++) {
1182               unsigned int theTE = TC_[iSeed][iTC][iTE];
1183 
1184               unsigned int TE1 = TE_[iSeed][theTE].first;  // VM in inner/outer layer of this TE.
1185               unsigned int TE2 = TE_[iSeed][theTE].second;
1186 
1187               if (l1 == ilayer && iReg == TE1 / NVMTE_[iSeed].first)
1188                 used = true;
1189               if (l2 == ilayer && iReg == TE2 / NVMTE_[iSeed].second)
1190                 used = true;
1191             }
1192 
1193             if (used) {
1194               nmem++;  // Another copy of memory
1195               memories << "AllStubs: AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n" << nmem << " [42]"
1196                        << std::endl;
1197               os << "AS_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n" << nmem << " input=> VMR_"
1198                  << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".allstubout output=> TC_" << iSeedStr(iSeed)
1199                  << iTCStr(iTC);
1200               if (ilayer == l1) {
1201                 os << ".innerallstubin" << std::endl;
1202               } else {
1203                 os << ".outerallstubin" << std::endl;
1204               }
1205             }
1206           }
1207         }
1208       }
1209     }
1210   }
1211 }
1212 
1213 void TrackletConfigBuilder::writeVMSMemories(std::ostream& os, std::ostream& memories, std::ostream&) {
1214   // Each VMR writes to Virtual Module memories ("VMS") to be used later by the ME or TE etc.
1215   // Memory VMSTE_L1PHIC9-12 is the memory for small phi region C in L1 for the TE module.
1216   // Numbers 9-12 correspond to the 4 VMs in this phi region.
1217   //
1218   // Each TE reads one VMS memory in each seeding layer.
1219 
1220   if (combinedmodules_) {
1221     //First write VMS memories used by MatchProcessor
1222     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
1223       for (unsigned int iReg = 0; iReg < NRegions_[ilayer]; iReg++) {
1224         if (duplicateMPs_) {
1225           if ((settings_.layersDisksDuplicatedEqualProjBalance()[ilayer] ||
1226                settings_.layersDisksDuplicatedWeightedProjBalance()[ilayer]) &&
1227               (iReg == 1 || iReg == 2)) {
1228             memories << "VMStubsME: VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1 [18]" << std::endl;
1229             memories << "VMStubsME: VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n2 [18]" << std::endl;
1230             os << "VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1231                << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstuboutPHI" << iTCStr(iReg)
1232                << " output=> MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstubin" << std::endl;
1233             os << "VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n2"
1234                << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstuboutPHI" << iTCStr(iReg)
1235                << " output=> MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) + "_E"
1236                << ".vmstubin" << std::endl;
1237           } else {
1238             memories << "VMStubsME: VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1 [18]" << std::endl;
1239             os << "VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1240                << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstuboutPHI" << iTCStr(iReg)
1241                << " output=> MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstubin" << std::endl;
1242           }
1243         } else {  // non duplicate MPs configuration
1244           memories << "VMStubsME: VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1 [18]" << std::endl;
1245           os << "VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << "n1"
1246              << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstuboutPHI" << iTCStr(iReg)
1247              << " output=> MP_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstubin" << std::endl;
1248         }
1249       }
1250     }
1251 
1252     //Next write VMS memories used by TrackletProcessor
1253     for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1254       //FIXME - code could be cleaner
1255       unsigned int l1 = seedLayers(iSeed).first;
1256       unsigned int l2 = seedLayers(iSeed).second;
1257 
1258       unsigned int ilayer = seedLayers(iSeed).second;
1259 
1260       //for(unsigned int iReg=0;iReg<NRegions_[ilayer];iReg++){
1261 
1262       unsigned int nTCReg = TC_[iSeed].size() / NRegions_[l2];
1263 
1264       for (unsigned int iReg = 0; iReg < NRegions_[l2]; iReg++) {
1265         unsigned int nmem = 0;
1266         //Hack since we use same module twice
1267         if (iSeed == Seed::L2D1) {
1268           nmem = 2;
1269         }
1270 
1271         for (unsigned iTC = 0; iTC < nTCReg; iTC++) {
1272           nmem++;
1273           memories << "VMStubsTE: VMSTE_" << LayerName(ilayer) << "PHI" << iRegStr(iReg, iSeed) << "n" << nmem
1274                    << " [18]" << std::endl;
1275           os << "VMSTE_" << LayerName(ilayer) << "PHI" << iRegStr(iReg, iSeed) << "n" << nmem << " input=> VMR_"
1276              << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstubout_seed_" << iSeed << " output=> TP_"
1277              << LayerName(l1) << LayerName(l2) << iTCStr(iReg * nTCReg + iTC) << ".outervmstubin" << std::endl;
1278         }
1279       }
1280     }
1281 
1282   } else {
1283     //First write VMS memories used by MatchEngine
1284     for (unsigned int ilayer = 0; ilayer < N_LAYER + N_DISK; ilayer++) {
1285       for (unsigned int iVMME = 0; iVMME < NVMME_[ilayer] * NRegions_[ilayer]; iVMME++) {
1286         unsigned int iReg = iVMME / NVMME_[ilayer];
1287         memories << "VMStubsME: VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << iVMME + 1 << "n1 [18]"
1288                  << std::endl;
1289         os << "VMSME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << iVMME + 1 << "n1"
1290            << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstuboutMEPHI" << iTCStr(iReg)
1291            << iVMME + 1 << " output=> ME_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << iVMME + 1 << ".vmstubin"
1292            << std::endl;
1293       }
1294     }
1295 
1296     // Next write VMS memories used by TrackletEngine
1297     // Each TE processes one VM region in inner + outer seeding layers, and needs its own copy of input memories.
1298     for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1299       for (unsigned int innerouterseed = 0; innerouterseed < 2; innerouterseed++) {
1300         //FIXME - code could be cleaner
1301         unsigned int l1 = seedLayers(iSeed).first;
1302         unsigned int l2 = seedLayers(iSeed).second;
1303 
1304         unsigned int NVMTE1 = NVMTE_[iSeed].first;
1305         unsigned int NVMTE2 = NVMTE_[iSeed].second;
1306 
1307         unsigned int ilayer = l1;
1308         unsigned int NVMTE = NVMTE1;
1309         if (innerouterseed == 1) {
1310           ilayer = l2;
1311           NVMTE = NVMTE2;
1312         }
1313 
1314         for (unsigned int iVMTE = 0; iVMTE < NVMTE * NRegions_[ilayer]; iVMTE++) {
1315           unsigned int iReg = iVMTE / NVMTE;
1316 
1317           unsigned int nmem = 0;
1318 
1319           if (iSeed == Seed::L2D1) {
1320             nmem = 4;
1321           }
1322 
1323           for (unsigned int iTE = 0; iTE < TE_[iSeed].size(); iTE++) {
1324             unsigned int TE1 = TE_[iSeed][iTE].first;  // VM region in inner/outer layer of this TE
1325             unsigned int TE2 = TE_[iSeed][iTE].second;
1326 
1327             bool used = false;
1328 
1329             if (innerouterseed == 0 && iVMTE == TE1)
1330               used = true;
1331             if (innerouterseed == 1 && iVMTE == TE2)
1332               used = true;
1333 
1334             if (!used)
1335               continue;
1336 
1337             string inorout = "I";
1338             if (innerouterseed == 1)
1339               inorout = "O";
1340 
1341             nmem++;  // Add another copy of memory.
1342             memories << "VMStubsTE: VMSTE_" << LayerName(ilayer) << "PHI" << iRegStr(iReg, iSeed) << iVMTE + 1 << "n"
1343                      << nmem << " [18]" << std::endl;
1344             os << "VMSTE_" << LayerName(ilayer) << "PHI" << iRegStr(iReg, iSeed) << iVMTE + 1 << "n" << nmem
1345                << " input=> VMR_" << LayerName(ilayer) << "PHI" << iTCStr(iReg) << ".vmstuboutTE" << inorout << "PHI"
1346                << iRegStr(iReg, iSeed) << iVMTE + 1 << " output=> TE_" << LayerName(l1) << "PHI"
1347                << iRegStr(TE1 / NVMTE1, iSeed) << TE1 + 1 << "_" << LayerName(l2) << "PHI"
1348                << iRegStr(TE2 / NVMTE2, iSeed) << TE2 + 1;
1349             if (innerouterseed == 0) {
1350               os << ".innervmstubin" << std::endl;
1351             } else {
1352               os << ".outervmstubin" << std::endl;
1353             }
1354           }
1355         }
1356       }
1357     }
1358   }
1359 }
1360 
1361 void TrackletConfigBuilder::writeTPARMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
1362   // Each TC module (e.g. TC_L1L2A) stores helix params in a single TPAR memory of similar name
1363   // (e.g. TPAR_L1L2A). The TPAR is subsequently read by the TrackBuilder (FT).
1364 
1365   if (combinedmodules_) {
1366     for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1367       for (unsigned int iTP = 0; iTP < TC_[iSeed].size(); iTP++) {
1368         memories << "TrackletParameters: TPAR_" << iSeedStr(iSeed) << iTCStr(iTP) << " [56]" << std::endl;
1369         modules << "TrackletProcessor: TP_" << iSeedStr(iSeed) << iTCStr(iTP) << std::endl;
1370         os << "TPAR_" << iSeedStr(iSeed) << iTCStr(iTP) << " input=> TP_" << iSeedStr(iSeed) << iTCStr(iTP)
1371            << ".trackpar output=> FT_" << iSeedStr(iSeed) << ".tparin" << std::endl;
1372       }
1373     }
1374   } else {
1375     for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1376       for (unsigned int iTC = 0; iTC < TC_[iSeed].size(); iTC++) {
1377         memories << "TrackletParameters: TPAR_" << iSeedStr(iSeed) << iTCStr(iTC) << " [56]" << std::endl;
1378         modules << "TrackletCalculator: TC_" << iSeedStr(iSeed) << iTCStr(iTC) << std::endl;
1379         os << "TPAR_" << iSeedStr(iSeed) << iTCStr(iTC) << " input=> TC_" << iSeedStr(iSeed) << iTCStr(iTC)
1380            << ".trackpar output=> FT_" << iSeedStr(iSeed) << ".tparin" << std::endl;
1381       }
1382     }
1383   }
1384 }
1385 
1386 void TrackletConfigBuilder::writeTFMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
1387   for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1388     memories << "TrackFit: TF_" << iSeedStr(iSeed) << " [126]" << std::endl;
1389     modules << "FitTrack: FT_" << iSeedStr(iSeed) << std::endl;
1390     os << "TF_" << iSeedStr(iSeed) << " input=> FT_" << iSeedStr(iSeed) << ".trackout output=> PD.trackin" << std::endl;
1391   }
1392 }
1393 
1394 void TrackletConfigBuilder::writeCTMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
1395   modules << "PurgeDuplicate: PD" << std::endl;
1396 
1397   for (unsigned int iSeed = 0; iSeed < N_SEED_PROMPT; iSeed++) {
1398     memories << "CleanTrack: CT_" << iSeedStr(iSeed) << " [126]" << std::endl;
1399     os << "CT_" << iSeedStr(iSeed) << " input=> PD.trackout output=>" << std::endl;
1400   }
1401 }
1402 
1403 void TrackletConfigBuilder::writeILMemories(std::ostream& os, std::ostream& memories, std::ostream& modules) {
1404   // Each Input Router (IR) reads stubs from one DTC (e.g. PS10G_1) & sends them
1405   // to 4-8 InputLink (IL) memories (labelled PHIA-PHIH), each corresponding to a small
1406   // phi region of a nonant, for each tracklet layer (L1-L6 or D1-D5) that the DTC
1407   // reads. The InputLink memories have names such as IL_L1PHIC_PS10G_1 to reflect this.
1408 
1409   string olddtc = "";
1410   for (const DTCinfo& info : vecDTCinfo_) {
1411     string dtcname = info.name;
1412     if (olddtc != dtcname) {
1413       // Write one entry per DTC, with each DTC connected to one IR.
1414       modules << "InputRouter: IR_" << dtcname << "_A" << std::endl;
1415       modules << "InputRouter: IR_" << dtcname << "_B" << std::endl;
1416       memories << "DTCLink: DL_" << dtcname << "_A [36]" << std::endl;
1417       memories << "DTCLink: DL_" << dtcname << "_B [36]" << std::endl;
1418       os << "DL_" << dtcname << "_A"
1419          << " input=> output=> IR_" << dtcname << "_A.stubin" << std::endl;
1420       os << "DL_" << dtcname << "_B"
1421          << " input=> output=> IR_" << dtcname << "_B.stubin" << std::endl;
1422     }
1423     olddtc = dtcname;
1424   }
1425 
1426   for (const DTCinfo& info : vecDTCinfo_) {
1427     string dtcname = info.name;
1428     int layerdisk = info.layer;
1429 
1430     for (unsigned int iReg = 0; iReg < NRegions_[layerdisk]; iReg++) {
1431       //--- Ian Tomalin's proposed bug fix
1432       double phiminDTC_A = info.phimin - M_PI / N_SECTOR;  // Phi range of each DTC.
1433       double phimaxDTC_A = info.phimax - M_PI / N_SECTOR;
1434       double phiminDTC_B = info.phimin + M_PI / N_SECTOR;  // Phi range of each DTC.
1435       double phimaxDTC_B = info.phimax + M_PI / N_SECTOR;
1436       if (allStubs_[layerdisk][iReg].second > phiminDTC_A && allStubs_[layerdisk][iReg].first < phimaxDTC_A) {
1437         memories << "InputLink: IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_A"
1438                  << " [36]" << std::endl;
1439         os << "IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_A"
1440            << " input=> IR_" << dtcname << "_A.stubout output=> VMR_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg)
1441            << ".stubin" << std::endl;
1442       }
1443       if (allStubs_[layerdisk][iReg].second > phiminDTC_B && allStubs_[layerdisk][iReg].first < phimaxDTC_B) {
1444         memories << "InputLink: IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_B"
1445                  << " [36]" << std::endl;
1446         os << "IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_B"
1447            << " input=> IR_" << dtcname << "_B.stubout output=> VMR_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg)
1448            << ".stubin" << std::endl;
1449       }
1450       //--- Original (buggy) code
1451       /*
1452       double phiminDTC = info.phimin; // Phi range of each DTC.
1453       double phimaxDTC = info.phimax;
1454 
1455       if (allStubs_[layerdisk][iReg].first > phimaxDTC && allStubs_[layerdisk][iReg].second < phiminDTC) 
1456         continue;
1457 
1458       // Phi region range must be entirely contained in this DTC to keep this connection.
1459       if (allStubs_[layerdisk][iReg].second < phimaxDTC) {
1460         memories << "InputLink: IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_A"
1461                  << " [36]" << std::endl;
1462         os << "IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_A"
1463            << " input=> IR_" << dtcname << "_A.stubout output=> VMR_" << LayerName(layerdisk) << "PHI"
1464            << iTCStr(iReg) << ".stubin" << std::endl;
1465       }
1466 
1467       if (allStubs_[layerdisk][iReg].first > phiminDTC) {
1468         memories << "InputLink: IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_B"
1469                  << " [36]" << std::endl;
1470         os << "IL_" << LayerName(layerdisk) << "PHI" << iTCStr(iReg) << "_" << dtcname << "_B"
1471            << " input=> IR_" << dtcname << "_B.stubout output=> VMR_" << LayerName(layerdisk) << "PHI"
1472            << iTCStr(iReg) << ".stubin" << std::endl;
1473       }
1474 */
1475     }
1476   }
1477 }
1478 
1479 //--- Fill streams used to write wiring map to file
1480 
1481 void TrackletConfigBuilder::writeAll(std::ostream& wires, std::ostream& memories, std::ostream& modules) {
1482   writeILMemories(wires, memories, modules);
1483   writeASMemories(wires, memories, modules);
1484   writeVMSMemories(wires, memories, modules);
1485   writeSPMemories(wires, memories, modules);
1486   writeSPDMemories(wires, memories, modules);
1487   writeProjectionMemories(wires, memories, modules);
1488   writeTPARMemories(wires, memories, modules);
1489   writeVMPROJMemories(wires, memories, modules);
1490   writeAPMemories(wires, memories, modules);
1491   writeCMMemories(wires, memories, modules);
1492   writeFMMemories(wires, memories, modules);
1493   writeTFMemories(wires, memories, modules);
1494   writeCTMemories(wires, memories, modules);
1495 }