Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:08:26

0001 // -*- C++ -*-
0002 //
0003 // Package:    SiPixelPhase1Common
0004 // Class:      GeometryInterface
0005 //
0006 // Geometry depedence goes here.
0007 //
0008 // Original Author:  Marcel Schneider
0009 
0010 #include "DQM/SiPixelPhase1Common/interface/GeometryInterface.h"
0011 
0012 // general plotting helpers
0013 #include "DQM/SiPixelPhase1Common/interface/SiPixelCoordinates.h"
0014 
0015 // Tracker Geometry/Topology  stuff
0016 #include "Geometry/CommonDetUnit/interface/PixelGeomDetUnit.h"
0017 #include "Geometry/CommonTopologies/interface/PixelTopology.h"
0018 #include "CondFormats/GeometryObjects/interface/PTrackerParameters.h"
0019 #include "CondFormats/SiPixelObjects/interface/SiPixelFrameReverter.h"
0020 
0021 // Pixel names
0022 #include "DataFormats/TrackerCommon/interface/PixelBarrelName.h"
0023 #include "DataFormats/TrackerCommon/interface/PixelEndcapName.h"
0024 
0025 // C++ stuff
0026 #include <cassert>
0027 #include <cstdint>
0028 #include <iostream>
0029 #include <iomanip>
0030 #include <memory>
0031 
0032 const GeometryInterface::Value GeometryInterface::UNDEFINED = 999999999.9f;
0033 
0034 GeometryInterface::GeometryInterface(const edm::ParameterSet& conf,
0035                                      edm::ConsumesCollector&& iC,
0036                                      edm::Transition transition)
0037     : iConfig(conf), cablingMapLabel_{conf.getParameter<std::string>("CablingMapLabel")} {
0038   if (transition == edm::Transition::BeginRun) {
0039     trackerGeometryToken_ = iC.esConsumes<TrackerGeometry, TrackerDigiGeometryRecord, edm::Transition::BeginRun>();
0040     trackerTopologyToken_ = iC.esConsumes<TrackerTopology, TrackerTopologyRcd, edm::Transition::BeginRun>();
0041     siPixelFedCablingMapToken_ =
0042         iC.esConsumes<SiPixelFedCablingMap, SiPixelFedCablingMapRcd, edm::Transition::BeginRun>();
0043     if (!cablingMapLabel_.empty()) {
0044       labeledSiPixelFedCablingMapToken_ =
0045           iC.esConsumes<SiPixelFedCablingMap, SiPixelFedCablingMapRcd, edm::Transition::BeginRun>(
0046               edm::ESInputTag("", cablingMapLabel_));
0047     }
0048   } else {
0049     trackerGeometryToken_ =
0050         iC.esConsumes<TrackerGeometry, TrackerDigiGeometryRecord, edm::Transition::EndLuminosityBlock>();
0051     trackerTopologyToken_ = iC.esConsumes<TrackerTopology, TrackerTopologyRcd, edm::Transition::EndLuminosityBlock>();
0052     siPixelFedCablingMapToken_ =
0053         iC.esConsumes<SiPixelFedCablingMap, SiPixelFedCablingMapRcd, edm::Transition::EndLuminosityBlock>();
0054     if (!cablingMapLabel_.empty()) {
0055       labeledSiPixelFedCablingMapToken_ =
0056           iC.esConsumes<SiPixelFedCablingMap, SiPixelFedCablingMapRcd, edm::Transition::EndLuminosityBlock>(
0057               edm::ESInputTag("", cablingMapLabel_));
0058     }
0059   }
0060 }
0061 
0062 void GeometryInterface::load(edm::EventSetup const& iSetup) {
0063   const TrackerGeometry& trackerGeometry = iSetup.getData(trackerGeometryToken_);
0064   const TrackerTopology& trackerTopology = iSetup.getData(trackerTopologyToken_);
0065   const SiPixelFedCablingMap& siPixelFedCablingMap = iSetup.getData(siPixelFedCablingMapToken_);
0066 
0067   const SiPixelFedCablingMap* labeledSiPixelFedCablingMap = &siPixelFedCablingMap;
0068   if (!cablingMapLabel_.empty()) {
0069     labeledSiPixelFedCablingMap = &iSetup.getData(labeledSiPixelFedCablingMapToken_);
0070   }
0071 
0072   //loadFromAlignment(iSetup, iConfig);
0073   loadFromTopology(trackerGeometry, trackerTopology, iConfig);
0074   loadTimebased(iConfig);
0075   loadModuleLevel(iConfig);
0076   loadFEDCabling(labeledSiPixelFedCablingMap);
0077   loadFromSiPixelCoordinates(trackerGeometry, trackerTopology, siPixelFedCablingMap, iConfig);
0078   edm::LogInfo log("GeometryInterface");
0079   log << "Known colum names:\n";
0080   for (const auto& e : ids)
0081     log << "+++ column: " << e.first << " ok " << bool(extractors[e.second]) << " min " << min_value[e.second]
0082         << " max " << max_value[e.second] << "\n";
0083   is_loaded = true;
0084 }
0085 
0086 void GeometryInterface::loadFromTopology(const TrackerGeometry& trackerGeometry,
0087                                          const TrackerTopology& trackerTopology,
0088                                          const edm::ParameterSet& iConfig) {
0089   std::vector<ID> geomquantities;
0090 
0091   struct TTField {
0092     const TrackerTopology* tt;
0093     TrackerTopology::DetIdFields field;
0094     Value operator()(InterestingQuantities const& iq) {
0095       if (tt->hasField(iq.sourceModule, field))
0096         return tt->getField(iq.sourceModule, field);
0097       else
0098         return UNDEFINED;
0099     };
0100   };
0101 
0102   const TrackerTopology* tt = &trackerTopology;
0103 
0104   std::vector<std::pair<std::string, TTField>> namedPartitions{
0105       {"PXEndcap", {tt, TrackerTopology::PFSide}},
0106 
0107       {"PXLayer", {tt, TrackerTopology::PBLayer}},
0108       {"PXLadder", {tt, TrackerTopology::PBLadder}},
0109       {"PXBModule", {tt, TrackerTopology::PBModule}},
0110 
0111       {"PXBlade", {tt, TrackerTopology::PFBlade}},
0112       {"PXDisk", {tt, TrackerTopology::PFDisk}},
0113       {"PXPanel", {tt, TrackerTopology::PFPanel}},
0114       {"PXFModule", {tt, TrackerTopology::PFModule}},
0115   };
0116 
0117   for (auto& e : namedPartitions) {
0118     geomquantities.push_back(intern(e.first));
0119     addExtractor(intern(e.first), e.second, UNDEFINED, UNDEFINED);
0120   }
0121 
0122   auto pxbarrel = [](InterestingQuantities const& iq) {
0123     return iq.sourceModule.subdetId() == PixelSubdetector::PixelBarrel ? 0 : UNDEFINED;
0124   };
0125   auto pxforward = [](InterestingQuantities const& iq) {
0126     return iq.sourceModule.subdetId() == PixelSubdetector::PixelEndcap ? 0 : UNDEFINED;
0127   };
0128   auto pxall = [](InterestingQuantities const& iq) { return 0; };
0129   addExtractor(intern("PXBarrel"), pxbarrel, 0, 0);
0130   addExtractor(intern("PXForward"), pxforward, 0, 0);
0131   addExtractor(intern("PXAll"), pxall, 0, 0);
0132 
0133   // Redefine the disk numbering to use the sign
0134   auto pxendcap = extractors[intern("PXEndcap")];
0135   auto diskid = intern("PXDisk");
0136   auto pxdisk = extractors[diskid];
0137   extractors[diskid] = [pxdisk, pxendcap](InterestingQuantities const& iq) {
0138     auto disk = pxdisk(iq);
0139     if (disk == UNDEFINED)
0140       return UNDEFINED;
0141     auto endcap = pxendcap(iq);
0142     return endcap == 1 ? -disk : disk;
0143   };
0144 
0145   // DetId and module names
0146   auto detid = [](InterestingQuantities const& iq) {
0147     uint32_t id = iq.sourceModule.rawId();
0148     return Value(id);
0149   };
0150   addExtractor(intern("DetId"), detid, 0, 0  // No sane value possible here.
0151   );
0152   // these are just aliases with special handling in formatting
0153   // the names are created with PixelBarrelName et. al. later
0154   addExtractor(intern("PXModuleName"), detid, 0, 0);
0155 
0156   int phase = iConfig.getParameter<int>("upgradePhase");
0157   bool isUpgrade = phase == 1;
0158 
0159   // Now traverse the detector and collect whatever we need.
0160   auto detids = trackerGeometry.detIds();
0161   for (DetId id : detids) {
0162     if (id.subdetId() != PixelSubdetector::PixelBarrel && id.subdetId() != PixelSubdetector::PixelEndcap)
0163       continue;
0164     auto iq = InterestingQuantities{nullptr, id, 0, 0};
0165 
0166     // prepare pretty names
0167     std::string name = "";
0168     if (id.subdetId() == PixelSubdetector::PixelBarrel) {  // Barrel
0169       PixelBarrelName mod(id, tt, isUpgrade);
0170       name = mod.name();
0171     } else {  // assume Endcap
0172       PixelEndcapName mod(id, tt, isUpgrade);
0173       name = mod.name();
0174     }
0175     format_value[std::make_pair(intern("PXModuleName"), Value(id.rawId()))] = name;
0176 
0177     // we record each module 4 times, one for each corner, so we also get ROCs
0178     // in booking (at least for the ranges)
0179     const PixelGeomDetUnit* detUnit = dynamic_cast<const PixelGeomDetUnit*>(trackerGeometry.idToDetUnit(id));
0180     assert(detUnit);
0181     const PixelTopology* topo = &detUnit->specificTopology();
0182     iq.row = 0;
0183     iq.col = 0;
0184     all_modules.push_back(iq);
0185     iq.row = topo->nrows() - 1;
0186     iq.col = 0;
0187     all_modules.push_back(iq);
0188     iq.row = 0;
0189     iq.col = topo->ncolumns() - 1;
0190     all_modules.push_back(iq);
0191     iq.row = topo->nrows() - 1;
0192     iq.col = topo->ncolumns() - 1;
0193     all_modules.push_back(iq);
0194   }
0195 }
0196 
0197 void GeometryInterface::loadFromSiPixelCoordinates(const TrackerGeometry& trackerGeometry,
0198                                                    const TrackerTopology& trackerTopology,
0199                                                    const SiPixelFedCablingMap& siPixelFedCablingMap,
0200                                                    const edm::ParameterSet& iConfig) {
0201   // TODO: SiPixelCoordinates has a large overlap with theis GeometryInterface
0202   // in general.
0203   // Rough convention is to use own code for things that are easy and fast to
0204   // determine, and use SiPixelCoordinates for complicated things.
0205   // SiPixelCoordinates uses lookup maps for everything, so it is faster than
0206   // most other code, but still slow on DQM scales.
0207   int phase = iConfig.getParameter<int>("upgradePhase");
0208 
0209   // this shared pointer is kept alive by the references in the lambdas that follow.
0210   // That is a bit less obvious than keeping it as a member but more correct.
0211   auto coord = std::make_shared<SiPixelCoordinates>(phase);
0212 
0213   // note that we should reeinit for each event. But this probably won't explode
0214   // thanks to the massive memoization in SiPixelCoordinates which is completely
0215   // initialized while booking.
0216   coord->init(&trackerTopology, &trackerGeometry, &siPixelFedCablingMap);
0217 
0218   // SiPixelCoordinates uses a different convention for UNDEFINED:
0219   auto from_coord = [](double in) { return (in == -9999.0) ? UNDEFINED : Value(in); };
0220 
0221   // Rings are a concept that cannot be derived from bitmasks.
0222   addExtractor(intern("PXRing"), [coord, from_coord](InterestingQuantities const& iq) {
0223     return from_coord(coord->ring(iq.sourceModule));
0224   });
0225 
0226   // Quadrant names.
0227   auto pxbarrel = extractors[intern("PXBarrel")];
0228   addExtractor(
0229       intern("HalfCylinder"),
0230       [coord, pxbarrel](InterestingQuantities const& iq) {
0231         if (pxbarrel(iq) != UNDEFINED)
0232           return UNDEFINED;
0233         int quadrant = coord->quadrant(iq.sourceModule);
0234         switch (quadrant) {
0235           case 1:
0236             return Value(12);  // mO
0237           case 2:
0238             return Value(11);  // mI
0239           case 3:
0240             return Value(22);  // pO
0241           case 4:
0242             return Value(21);  // pI
0243           default:
0244             return UNDEFINED;
0245         }
0246       },
0247       0,
0248       0  // N/A
0249   );
0250   addExtractor(
0251       intern("Shell"),
0252       [coord, pxbarrel](InterestingQuantities const& iq) {
0253         if (pxbarrel(iq) == UNDEFINED)
0254           return UNDEFINED;
0255         int quadrant = coord->quadrant(iq.sourceModule);
0256         switch (quadrant) {
0257           case 1:
0258             return Value(12);  // mO
0259           case 2:
0260             return Value(11);  // mI
0261           case 3:
0262             return Value(22);  // pO
0263           case 4:
0264             return Value(21);  // pI
0265           default:
0266             return UNDEFINED;
0267         }
0268       },
0269       0,
0270       0  // N/A
0271   );
0272 
0273   // Online Numbering.
0274   addExtractor(intern("SignedLadder"), [coord, from_coord](InterestingQuantities const& iq) {
0275     return from_coord(coord->signed_ladder(iq.sourceModule()));
0276   });
0277   addExtractor(intern("SignedModule"), [coord, from_coord](InterestingQuantities const& iq) {
0278     return from_coord(coord->signed_module(iq.sourceModule()));
0279   });
0280   addExtractor(intern("SignedBlade"), [coord, from_coord](InterestingQuantities const& iq) {
0281     return from_coord(coord->signed_blade(iq.sourceModule()));
0282   });
0283 
0284   // Flipped and Outer ladders
0285   addExtractor(intern("OuterLadder"), [coord, from_coord](InterestingQuantities const& iq) {
0286     return from_coord(coord->outer(iq.sourceModule()));
0287   });
0288   addExtractor(intern("FlippedLadder"), [coord, from_coord](InterestingQuantities const& iq) {
0289     return from_coord(coord->flipped(iq.sourceModule()));
0290   });
0291 
0292   // Pixel Map axis.
0293   // TODO: automatic range and binning for phase0 are incorrect.
0294   // Should be set manually here.
0295   addExtractor(
0296       intern("SignedModuleCoord"),  // BPIX x
0297       [coord, from_coord](InterestingQuantities const& iq) {
0298         return from_coord(coord->signed_module_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0299       },
0300       UNDEFINED,
0301       UNDEFINED,
0302       1.0 / 8.0);
0303   addExtractor(
0304       intern("SignedLadderCoord"),  // BPIX y
0305       [coord, from_coord](InterestingQuantities const& iq) {
0306         return from_coord(coord->signed_ladder_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0307       },
0308       UNDEFINED,
0309       UNDEFINED,
0310       1.0 / 2.0);
0311   addExtractor(
0312       intern("SignedDiskCoord"),  // FPIX x (per-ring)
0313       [coord, from_coord](InterestingQuantities const& iq) {
0314         return from_coord(coord->signed_disk_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0315       },
0316       UNDEFINED,
0317       UNDEFINED,
0318       1.0 / 8.0);
0319   addExtractor(
0320       intern("SignedDiskRingCoord"),  // FPIX x (FPIX-as-one-plot)
0321       [coord, from_coord](InterestingQuantities const& iq) {
0322         return from_coord(coord->signed_disk_ring_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0323       },
0324       UNDEFINED,
0325       UNDEFINED,
0326       1.0 / 16.0);
0327   addExtractor(
0328       intern("SignedBladePanelCoord"),  // FPIX y
0329       [coord, from_coord, phase](InterestingQuantities const& iq) {
0330         if (phase == 0) {
0331           return from_coord(coord->signed_blade_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0332         } else if (phase == 1) {
0333           return from_coord(
0334               coord->signed_blade_panel_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0335         } else {
0336           return UNDEFINED;  // TODO: phase2
0337         }
0338       },
0339       UNDEFINED,
0340       UNDEFINED,
0341       phase == 1 ? 0.25 : 0.2);
0342   addExtractor(
0343       intern("SignedShiftedBladePanelCoord"),  // FPIX-as-one y
0344       [coord, from_coord, phase](InterestingQuantities const& iq) {
0345         if (phase == 0) {
0346           return from_coord(coord->signed_blade_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0347         } else if (phase == 1) {
0348           return from_coord(
0349               coord->signed_shifted_blade_panel_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0350         } else {
0351           return UNDEFINED;  // TODO: phase2
0352         }
0353       },
0354       UNDEFINED,
0355       UNDEFINED,
0356       phase == 1 ? 0.25 : 0.1  // half-roc for phase0
0357   );
0358   addExtractor(
0359       intern("SignedBladePanel"),  // per-module FPIX y
0360       [coord, from_coord](InterestingQuantities const& iq) {
0361         return from_coord(coord->signed_blade_panel_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0362       },
0363       UNDEFINED,
0364       UNDEFINED,
0365       1.0 / 2.0);
0366 
0367   addExtractor(
0368       intern("SignedBladePanel"),
0369       [coord, from_coord](InterestingQuantities const& iq) {
0370         return from_coord(coord->signed_blade_panel_coord(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0371       },
0372       UNDEFINED,
0373       UNDEFINED,
0374       1.0 / 2.0);
0375 
0376   // more readout-related things.
0377   addExtractor(intern("ROC"), [coord, from_coord](InterestingQuantities const& iq) {
0378     return from_coord(coord->roc(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0379   });
0380   addExtractor(intern("Sector"), [coord, from_coord](InterestingQuantities const& iq) {
0381     return from_coord(coord->sector(iq.sourceModule()));
0382   });
0383   addExtractor(intern("Channel"), [coord, from_coord](InterestingQuantities const& iq) {
0384     return from_coord(coord->channel(iq.sourceModule(), std::make_pair(int(iq.row), int(iq.col))));
0385   });
0386 }
0387 
0388 void GeometryInterface::loadTimebased(const edm::ParameterSet& iConfig) {
0389   // extractors for quantities that are roughly time-based. We cannot book plots based on these; they have to
0390   // be grouped away in step1.
0391   addExtractor(
0392       intern("Lumisection"),
0393       [](InterestingQuantities const& iq) {
0394         if (!iq.sourceEvent)
0395           return UNDEFINED;
0396         return Value(iq.sourceEvent->luminosityBlock());
0397       },
0398       1,
0399       iConfig.getParameter<int>("max_lumisection"));
0400 
0401   int onlineblock = iConfig.getParameter<int>("onlineblock");
0402   int n_onlineblocks = iConfig.getParameter<int>("n_onlineblocks");
0403   addExtractor(
0404       intern("OnlineBlock"),
0405       [onlineblock](InterestingQuantities const& iq) {
0406         if (!iq.sourceEvent)
0407           return UNDEFINED;
0408         return Value(onlineblock + iq.sourceEvent->luminosityBlock() / onlineblock);
0409       },
0410       // note: this range is not visible anywhere (if the RenderPlugin does its job),
0411       // but the strange range allows the RenderPlugin to know the block size.
0412       onlineblock,
0413       onlineblock + n_onlineblocks - 1);
0414 
0415   int lumiblock = iConfig.getParameter<int>("lumiblock");
0416   addExtractor(
0417       intern("LumiBlock"),
0418       [lumiblock](InterestingQuantities const& iq) {
0419         if (!iq.sourceEvent)
0420           return UNDEFINED;
0421         // The '-1' is for making 1-10 the same block rather than 0-9
0422         // The '+0.5' makes the block span an integer range rather n.5-m.5
0423         return Value(((iq.sourceEvent->luminosityBlock() - 1) / lumiblock) + 0.5);
0424       },
0425       -0.5,
0426       iConfig.getParameter<int>("max_lumisection") / lumiblock);
0427 
0428   addExtractor(
0429       intern("BX"),
0430       [](InterestingQuantities const& iq) {
0431         if (!iq.sourceEvent)
0432           return UNDEFINED;
0433         return Value(iq.sourceEvent->bunchCrossing());
0434       },
0435       1,
0436       iConfig.getParameter<int>("max_bunchcrossing"));
0437 }
0438 
0439 void GeometryInterface::loadModuleLevel(const edm::ParameterSet& iConfig) {
0440   // stuff that is within modules. Might require some phase0/phase1/strip switching later
0441   addExtractor(
0442       intern("row"),
0443       [](InterestingQuantities const& iq) { return Value(iq.row); },
0444       0,
0445       iConfig.getParameter<int>("module_rows") - 1);
0446   addExtractor(
0447       intern("col"),
0448       [](InterestingQuantities const& iq) { return Value(iq.col); },
0449       0,
0450       iConfig.getParameter<int>("module_cols") - 1);
0451 }
0452 
0453 void GeometryInterface::loadFEDCabling(const SiPixelFedCablingMap* labeledSiPixelFedCablingMap) {
0454   std::shared_ptr<SiPixelFrameReverter> siPixelFrameReverter =
0455       // I think passing the bare pointer here is safe, but who knows...
0456       std::make_shared<SiPixelFrameReverter>(labeledSiPixelFedCablingMap);
0457 
0458   addExtractor(intern("FED"), [siPixelFrameReverter](InterestingQuantities const& iq) {
0459     if (iq.sourceModule == 0xFFFFFFFF)
0460       return Value(iq.col);  // hijacked for the raw data plugin
0461     return Value(siPixelFrameReverter->findFedId(iq.sourceModule.rawId()));
0462   });
0463 
0464   // TODO: ranges should be set manually below, since booking probably cannot
0465   // infer them correctly (no ROC-level granularity)
0466   // PERF: this is slow. Prefer SiPixelCordinates versions here.
0467   addExtractor(intern("LinkInFed"), [siPixelFrameReverter](InterestingQuantities const& iq) {
0468     if (iq.sourceModule == 0xFFFFFFFF)
0469       return Value(iq.row);  // hijacked for the raw data plugin
0470     sipixelobjects::GlobalPixel gp = {iq.row, iq.col};
0471     return Value(siPixelFrameReverter->findLinkInFed(iq.sourceModule.rawId(), gp));
0472   });
0473   // not sure if this is useful anywhere.
0474   addExtractor(intern("RocInLink"), [siPixelFrameReverter](InterestingQuantities const& iq) {
0475     sipixelobjects::GlobalPixel gp = {iq.row, iq.col};
0476     return Value(siPixelFrameReverter->findRocInLink(iq.sourceModule.rawId(), gp));
0477   });
0478   // This might be equivalent to our ROC numbering.
0479   addExtractor(intern("RocInDet"), [siPixelFrameReverter](InterestingQuantities const& iq) {
0480     sipixelobjects::GlobalPixel gp = {iq.row, iq.col};
0481     return Value(siPixelFrameReverter->findRocInDet(iq.sourceModule.rawId(), gp));
0482   });
0483 }
0484 
0485 std::string GeometryInterface::formatValue(Column col, Value val) {
0486   auto it = format_value.find(std::make_pair(col, val));
0487   if (it != format_value.end())
0488     return it->second;
0489 
0490   // non-number output names (_pO etc.) are hardwired here.
0491   std::string name = pretty(col);
0492   std::string value = "_" + std::to_string(int(val));
0493   if (val == 0)
0494     value = "";                     // hide Barrel_0 etc.
0495   if (name == "PXDisk" && val > 0)  // +/- sign for disk num
0496     value = "_+" + std::to_string(int(val));
0497   // pretty (legacy?) names for Shells and HalfCylinders
0498   std::map<int, std::string> shellname{{11, "_mI"}, {12, "_mO"}, {21, "_pI"}, {22, "_pO"}};
0499   if (name == "HalfCylinder" || name == "Shell")
0500     value = shellname[int(val)];
0501   if (val == UNDEFINED)
0502     value = "_UNDEFINED";
0503   return format_value[std::make_pair(col, val)] = name + value;
0504 }