Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:14:12

0001 #ifndef tuClass__h
0002 
0003 #ifndef noiPads__h
0004 #define noiPads__h
0005 
0006 #include "noiDict.h"
0007 #include "noi_fnc.h"
0008    const int kLeft  = 2;
0009    const int kRight = 3;
0010 // David Stewart, Dec 1 2022
0011 // Stripped down version of tuPads
0012 // used in conveinece for plotting
0013 struct noiPadDim {
0014     // a structure to contain the four coordinates requisite for a TPad (in x or y):
0015     //    low   : left/bottom edge of TPad (outer edge of margin)
0016     //    p_low : left/bottom edge of the plot area
0017     //    p_up  : right/top edge of the plot area
0018     //    up    : right/top edge of TPad
0019     //
0020     //    If initialized with only two arguments (low, up), then set p_low to low and p_up to up
0021     //    If initialized with three arguments (low, plow, up) set p_up to up
0022     double low;
0023     double p_low;
0024     double p_up;
0025     double up;
0026 
0027     void check_input() {
0028         if (   low   < 0. || low   > 1. 
0029                 || p_low < 0. || p_low > 1. 
0030                 || p_up  < 0. || p_up  > 1. 
0031                 || up    < 0. || up    > 1. ) {
0032             cout << " Fatal error: input coordinates for tuPadDim for pads must all "
0033                 " be in range [0,1] " << endl;
0034             print();
0035             exit (2);
0036         } else if ( low > p_low || p_low > p_up || p_up > up ) {
0037             cout << " Fatal error: input coordinates must monotonically increase " << endl;
0038             print();
0039             exit(2);
0040         }
0041     };
0042     noiPadDim( double _low, double _p_low, double _p_up, double _up ) :
0043         low{_low}, p_low{_p_low}, p_up{_p_up}, up{_up} { check_input(); };
0044     noiPadDim( double _low, double _up ) : 
0045         low{_low}, p_low{_low}, p_up{_up}, up{_up} { check_input(); };
0046     noiPadDim( double _low, double _p_low, double _up ) : 
0047         low{_low}, p_low{_p_low}, p_up{_up}, up{_up} { check_input(); };
0048     noiPadDim( ) :
0049         low{0.}, p_low{0.}, p_up{1.}, up{1.} { check_input(); };
0050 
0051     void print() const {
0052         cout << Form(" Four points are: (%.2f, %.2f %.2f, %.2f)",low,p_low,p_up,up) << endl;
0053     };
0054     double low_margin () const {
0055         double margin { (p_low - low) / (up - low) };
0056         if (margin < 0) margin = 0;
0057         return margin;
0058     };
0059     double up_margin () const {
0060         // use to get set the lower margin
0061         double margin { (up - p_up) / (up - low) };
0062         if (margin < 0) margin = 0;
0063         return margin;
0064     };
0065     bool operator==(noiPadDim& B) const {
0066         return low == B.low
0067             && p_low == B.p_low
0068             && p_up  == B.p_up
0069             && up    == B.up;
0070     };
0071 };
0072 struct noiPadDimSet {
0073     /* noiPadDimSet(int _nPads, // make negative is wish to flip directtuns */
0074             /* vector<double> _lefts={}, */ 
0075             /* vector<double> _rights={}); */
0076     vector<double> lefts;
0077     vector<double> rights;
0078     int            nPads;
0079 
0080     static noiPadDim make_pad(double left, 
0081                 double left_margin, double pad_width, 
0082                 double right_margin) 
0083     {
0084         return noiPadDim{ left, 
0085                          left+left_margin,
0086                          left+left_margin+pad_width,
0087                          left+left_margin+pad_width+right_margin };
0088     };
0089 
0090     vector<noiPadDim> calc_pads() {
0091         int npads = nPads;
0092         bool flip_direction = false;
0093         if (npads < 0) { 
0094             npads = -npads; 
0095             flip_direction=true;
0096         };
0097         vector<noiPadDim> pads (npads) ;
0098 
0099         double first_left = (lefts.size() > 0) ? lefts[0] : 0.2;
0100         double inner_left = (lefts.size() > 1) ? lefts[1] : 0.0001;
0101         double page_left  = (lefts.size() > 2) ? lefts[2] : 0.01;
0102 
0103         double last_right  = (rights.size() > 0) ? rights[0] : 0.0001;
0104         double inner_right = (rights.size() > 1) ? rights[1] : 0.0;
0105         double page_right  = (rights.size() > 2) ? rights[2] : 0.01;
0106 
0107         if (npads == 0) throw std::runtime_error(
0108             "fatal in noiPadDimSet must request at least one pad");
0109         if (npads == 1) {
0110             double pad_width = 1.-first_left-page_left-last_right-page_right;
0111             if (pad_width<=0) throw std::runtime_error(
0112                     "fatal in noiPadDimSet margins have consumed more than 100\% of TCanvas");
0113             pads[0] = make_pad( page_left, first_left, pad_width, last_right );
0114             return pads;
0115         } 
0116 
0117         double pad_width { (1.-(first_left+page_left+last_right+page_right+
0118                 (inner_left+inner_right)*(npads-1)))/npads };
0119         if (pad_width<=0) throw std::runtime_error(
0120                 "fatal in noiPadDimSet margins have consumed more than 100\% of TCanvas");
0121 
0122         int index = flip_direction ? npads-1 : 0;
0123         pads[index] = make_pad(page_left, first_left, pad_width, inner_right);
0124         double left = pads[index].up;
0125 
0126         for (int i=1;i<npads-1;++i) {
0127             int index = flip_direction ? npads-i-1 : i;
0128             pads[index] = make_pad(left, inner_left, pad_width, inner_right);
0129             left = pads[index].up;
0130         }
0131         pads[flip_direction ? 0 : npads-1] = make_pad(left, inner_left, pad_width, last_right);
0132         return pads;
0133     };
0134 
0135 
0136     noiPadDimSet(vector<double> _lefts, vector<double> _rights ) :
0137               rights{_rights} 
0138     {
0139         if (_lefts.size() == 0) nPads = 1;
0140         else if (_lefts[0] >= 1.) {
0141             nPads = (int) _lefts[0];
0142             for (int i{0}; i<(int)_lefts.size()-1; ++i) lefts.push_back(_lefts[i+1]);
0143         } else {
0144             nPads = 1;
0145             lefts = _lefts;
0146         }
0147     };
0148     /* operator vector<noiPadDim> (); */
0149 };
0150 
0151 struct noiPads {
0152     // data
0153     string prefix="";
0154     int i_prefix=1;
0155     TCanvas* canvas = nullptr;
0156     vector<pair<noiPadDim,noiPadDim>> pad_dimensions;
0157     vector<TPad*> pads; // all the generated smaller pads
0158     TPad* canvas_pad;   // a single big pad the size of the canvas
0159     int nRow{1};
0160     int nCol{1};
0161     int canvas_width         { 1200 };
0162     int canvas_height        {  800 };
0163     
0164     noiPads ( int nYpads=1, vector<double> dimensions={}, int nXpads=1 ) {
0165         // build the noiPadDimSet out of dimensions
0166         noiPadDimSet xPads{ {0.2, 0.0001, 0.01}, {0.0001,0.0,0.01 }};
0167         noiPadDimSet yPads{ {0.2, 0.0001, 0.01}, {0.0001,0.0,0.01 }};
0168 
0169         int which = 0;
0170         int cnt   = 0;
0171         canvas_width  = -1;
0172         canvas_height = -1;
0173         for (auto val : dimensions) {
0174             if (val > 6) { // set first dimensions
0175                 if (canvas_width == -1) canvas_width  = val;
0176                 else                    canvas_height = val;
0177                 continue;
0178             } else if (val > 1) { 
0179                 which = (int) val;
0180                 cnt = 0;
0181                 continue;
0182             } else if (which == 0) {
0183                 which = kLeft;
0184             }
0185             switch (which) {
0186                 case 6:  // kTop
0187                     yPads.rights[cnt] = val;
0188                     break;
0189                 case 5: // kBottom
0190                     yPads.lefts[cnt] = val;
0191                     break;
0192                 case kLeft:
0193                     xPads.lefts[cnt] = val;
0194                     break;
0195                 case kRight:
0196                     xPads.rights[cnt] = val;
0197                     break;
0198                 default:
0199                     throw std::runtime_error(Form("fatal error: noiPads::noiPads: Error in selection of pad dimensions: was %i but must be (2,3,5,6:kLeft,Right,Bottom,Top)",
0200                                 which));
0201             }
0202             ++cnt;
0203         }
0204         yPads.nPads = -nYpads;
0205         xPads.nPads =  nXpads;
0206         if (canvas_width  == -1) canvas_width = 1200;
0207         if (canvas_height == -1) canvas_height =  800;
0208         nCol = TMath::Abs(nXpads);
0209         nRow = TMath::Abs(nYpads);
0210         for (auto x_pad : xPads.calc_pads())
0211             for (auto y_pad : yPads.calc_pads())
0212                 pad_dimensions.push_back( {y_pad, x_pad} );
0213     };
0214 
0215                     
0216     noiPads ( vector<pair<noiPadDim, noiPadDim>> _pad_dimensions={{{},{}}}, int _canvas_width=0, int _canvas_height=0) :
0217         pad_dimensions{ _pad_dimensions }
0218     {
0219         if (_canvas_width)  canvas_width  = _canvas_width;
0220         if (_canvas_height) canvas_height = _canvas_height;
0221     };
0222 
0223     void add_pad(pair<noiPadDim,noiPadDim>& coord){
0224         canvas->cd();
0225 
0226         if (pads.size()==0) {
0227             canvas_pad = new TPad(noiUniqueName(i_prefix,prefix.c_str()),"",0.,0.,1.,1.);
0228             canvas_pad ->SetFillStyle(4000);
0229             canvas_pad ->SetFrameFillStyle(4000);
0230             
0231             canvas_pad->Draw();
0232             canvas->cd();
0233         }
0234 
0235         const noiPadDim x { coord.second };
0236         const noiPadDim y { coord.first  };
0237         int i{0};
0238         /* while (gDirectory->FindObjectAny(Form("loc_pad_%i",i))) { ++i; } */
0239         TPad* p = new TPad(noiUniqueName(),"",x.low,y.low,x.up,y.up);
0240 
0241         // set the boundaries left(l), right(r), top(t), bottom(b)
0242         p->SetLeftMargin(x.low_margin());
0243         p->SetRightMargin(x.up_margin());
0244         p->SetBottomMargin(y.low_margin());
0245         p->SetTopMargin(y.up_margin());
0246 
0247         p->SetFillStyle(4000);
0248         p->SetFrameFillStyle(4000);
0249         p->Draw();
0250         pads.push_back(p);
0251     };
0252 
0253     void add_pad(vector<pair<noiPadDim,noiPadDim>> input) {
0254         for (auto& inp : input) add_pad(inp);
0255     };
0256 
0257     void init() {
0258         // make and stylize the TCanvas and pads currently in the list
0259         /* const char* t_name = Form("canv_%s",noiUniqueName()); */
0260         canvas = new TCanvas(noiUniqueName(i_prefix,Form("canv_%s",prefix.c_str())), "",canvas_width, canvas_height);
0261         canvas->SetFillStyle(4000);
0262         canvas->SetFrameFillStyle(4000);
0263         canvas->Draw();
0264         canvas->cd();
0265 
0266         // add all pads
0267         add_pad(pad_dimensions);
0268 
0269         canvas->cd();
0270     };
0271 
0272     TPad* operator()(int row=0, int col=0) {
0273         if (pads.size() == 0) init();
0274         if (row < 0) {
0275             row = -row;
0276             col = row % nCol;
0277             row = row / nCol;
0278         }
0279         int i_pad = row+col*nRow;
0280         if (i_pad >= (int)pads.size()) {
0281             i_pad = i_pad % (int) pads.size();
0282         }
0283         pads[i_pad]->cd();
0284         return pads[i_pad];
0285     };
0286 
0287     void stamp(string msg, noiDict opt={}, noiDict dict = {{ 
0288         "TextColor", (kGray+2), 
0289         "TextSize", 16,
0290         "x-loc", .05,
0291         "y-loc", .05}} ) 
0292     {
0293         dict += opt;
0294         if (msg.size() > 120) {
0295             cout << "pads stamp msg size: " << msg.size() << endl;
0296             noiDict dsize {{ "TextSize", 10 }};
0297             dict += dsize;
0298         }
0299         canvas_pad->cd();
0300         /* cout << " x: " << dict["x-loc"] << "  " << dict["y-loc"] << endl; */
0301         noiDrawTLatex(msg.c_str(),dict("x-loc"), dict("y-loc"), dict);
0302     };
0303     // save the output; check for *cc or *C ending and save as .pdf if required
0304     
0305     void pdf(string string_with_dollar0, vector<string> other={}) {
0306         string name = gSystem->pwd();
0307         name += "/";
0308         istringstream iss;
0309         iss.str(string_with_dollar0);
0310         string word;
0311         while (iss >> word) {
0312             name += noiStripEnds( noiStripStart(word, "./"), {".C",".cc",".cxx",".pdf"});
0313         }
0314         for (auto& words : other) {
0315             iss.clear();
0316             iss.str(words);
0317             while (iss >> word)  {
0318                 name += noiStripEnds( noiStripStart(word, "./"), {".C",".cc",".cxx",".pdf"});
0319             }
0320         }
0321         name += ".pdf";
0322         canvas->Print(name.c_str());
0323     };
0324 };
0325 
0326 
0327 #endif
0328 
0329 #endif