Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:21:59

0001 //
0002 // Integer representation of floating point arithmetic suitable for FPGA designs
0003 //
0004 // Author: Yuri Gershtein
0005 // Date:   March 2018
0006 //
0007 
0008 #include "L1Trigger/TrackFindingTracklet/interface/imath.h"
0009 
0010 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0011 
0012 #include <cmath>
0013 
0014 using namespace trklet;
0015 
0016 std::string VarBase::itos(int i) { return std::to_string(i); }
0017 
0018 std::string VarBase::kstring() const {
0019   char s[1024];
0020   std::string t = "";
0021   for (const auto &Kmap : Kmap_) {
0022     sprintf(s, "^(%i)", Kmap.second);
0023     std::string t0(s);
0024     t = t + Kmap.first + t0;
0025   }
0026   return t;
0027 }
0028 
0029 void VarBase::analyze() {
0030   if (!readytoanalyze_)
0031     return;
0032 
0033   double u = maxval_;
0034   if (u < -minval_)
0035     u = -minval_;
0036 
0037   int iu = log2(range() / u);
0038   if (iu > 1) {
0039     char slog[1024];
0040     sprintf(slog,
0041             "analyzing %s: range %g is much larger then %g. suggest cutting by a factor of 2^%i",
0042             name_.c_str(),
0043             range(),
0044             u,
0045             iu);
0046     edm::LogVerbatim("Tracklet") << slog;
0047   }
0048 #ifdef IMATH_ROOT
0049   char slog[100];
0050   if (h_) {
0051     double eff = h_->Integral() / h_->GetEntries();
0052     if (eff < 0.99) {
0053       sprintf(slog, "analyzing %s: range is too small, contains %f", name_.c_str(), eff);
0054       edm::LogVerbatim("Tracklet") << slog;
0055       h_->Print();
0056     }
0057     globals_->h_file_->cd();
0058     TCanvas *c = new TCanvas();
0059     c->cd();
0060     h_->Draw("colz");
0061     h_->Write();
0062   } else {
0063     if (globals_->use_root) {
0064       sprintf(slog, "analyzing %s: no histogram!\n", name_.c_str());
0065       edm::LogVerbatim("Tracklet") << slog;
0066     }
0067   }
0068 #endif
0069 
0070   if (p1_)
0071     p1_->analyze();
0072   if (p2_)
0073     p2_->analyze();
0074 
0075   readytoanalyze_ = false;
0076 }
0077 
0078 std::string VarBase::dump() {
0079   char s[1024];
0080   std::string u = kstring();
0081   sprintf(
0082       s,
0083       "Name = %s \t Op = %s \t nbits = %i \n       ival = %li \t fval = %g \t K = %g Range = %f\n       units = %s\n",
0084       name_.c_str(),
0085       op_.c_str(),
0086       nbits_,
0087       ival_,
0088       fval_,
0089       K_,
0090       range(),
0091       u.c_str());
0092   std::string t(s);
0093   return t;
0094 }
0095 
0096 void VarBase::dump_msg() {
0097   char s[2048];
0098   std::string u = kstring();
0099   sprintf(s,
0100           "Name = %s \t Op = %s \t nbits = %i \n       ival = %li \t fval = %g \t K = %g Range = %f\n       units = "
0101           "%s\n       step = %i, latency = %i\n",
0102           name_.c_str(),
0103           op_.c_str(),
0104           nbits_,
0105           ival_,
0106           fval_,
0107           K_,
0108           range(),
0109           u.c_str(),
0110           step_,
0111           latency_);
0112   std::string t(s);
0113   edm::LogVerbatim("Tracklet") << t;
0114   if (p1_)
0115     p1_->dump_msg();
0116   if (p2_)
0117     p2_->dump_msg();
0118 }
0119 
0120 void VarAdjustK::adjust(double Knew, double epsilon, bool do_assert, int nbits) {
0121   //WARNING!!!
0122   //THIS METHID CAN BE USED ONLY FOR THE FINAL ANSWER
0123   //THE CHANGE IN CONSTANT CAN NOT BE PROPAGATED UP THE CALCULATION TREE
0124 
0125   K_ = p1_->K();
0126   Kmap_ = p1_->Kmap();
0127   double r = Knew / K_;
0128 
0129   lr_ = (r > 1) ? log2(r) + epsilon : log2(r);
0130   K_ = K_ * pow(2, lr_);
0131   if (do_assert)
0132     assert(std::abs(Knew / K_ - 1) < epsilon);
0133 
0134   if (nbits > 0)
0135     nbits_ = nbits;
0136   else
0137     nbits_ = p1_->nbits() - lr_;
0138 
0139   Kmap_["2"] = Kmap_["2"] + lr_;
0140 }
0141 
0142 void VarInv::initLUT(double offset) {
0143   offset_ = offset;
0144   double offsetI = lround(offset_ / p1_->K());
0145   for (int i = 0; i < Nelements_; ++i) {
0146     int i1 = addr_to_ival(i);
0147     LUT[i] = gen_inv(offsetI + i1);
0148   }
0149 }
0150 
0151 void VarBase::makeready() {
0152   pipe_counter_ = 0;
0153   pipe_delays_.clear();
0154   readytoprint_ = true;
0155   readytoanalyze_ = true;
0156   usedasinput_ = false;
0157   if (p1_)
0158     p1_->makeready();
0159   if (p2_)
0160     p2_->makeready();
0161   if (p3_)
0162     p3_->makeready();
0163 }
0164 
0165 bool VarBase::has_delay(int i) {
0166   //dumb sequential search
0167   for (int pipe_delay : pipe_delays_)
0168     if (pipe_delay == i)
0169       return true;
0170   return false;
0171 }
0172 
0173 std::string VarBase::pipe_delay(VarBase *v, int nbits, int delay) {
0174   //have we been delayed by this much already?
0175   if (v->has_delay(delay))
0176     return "";
0177   v->add_delay(delay);
0178   std::string name = v->name();
0179   std::string name_delayed = name + "_delay" + itos(delay);
0180   std::string out = "wire signed [" + itos(nbits - 1) + ":0] " + name_delayed + ";\n";
0181   out = out + pipe_delay_wire(v, name_delayed, nbits, delay);
0182   return out;
0183 }
0184 std::string VarBase::pipe_delays(const int step) {
0185   std::string out = "";
0186   if (p1_)
0187     out += p1_->pipe_delays(step);
0188   if (p2_)
0189     out += p2_->pipe_delays(step);
0190   if (p3_)
0191     out += p3_->pipe_delays(step);
0192 
0193   int l = step - latency_ - step_;
0194   return (out + pipe_delay(this, nbits(), l));
0195 }
0196 std::string VarBase::pipe_delay_wire(VarBase *v, std::string name_delayed, int nbits, int delay) {
0197   std::string name = v->name();
0198   std::string name_pipe = name + "_pipe" + itos(v->pipe_counter());
0199   v->pipe_increment();
0200   std::string out = "pipe_delay #(.STAGES(" + itos(delay) + "), .WIDTH(" + itos(nbits) + ")) " + name_pipe +
0201                     "(.clk(clk), .val_in(" + name + "), .val_out(" + name_delayed + "));\n";
0202   return out;
0203 }
0204 
0205 void VarBase::inputs(std::vector<VarBase *> *vd) {
0206   if (op_ == "def" && !usedasinput_) {
0207     usedasinput_ = true;
0208     vd->push_back(this);
0209   } else {
0210     if (p1_)
0211       p1_->inputs(vd);
0212     if (p2_)
0213       p2_->inputs(vd);
0214     if (p3_)
0215       p3_->inputs(vd);
0216   }
0217 }
0218 
0219 #ifdef IMATH_ROOT
0220 TTree *VarBase::addToTree(imathGlobals *globals, VarBase *v, char *s) {
0221   if (globals->h_file_ == 0) {
0222     globals->h_file_ = new TFile("imath.root", "RECREATE");
0223     edm::LogVerbatim("Tracklet") << "recreating file imath.root";
0224   }
0225   globals->h_file_->cd();
0226   TTree *tt = (TTree *)globals->h_file_->Get("tt");
0227   if (tt == 0) {
0228     tt = new TTree("tt", "");
0229     edm::LogVerbatim("Tracklet") << "creating TTree tt";
0230   }
0231   std::string si = v->name() + "_i";
0232   std::string sf = v->name() + "_f";
0233   std::string sv = v->name();
0234   if (s != 0) {
0235     std::string prefix(s);
0236     si = prefix + si;
0237     sf = prefix + sf;
0238     sv = prefix + sv;
0239   }
0240   if (!tt->GetBranchStatus(si.c_str())) {
0241     tt->Branch(si.c_str(), (Long64_t *)&(v->ival_));
0242     tt->Branch(sf.c_str(), &(v->fval_));
0243     tt->Branch(sv.c_str(), &(v->val_));
0244   }
0245 
0246   if (v->p1_)
0247     addToTree(globals, v->p1_, s);
0248   if (v->p2_)
0249     addToTree(globals, v->p2_, s);
0250   if (v->p3_)
0251     addToTree(globals, v->p3_, s);
0252 
0253   return tt;
0254 }
0255 TTree *VarBase::addToTree(imathGlobals *globals, double *v, char *s) {
0256   if (globals->h_file_ == 0) {
0257     globals->h_file_ = new TFile("imath.root", "RECREATE");
0258     edm::LogVerbatim("Tracklet") << "recreating file imath.root";
0259   }
0260   globals->h_file_->cd();
0261   TTree *tt = (TTree *)globals->h_file_->Get("tt");
0262   if (tt == 0) {
0263     tt = new TTree("tt", "");
0264     edm::LogVerbatim("Tracklet") << "creating TTree tt";
0265   }
0266   tt->Branch(s, v);
0267   return tt;
0268 }
0269 TTree *VarBase::addToTree(imathGlobals *globals, int *v, char *s) {
0270   if (globals->h_file_ == 0) {
0271     globals->h_file_ = new TFile("imath.root", "RECREATE");
0272     edm::LogVerbatim("Tracklet") << "recreating file imath.root";
0273   }
0274   globals->h_file_->cd();
0275   TTree *tt = (TTree *)globals->h_file_->Get("tt");
0276   if (tt == 0) {
0277     tt = new TTree("tt", "");
0278     edm::LogVerbatim("Tracklet") << "creating TTree tt";
0279   }
0280   tt->Branch(s, v);
0281   return tt;
0282 }
0283 void VarBase::fillTree(imathGlobals *globals) {
0284   if (globals->h_file_ == 0)
0285     return;
0286   globals->h_file_->cd();
0287   TTree *tt = (TTree *)globals->h_file_->Get("tt");
0288   if (tt == 0)
0289     return;
0290   tt->Fill();
0291 }
0292 void VarBase::writeTree(imathGlobals *globals) {
0293   if (globals->h_file_ == 0)
0294     return;
0295   globals->h_file_->cd();
0296   TTree *tt = (TTree *)globals->h_file_->Get("tt");
0297   if (tt == 0)
0298     return;
0299   tt->Write();
0300 }
0301 
0302 #endif
0303 
0304 void VarCut::local_passes(std::map<const VarBase *, std::vector<bool> > &passes,
0305                           const std::map<const VarBase *, std::vector<bool> > *const previous_passes) const {
0306   const int lower_cut = lower_cut_ / cut_var_->K();
0307   const int upper_cut = upper_cut_ / cut_var_->K();
0308   if (!previous_passes || (previous_passes && !previous_passes->count(cut_var_))) {
0309     if (!passes.count(cut_var_))
0310       passes[cut_var_];
0311     passes.at(cut_var_).push_back(cut_var_->ival() > lower_cut && cut_var_->ival() < upper_cut);
0312   }
0313 }
0314 
0315 bool VarBase::local_passes() const {
0316   bool passes = false;
0317   for (const auto &cut : cuts_) {
0318     const VarCut *const cast_cut = (VarCut *)cut;
0319     const int lower_cut = cast_cut->lower_cut() / K_;
0320     const int upper_cut = cast_cut->upper_cut() / K_;
0321     passes = passes || (ival_ > lower_cut && ival_ < upper_cut);
0322     if (globals_->printCutInfo_) {
0323       edm::LogVerbatim("Tracklet") << "  " << name_ << " "
0324                                    << ((ival_ > lower_cut && ival_ < upper_cut) ? "PASSES" : "FAILS")
0325                                    << " (required: " << lower_cut * K_ << " < " << ival_ * K_ << " < " << upper_cut * K_
0326                                    << ")";
0327     }
0328   }
0329   return passes;
0330 }
0331 
0332 void VarBase::passes(std::map<const VarBase *, std::vector<bool> > &passes,
0333                      const std::map<const VarBase *, std::vector<bool> > *const previous_passes) const {
0334   if (p1_)
0335     p1_->passes(passes, previous_passes);
0336   if (p2_)
0337     p2_->passes(passes, previous_passes);
0338   if (p3_)
0339     p3_->passes(passes, previous_passes);
0340 
0341   for (const auto &cut : cuts_) {
0342     const VarCut *const cast_cut = (VarCut *)cut;
0343     const int lower_cut = cast_cut->lower_cut() / K_;
0344     const int upper_cut = cast_cut->upper_cut() / K_;
0345     if (!previous_passes || (previous_passes && !previous_passes->count(this))) {
0346       if (!passes.count(this))
0347         passes[this];
0348       passes.at(this).push_back(ival_ > lower_cut && ival_ < upper_cut);
0349       if (globals_->printCutInfo_) {
0350         edm::LogVerbatim("Tracklet") << "  " << name_ << " "
0351                                      << ((ival_ > lower_cut && ival_ < upper_cut) ? "PASSES" : "FAILS")
0352                                      << " (required: " << lower_cut * K_ << " < " << ival_ * K_ << " < "
0353                                      << upper_cut * K_ << ")";
0354       }
0355     }
0356   }
0357 }
0358 
0359 void VarBase::add_cut(VarCut *cut, const bool call_set_cut_var) {
0360   cuts_.push_back(cut);
0361   if (call_set_cut_var)
0362     cut->set_cut_var(this, false);
0363 }
0364 
0365 void VarCut::set_cut_var(VarBase *cut_var, const bool call_add_cut) {
0366   cut_var_ = cut_var;
0367   if (call_add_cut)
0368     cut_var->add_cut(this, false);
0369   if (parent_flag_)
0370     parent_flag_->calculate_step();
0371 }
0372 
0373 void VarFlag::add_cut(VarBase *cut, const bool call_set_parent_flag) {
0374   cuts_.push_back(cut);
0375   if (cut->op() == "cut" && call_set_parent_flag) {
0376     VarCut *const cast_cut = (VarCut *)cut;
0377     cast_cut->set_parent_flag(this, false);
0378   }
0379   calculate_step();
0380 }
0381 
0382 void VarCut::set_parent_flag(VarFlag *parent_flag, const bool call_add_cut) {
0383   parent_flag_ = parent_flag;
0384   if (call_add_cut)
0385     parent_flag->add_cut(this, false);
0386 }
0387 
0388 VarBase *VarBase::cut_var() {
0389   if (op_ == "cut")
0390     return cut_var_;
0391   else
0392     return this;
0393 }
0394 
0395 bool VarFlag::passes() {
0396   if (globals_->printCutInfo_) {
0397     edm::LogVerbatim("Tracklet") << "Checking if " << name_ << " passes...";
0398   }
0399 
0400   std::map<const VarBase *, std::vector<bool> > passes0, passes1;
0401   for (const auto &cut : cuts_) {
0402     if (cut->op() != "cut")
0403       continue;
0404     const VarCut *const cast_cut = (VarCut *)cut;
0405     cast_cut->local_passes(passes0);
0406   }
0407   for (const auto &cut : cuts_) {
0408     if (cut->op() != "cut")
0409       cut->passes(passes1, &passes0);
0410     else {
0411       if (cut->cut_var()->p1())
0412         cut->cut_var()->p1()->passes(passes1, &passes0);
0413       if (cut->cut_var()->p2())
0414         cut->cut_var()->p2()->passes(passes1, &passes0);
0415       if (cut->cut_var()->p3())
0416         cut->cut_var()->p3()->passes(passes1, &passes0);
0417     }
0418   }
0419 
0420   bool passes = true;
0421   for (const auto &cut_var : passes0) {
0422     bool local_passes = false;
0423     for (const auto pass : cut_var.second)
0424       local_passes = local_passes || pass;
0425     passes = passes && local_passes;
0426   }
0427   for (const auto &cut_var : passes1) {
0428     bool local_passes = false;
0429     for (const auto pass : cut_var.second)
0430       local_passes = local_passes || pass;
0431     passes = passes && local_passes;
0432   }
0433 
0434   if (globals_->printCutInfo_) {
0435     edm::LogVerbatim("Tracklet") << name_ << " " << (passes ? "PASSES" : "FAILS");
0436   }
0437 
0438   return passes;
0439 }