Beispiel #1
0
bool                              // returns true if success
processGraphSection(FILE *fp,
		    string& theline,
		    bool& new_section)
{
  vector<string> v_tokens;
  TString  title;
  string   *gid  = NULL;
  TVectorD vx,vy,vz,exl,exh,eyl,eyh;
  float xoffset=0.0,yoffset=0.0, yscale=1.0;
  float xmin=0.,xmax=0.,ymin=0.,ymax=0.,zmin=0.,zmax=0.;
  bool asymerrors = false;
  bool printvecs  = false;
  wGraph_t wg;                                    // placeholder for read-in values
  vector<std::pair<string, wGraph_t *> > v_graphs;

  char xheader[80],yheader[80];
  xheader[0]=0;
  yheader[0]=0;

  if (gl_verbose) cout << "Processing graph section" << endl;

  new_section=false;

  while (getLine(fp,theline,"graph")) {
    if (!theline.size()) continue;
    if (theline[0] == '#') continue; // comments are welcome

    if (theline[0] == '[') {
      new_section=true;
      break;
    }

    string key, value;
    if (!getKeyValue(theline,key,value)) continue;

    //--------------------
    if (key == "id") {
    //--------------------
      if (gid != NULL) {
	cerr << "no more than one id per graph section allowed " << value << endl;
	break;
      }

      gid = new string(value);

    //------------------------------
    } else if (key == "vectorfile") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      string path     = value;
      string scanspec = asymerrors ?  "%lf %lf %lf %lf" : "%lf %lf";

      Tokenize(value,v_tokens,",");
      if (v_tokens.size() > 1) {
	path     = v_tokens[0];
	scanspec = v_tokens[1];
      }

      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wGraph_t *pwg = new wGraph_t();

      if (asymerrors)
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,exl,exh,eyl,eyh);
      else
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,xheader,yheader);

      if (strlen(xheader)) pwg->xax->SetTitle(xheader);
      if (strlen(yheader)) pwg->yax->SetTitle(yheader);

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

      // pend filling the graph until all parameters are read in

    //------------------------------
    } else if (key == "vectorfile2d") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }

      Tokenize(value,v_tokens,",");

      string path=v_tokens[0];
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wGraph_t *pwg = new wGraph_t();

      switch(v_tokens.size()) {
      case 1:  pwg->gr2d = new TGraph2D(path.c_str()); break;
      case 2:  pwg->gr2d = new TGraph2D(path.c_str(),v_tokens[1].c_str()); break;
      case 3:  pwg->gr2d = new TGraph2D(path.c_str(),v_tokens[1].c_str(),v_tokens[2].c_str()); break;
      default:
	cerr << "malformed vectorfile2d spec path[,format[,option]] " << value << endl;
	break;
      }

      if (pwg->gr2d->IsZombie()) {
	cerr << "Unable to make Graph2D from file " << path << endl;
	exit(-1);
      }
      pwg->gr2d->SetName(gid->c_str());

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

    //------------------------------
    } else if (key == "path") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph already defined" << endl; continue;
      }
      wGraph_t *pwg = new wGraph_t();
      pwg->gr  = getGraphFromSpec(*gid,value);
      if (!pwg->gr) continue;

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

    //------------------------------
    } else if (key == "clone") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph already defined" << endl; continue;
      }
      map<string,wGraph_t *>::const_iterator it = glmap_id2graph.find(value);
      if( it == glmap_id2graph.end() ) {
	cerr << "Graph ID " << value << " not found,";
	cerr << "clone must be defined after the clonee" << endl;
	break;
      }
      wGraph_t *pwg  = new wGraph_t(*(it->second),*gid);

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

    //------------------------------
    } else if( key == "fromhisto" ) { // converts TH1 to TGraph
    //------------------------------
      if( !gid ) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }
      // look for multihist with this identifier
      std::map<string,unsigned>::const_iterator it=glmap_mhid2size.find(value);
      if (it!=glmap_mhid2size.end()) {
	for (size_t i=0; i<it->second; i++) {
	  string hidi=value+int2str(i);
	  TH1 *h = (TH1 *)findHisto(hidi,"");
	  assert(h);
	  wGraph_t *pwg = new wGraph_t();
	  pwg->gr = new TGraph(h);
	  v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));
	}
      } else {
	TH1 *h = (TH1 *)findHisto(value);
	assert(h);
	wGraph_t *pwg = new wGraph_t();
	pwg->gr = new TGraph(h);
	v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));
      }

    //------------------------------
    } else if( key == "fillfromtree" ) { // converts tree array variables into a group of graphs
    //------------------------------
      if( !gid ) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }

      Tokenize(value,v_tokens,";");
      string treedrawspec=v_tokens[0];

      int ifirst=-1,ilast=-1;
      if (v_tokens.size() == 2) {
	string range=v_tokens[1];
	Tokenize(range,v_tokens,"-");
	if (v_tokens.size()==2) {
	  ifirst=str2int(v_tokens[0]);
	  ilast =str2int(v_tokens[1]);
	}
      }
      //cout << v_tokens.size() << " " << ifirst << " " << ilast << endl;
      if (ifirst>0 && 
	  ilast>=ifirst ) {
	for (int i=ifirst; i<=ilast; i++) {
	  wGraph_t *pwg = NULL;

	  // defined in spTree.C
	  void fillGraphFromTreeVar(std::string& drawspec,int index,wGraph_t *&pwg);
	  fillGraphFromTreeVar(treedrawspec,i,pwg);
	  assert(pwg);
	  string gidi= (*gid)+"_"+int2str(i-ifirst);
	  v_graphs.push_back(std::pair<string,wGraph_t *>(gidi,pwg));
	}

	glmap_mgid2size.insert(pair<string,unsigned>(*gid,v_graphs.size()));
      } else {
	wGraph_t *pwg = NULL;
	void fillGraphFromTreeVar(std::string& drawspec,int index,wGraph_t *&pwg);
	fillGraphFromTreeVar(treedrawspec,0,pwg);
	assert(pwg);
	v_graphs.push_back(std::pair<string,wGraph_t *>(*gid,pwg));
	glmap_mgid2size.insert(pair<string,unsigned>(*gid,v_graphs.size()));
      }

    //------------------------------
    } else if (key == "bayesdiv") {
    //------------------------------

      Tokenize(value,v_tokens,",/"); // either comma-separated or using '/'
      if (v_tokens.size() != 2) {
	cerr << "expect comma-separated list of exactly two histo specs to divide! ";
	cerr << theline << endl;
	continue;
      }

      TH1 *tmph1 = (TH1 *)findHisto(v_tokens[0]); if (!tmph1) exit(-1);
      TH1 *tmph2 = (TH1 *)findHisto(v_tokens[1]); if (!tmph2) exit(-1);

      cout << tmph1->GetNbinsX() << " " << tmph2->GetNbinsX() << endl;

      wGraph_t *pwg = new wGraph_t();

      if ( gl_verbose ) { 
	std::cout << "Dump of bin contents, errors" << std::endl ; 
	if ( tmph1->GetNbinsX() == tmph2->GetNbinsX() ) { 
	  for (int ib=1; ib<=tmph1->GetNbinsX(); ib++) {
	    std::cout << ib << ": " << tmph1->GetBinContent(ib) << "+/-" << tmph1->GetBinError(ib) 
		      << ", " << tmph2->GetBinContent(ib) << "+/-" << tmph2->GetBinError(ib) << std::endl ; 
	  }
	} else { 
	  cerr << "Histograms being divided do not have same number of bins!!!" << endl ; 
	}
      }

      // equivalent to BayesDivide
      //
      if (gl_verbose) pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"debug");
      else            pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"");
      //if (gl_verbose) pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode v");
      //else            pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode");
      if (!pwg->gr) {
	cerr << "BayesDivide didn't work! wonder why..." << endl;
	continue;
      } else if (gl_verbose) {
	cout << pwg->gr->GetN() << " points in the graph" << endl;
      }

      // Fix in case something broke

      for (int i=0; i<pwg->gr->GetN(); i++) {
          if ( pwg->gr->GetErrorYhigh(i) == 0. || pwg->gr->GetErrorYlow(i) == 0 ) { // Something bad happened
              if ( gl_verbose ) std::cout << "Problem with Bayes divide, checking..." << std::endl ;
              double pass  = tmph1->GetBinContent(i+1) ; 
              double total = tmph2->GetBinContent(i+1) ;
              if ( gl_verbose ) std::cout << pass << "/" << total << std::endl ;
              if ( pass == total ) {
                  if ( gl_verbose ) std::cout << "Everything OK" << std::endl ;
              } else { 
                  if ( gl_verbose ) std::cout << "Yep, something is broken" << std::endl ;
                  double xval, yval ;
                  pwg->gr->GetPoint(i,xval,yval) ;
                  yval = pass / total ;
                  // Use simplified efficiency assumption
                  // double u1 = tmph1->GetBinError(i+1) / tmph1->GetBinContent(i+1) ; 
                  // double u2 = tmph2->GetBinError(i+1) / tmph2->GetBinContent(i+1) ; 
                  // double unc = yval * sqrt( u1*u1 + u2*u2 ) ; 
                  double unc = sqrt( yval * (1.-yval)/tmph2->GetBinContent(i+1) ) ; 
                  double uhi = ( (yval + unc > 1.)?(1.-yval):(unc) ) ; 
                  double ulo = ( (yval - unc < 0.)?(yval):(unc) ) ;
                  pwg->gr->SetPoint(i,xval,yval) ;
                  ((TGraphAsymmErrors*)pwg->gr)->SetPointError(i,pwg->gr->GetErrorXlow(i),pwg->gr->GetErrorXhigh(i),ulo,uhi) ; 
//                   pwg->gr->SetPointEYhigh(i,uhi) ; 
//                   pwg->gr->SetPointEYlow(i,ulo) ; 
              }
          }   
          if (gl_verbose) std::cout << i << ": " << pwg->gr->GetErrorYhigh(i) << "/" << pwg->gr->GetErrorYlow(i) << std::endl ; 
      }

    } else if (!v_graphs.size()) {
      cerr<<"One of keys path,clone,vectorfile,vectorfile2d or bayesdiv must be defined before key..."<<key<<endl;
    } else {
      if     ( key == "xoffset" )      xoffset   = str2flt(value);
      else if( key == "yoffset" )      yoffset   = str2flt(value);
      else if( key == "yscale" )       yscale    = str2flt(value);
      else if( key == "title"  )       title     = TString(value);
      else if( key == "xtitle" )       wg.xax->SetTitle      (TString(value));
      else if( key == "ytitle" )       wg.yax->SetTitle      (TString(value));
      else if( key == "ztitle" )       wg.zax->SetTitle      (TString(value));
      else if( key == "xtitleoffset" ) wg.xax->SetTitleOffset(str2flt(value));
      else if( key == "ytitleoffset" ) wg.yax->SetTitleOffset(str2flt(value));
      else if( key == "ztitleoffset" ) wg.zax->SetTitleOffset(str2flt(value));
      else if( key == "xndiv" )        wg.xax->SetNdivisions (str2int(value));
      else if( key == "yndiv" )        wg.yax->SetNdivisions (str2int(value));
      else if( key == "zndiv" )        wg.zax->SetNdivisions (str2int(value));
      else if( key == "xmin" )         xmin         = str2flt(value);
      else if( key == "xmax" )         xmax         = str2flt(value);
      else if( key == "ymin" )         ymin         = str2flt(value);
      else if( key == "ymax" )         ymax         = str2flt(value);
      else if( key == "zmin" )         zmin         = str2flt(value);
      else if( key == "zmax" )         zmax         = str2flt(value);
      else if( key == "linecolor" )    wg.lcolor    = str2int(value);
      else if( key == "linestyle" )    wg.lstyle    = str2int(value);
      else if( key == "linewidth" )    wg.lwidth    = str2int(value);
      else if( key == "markercolor" )  wg.mcolor    = str2int(value);
      else if( key == "markerstyle" )  wg.mstyle    = str2int(value);
      else if( key == "markersize"  )  wg.msize     = str2int(value);
      else if( key == "fillcolor" )    wg.fcolor    = str2int(value);
      else if( key == "fillstyle" )    wg.fstyle    = str2int(value);
      else if( key == "asymerrors" )   asymerrors   = (bool)str2int(value);
      else if( key == "leglabel" )     wg.leglabel  = value;
      else if( key == "draw" )         wg.drawopt   = value;
      else if( key == "legdraw" )      wg.legdrawopt= value;
      else if( key == "setprecision" ) cout << setprecision(str2int(value));
      else if( key == "printvecs2file") printvecs = true;
      else if( key == "fittf1" ) {
	TF1 *tf1 = findTF1(value);
	if( !tf1 ) {
	  cerr << "TF1 " << value << " must be defined first" << endl;
	  continue;
	}
	string funcnewname = value+(*gid);
	wg.fitfn = new TF1(*tf1);
	wg.fitfn->SetName(funcnewname.c_str());
      }
      else if ( key == "contours" ) {
	Tokenize(value,v_tokens,",");
	wg.contours = new TVectorD(v_tokens.size());
	for (size_t i=0; i<v_tokens.size(); i++)
	  wg.contours[i] = str2flt(v_tokens[i]);
      }
      else {
	cerr << "unknown key " << key << endl;
      }
#if 0
      processCommonHistoParams(key,value,*wh);
#endif
    }
  } // getline loop

  //cout << title << endl;

  for (size_t i=0; i<v_graphs.size(); i++) {
    string gidi = v_graphs[i].first;
    wGraph_t *pwg = v_graphs[i].second;
    if (pwg->gr2d) {
      pwg->gr2d->SetTitle(title);
      pwg->gr2d->SetLineStyle   (wg.lstyle);
      pwg->gr2d->SetLineColor   (wg.lcolor);
      pwg->gr2d->SetLineWidth   (wg.lwidth);
      pwg->gr2d->SetMarkerColor (wg.mcolor);
      pwg->gr2d->SetMarkerStyle (wg.mstyle);
      pwg->gr2d->SetMarkerSize  (wg.msize);
      pwg->gr2d->SetFillStyle   (wg.fstyle);
      pwg->gr2d->SetFillColor   (wg.fcolor);
      if (zmax>zmin)  
	pwg->zax->SetLimits(zmin,zmax);
    } else {
      if (vx.GetNoElements()) { // load utility guarantees the same size for both
	if (yscale  != 1.0) vy *= yscale;
	if (xoffset != 0.0) vx += xoffset;
	if (yoffset != 0.0) vy += yoffset;
	if (asymerrors) 
	  pwg->gr = new TGraphAsymmErrors(vx,vy,exl,exh,eyl,eyh);
	else
	  pwg->gr = new TGraph(vx,vy);
      }
      pwg->gr->UseCurrentStyle();
      pwg->fitfn      =        wg.fitfn;
      pwg->contours   =        wg.contours;
      pwg->drawopt    =        wg.drawopt;
      pwg->legdrawopt =        wg.legdrawopt;
      pwg->gr->SetTitle       (title);
      pwg->xax->SetTitle      (wg.xax->GetTitle());
      pwg->yax->SetTitle      (wg.yax->GetTitle());
      pwg->zax->SetTitle      (wg.zax->GetTitle());
      pwg->xax->SetTitleOffset(wg.xax->GetTitleOffset());
      pwg->yax->SetTitleOffset(wg.yax->GetTitleOffset());
      pwg->zax->SetTitleOffset(wg.zax->GetTitleOffset());
      pwg->xax->SetNdivisions (wg.xax->GetNdivisions());
      pwg->yax->SetNdivisions (wg.yax->GetNdivisions());
      pwg->zax->SetNdivisions (wg.zax->GetNdivisions());
      pwg->gr->SetLineStyle   (wg.lstyle);
      pwg->gr->SetLineColor   (wg.lcolor);
      pwg->gr->SetLineWidth   (wg.lwidth);
      pwg->gr->SetMarkerColor (wg.mcolor);
      pwg->gr->SetMarkerStyle (wg.mstyle);
      pwg->gr->SetMarkerSize  (wg.msize);
      pwg->gr->SetFillStyle   (wg.fstyle);
      pwg->gr->SetFillColor   (wg.fcolor);

      if (xmax>xmin) pwg->xax->SetLimits(xmin,xmax);
      if (ymax>ymin) pwg->yax->SetLimits(ymin,ymax);

      glmap_id2graph.insert(pair<string,wGraph_t *>(gidi,pwg));

      if (printvecs) printVectorsToFile(pwg); // ,value);
    }
  }

  return (v_graphs.size());
}                                                 // processGraphSection
Beispiel #2
0
bool                              // returns true if success
processMultiHistSection(FILE *fp,
			string& theline,
			bool& new_section)
{
  vector<string> v_tokens;
  vector<std::pair<string, wTH1 *> > v_histos;
  string mhid;

  if (gl_verbose)
    cout << "Processing multihist section" << endl;

  new_section=false;

  while (getLine(fp,theline,"multihist")) {
    if (!theline.size()) continue;
    if (theline[0] == '#') continue; // comments are welcome

    if (theline[0] == '[') {
      new_section=true;
      return true;
    }

    string key, value;
    if (!getKeyValue(theline,key,value)) continue;

    //--------------------
    if (key == "id") {
    //--------------------
      if (mhid.size()) {
	cerr << "no more than one id per histo section allowed " << value << endl;
	break;
      }

      mhid = value;

    //------------------------------
    } else if (key == "pathglob") {
    //------------------------------
      glob_t globbuf;
      
      if (!mhid.size()) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }

      Tokenize(value,v_tokens,":");
      if ((v_tokens.size() != 2) ||
	  (!v_tokens[0].size())  ||
	  (!v_tokens[1].size())    ) {
	cerr << "malformed pathglob 'fileglob:regex' " << value << endl;
	exit(-1);
      }

      // File globbing pattern can select multiple files
      // regular expression pattern can select multiple histos within each file.
      //
      string fileglob = v_tokens[0];
      string stregex  = v_tokens[1];

      int stat = glob (fileglob.c_str(), GLOB_MARK, NULL, &globbuf);
      if (stat) {
	switch (stat) {
	case GLOB_NOMATCH: cerr << "No file matching glob pattern "; break;
	case GLOB_NOSPACE: cerr << "glob ran out of memory "; break;
	case GLOB_ABORTED: cerr << "glob read error "; break;
	default: cerr << "unknown glob error stat=" << stat << " "; break;
	}
	cerr << fileglob << endl;
	exit(-1);
      }
      if (gl_verbose) cout<<globbuf.gl_pathc<<" files match the glob pattern"<<endl;
      for (size_t i=0; i<globbuf.gl_pathc; i++) {
	char *path = globbuf.gl_pathv[i];
	if (!strncmp(&path[strlen(path)-6],".root",5)) {
	  cerr << "non-root file found in glob, skipping: " << path << endl;
	} else {
	  getHistosFromRE(mhid,string(path),stregex, v_histos);
	}
      }
      if (gl_verbose) cout << v_histos.size() << " total matches found." << endl;
      globfree(&globbuf);

      glmap_mobj2size.insert(pair<string,unsigned>(mhid,v_histos.size()));

    //------------------------------
    } else if( key == "fillfromtree" ) { // converts tree array variables into a group of histos
    //------------------------------
      if( !mhid.size() ) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }

      // histo need not be pre-booked, since TTree::Draw can do that

      Tokenize(value,v_tokens,";");
      string treedrawspec=v_tokens[0];

      int ifirst=-1,ilast=-1;
      if (v_tokens.size() == 2) {
	string range=v_tokens[1];
	Tokenize(range,v_tokens,"-");
	if (v_tokens.size()==2) {
	  ifirst=str2int(v_tokens[0]);
	  ilast =str2int(v_tokens[1]);
	}
      }
      //cout << v_tokens.size() << " " << ifirst << " " << ilast << endl;
      if (ifirst<0 || 
	  ilast <0 ||
	  ilast<ifirst ) {
	cerr << "malformed filltree expression drawspec;X-Y, where X-Y is the array index range to plot"<<endl;
	exit(-1);
      }

      for (int i=ifirst; i<=ilast; i++) {
	wTH1   *wth1 = NULL;
	// defined in spTree.C
	void fillHistoFromTreeVar(std::string& drawspec,int index,wTH1 *&wth1);
	fillHistoFromTreeVar(treedrawspec,i,wth1);
	assert(wth1);
	string hidi= mhid+"_"+int2str(i-ifirst);
	v_histos.push_back(std::pair<string,wTH1 *>(hidi,wth1));
	glmap_id2histo.insert(pair<string,wTH1 *>(hidi,wth1));
      }

      glmap_mobj2size.insert(pair<string,unsigned>(mhid,v_histos.size()));

    //-----------------------
    } else if( key == "printf" ) {
    //-----------------------

      Tokenize(value,v_tokens,"\",");
      switch( v_tokens.size() ) {
      case 1: printf (v_tokens[0].c_str()); break;
      case 2: printf (v_tokens[0].c_str(),v_tokens[1].c_str()); break;
      case 3: printf (v_tokens[0].c_str(),
		      v_tokens[1].c_str(),
		      v_tokens[2].c_str()); break;
      case 4: printf (v_tokens[0].c_str(),
		      v_tokens[1].c_str(),
		      v_tokens[2].c_str(),
		      v_tokens[3].c_str()); break;
      default:
	cerr << "Unsupported number of arguments, " << value << endl;
	exit(-1);
      }

    } else if( !v_histos.size() ) {  // all other keys must have "path" defined
      cerr << "histo vector is empty" << endl;
      cerr << "key 'pathglob' or 'vartable' must define nonempty histo set before key " << key << endl;
      break;
    }

    else {
      processCommonHistoParams(key,value,v_histos);
      if( key == "printfstats" )   cout << endl;
    }
  }

  return (v_histos.size());
}                                             // processMultiHistSection
Beispiel #3
0
bool                              // returns true if success
processMultiGraphSection(FILE *fp,
			 string& theline,
			 bool& new_section)
{
  vector<string> v_tokens;
  TString  title;
  string   *gid  = NULL;
  TVectorD vx,vy,vz,exl,exh,eyl,eyh;
  float xoffset=0.0,yoffset=0.0, yscale=1.0;
  float xmin=0.,xmax=0.,ymin=0.,ymax=0.,zmin=0.,zmax=0.;
  bool asymerrors = false;
  wGraph_t *wg = NULL;

  char xheader[80],yheader[80];
  xheader[0]=0;
  yheader[0]=0;

  if (gl_verbose) cout << "Processing multigraph section" << endl;

  new_section=false;

  while (getLine(fp,theline,"multigraph")) {
    if (!theline.size()) continue;
    if (theline[0] == '#') continue; // comments are welcome

    if (theline[0] == '[') {
      new_section=true;
      break;
    }

    string key, value;
    if (!getKeyValue(theline,key,value)) continue;

    //--------------------
    if (key == "id") {
    //--------------------
      if (gid != NULL) {
	cerr << "no more than one id per section allowed " << value << endl;
	break;
      }

      gid = new string(value);

    //------------------------------
    } else if (key == "graphs") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }

      Tokenize(value,v_tokens,","); 

      for (size_t i=0; i<v_tokens.size(); i++) {
	map<string,wGraph_t *>::const_iterator it = glmap_id2graph.find(v_tokens[i]);
	if( it == glmap_id2graph.end() ) {
	  cerr << "Graph ID " << v_tokens[i] << " not found,";
	  cerr << "graphs must be defined before multigraph section" << endl;
	  break;
	}
	wg  = new wGraph_t(*(it->second),*gid);
	
      }
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wg = new wGraph_t();

      if (asymerrors)
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,exl,exh,eyl,eyh);
      else
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,xheader,yheader);

      if (strlen(xheader)) wg->xax->SetTitle(xheader);
      if (strlen(yheader)) wg->yax->SetTitle(yheader);

    //------------------------------
    } else if (key == "vectorfile2d") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      string path = value;
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wg = new wGraph_t();

      wg->gr2d = new TGraph2D(path.c_str());

      if (wg->gr2d->IsZombie()) {
	cerr << "Unable to make Graph2D from file " << path << endl;
	exit(-1);
      }
      wg->gr2d->SetName(gid->c_str());

    //------------------------------
    } else if (key == "path") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      wg = new wGraph_t();
      wg->gr  = getGraphFromSpec(*gid,value);
      if (!wg->gr) continue;

    //------------------------------
    } else if (key == "clone") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      map<string,wGraph_t *>::const_iterator it = glmap_id2graph.find(value);
      if( it == glmap_id2graph.end() ) {
	cerr << "Graph ID " << value << " not found,";
	cerr << "clone must be defined after the clonee" << endl;
	break;
      }
      wg  = new wGraph_t(*(it->second),*gid);

    //------------------------------
    } else if (key == "bayesdiv") {
    //------------------------------

      Tokenize(value,v_tokens,",/"); // either comma-separated or using '/'
      if (v_tokens.size() != 2) {
	cerr << "expect comma-separated list of exactly two histo specs to divide! ";
	cerr << theline << endl;
	continue;
      }

      TH1 *tmph1 = (TH1 *)findHisto(v_tokens[0]); if (!tmph1) exit(-1);
      TH1 *tmph2 = (TH1 *)findHisto(v_tokens[1]); if (!tmph2) exit(-1);

      cout << tmph1->GetNbinsX() << " " << tmph2->GetNbinsX() << endl;

      wg = new wGraph_t();

      // equivalent to BayesDivide
      //
      if (gl_verbose) wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"debug");
      else            wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"");
      //if (gl_verbose) wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode v");
      //else            wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode");
      if (!wg->gr) {
	cerr << "BayesDivide didn't work! wonder why..." << endl;
	continue;
      } else if (gl_verbose) {
	cout << wg->gr->GetN() << " points in the graph" << endl;
      }

    } else if (!wg) {
      cerr<<"One of keys path,clone,vectorfile,vectorfile2d or bayesdiv must be defined before key..."<<key<<endl;
    } else {
      if     ( key == "xoffset" )      xoffset   = str2flt(value);
      else if( key == "yoffset" )      yoffset   = str2flt(value);
      else if( key == "yscale" )       yscale    = str2flt(value);
      else if( key == "title"  )       title     = TString(value);
      else if( key == "xtitle" )       wg->xax->SetTitle(value.c_str());
      else if( key == "ytitle" )       wg->yax->SetTitle(value.c_str());
      else if( key == "ztitle" )       wg->zax->SetTitle(value.c_str());
      else if( key == "xtitleoffset" ) wg->xax->SetTitleOffset(str2flt(value));
      else if( key == "ytitleoffset" ) wg->yax->SetTitleOffset(str2flt(value));
      else if( key == "ztitleoffset" ) wg->zax->SetTitleOffset(str2flt(value));
      else if( key == "xmin" )         xmin      = str2flt(value);
      else if( key == "xmax" )         xmax      = str2flt(value);
      else if( key == "ymin" )         ymin      = str2flt(value);
      else if( key == "ymax" )         ymax      = str2flt(value);
      else if( key == "zmin" )         zmin      = str2flt(value);
      else if( key == "zmax" )         zmax      = str2flt(value);
      else if( key == "linecolor" )    wg->lcolor  = str2int(value);
      else if( key == "linestyle" )    wg->lstyle  = str2int(value);
      else if( key == "linewidth" )    wg->lwidth  = str2int(value);
      else if( key == "markercolor" )  wg->mcolor  = str2int(value);
      else if( key == "markerstyle" )  wg->mstyle  = str2int(value);
      else if( key == "markersize"  )  wg->msize   = str2int(value);
      else if( key == "fillcolor" )    wg->fcolor  = str2int(value);
      else if( key == "fillstyle" )    wg->fstyle  = str2int(value);
      else if( key == "xndiv" )        wg->xax->SetNdivisions(str2int(value));
      else if( key == "yndiv" )        wg->yax->SetNdivisions(str2int(value));
      else if( key == "asymerrors" )   asymerrors  = (bool)str2int(value);
      else if( key == "leglabel" )     wg->leglabel   = value;
      else if( key == "draw" )         wg->drawopt    = value;
      else if( key == "legdraw" )      wg->legdrawopt = value;
      else if( key == "setprecision" ) cout << setprecision(str2int(value));
      else if( key == "printvecs2file") printVectorsToFile(wg); // ,value);
      else if( key == "fittf1" ) {
	TF1 *tf1 = findTF1(value);
	if( !tf1 ) {
	  cerr << "TF1 " << value << " must be defined first" << endl;
	  continue;
	}
	string funcnewname = value+(*gid);
	wg->fitfn = new TF1(*tf1);
	wg->fitfn->SetName(funcnewname.c_str());
      }
      else if ( key == "contours" ) {
	Tokenize(value,v_tokens,",");
	wg->contours = new TVectorD(v_tokens.size());
	for (size_t i=0; i<v_tokens.size(); i++)
	  wg->contours[i] = str2flt(v_tokens[i]);
      }
      else {
	cerr << "unknown key " << key << endl;
      }
#if 0
      processCommonHistoParams(key,value,*wh);
#endif
    }
  }

  //cout << title << endl;
  if (wg->gr2d) {
    wg->gr2d->SetTitle(title);
    wg->gr2d->SetLineStyle   (wg->lstyle);
    wg->gr2d->SetLineColor   (wg->lcolor);
    wg->gr2d->SetLineWidth   (wg->lwidth);
    wg->gr2d->SetMarkerColor (wg->mcolor);
    wg->gr2d->SetMarkerStyle (wg->mstyle);
    wg->gr2d->SetMarkerSize  (wg->msize);
    wg->gr2d->SetFillStyle   (wg->fstyle);
    wg->gr2d->SetFillColor   (wg->fcolor);
    if (zmax>zmin)  
      wg->zax->SetLimits(zmin,zmax);
  } else {
    if (vx.GetNoElements()) { // load utility guarantees the same size for both
      if (yscale  != 1.0) vy *= yscale;
      if (xoffset != 0.0) vx += xoffset;
      if (yoffset != 0.0) vy += yoffset;
      if (asymerrors) 
	wg->gr = new TGraphAsymmErrors(vx,vy,exl,exh,eyl,eyh);
      else
	wg->gr = new TGraph(vx,vy);
    }
    wg->gr->UseCurrentStyle();
    wg->gr->SetTitle(title);
    wg->gr->SetLineStyle   (wg->lstyle);
    wg->gr->SetLineColor   (wg->lcolor);
    wg->gr->SetLineWidth   (wg->lwidth);
    wg->gr->SetMarkerColor (wg->mcolor);
    wg->gr->SetMarkerStyle (wg->mstyle);
    wg->gr->SetMarkerSize  (wg->msize);
    wg->gr->SetFillStyle   (wg->fstyle);
    wg->gr->SetFillColor   (wg->fcolor);

    if (xmax>xmin) wg->xax->SetLimits(xmin,xmax);
    if (ymax>ymin) wg->yax->SetLimits(ymin,ymax);
  }

  glmap_id2graph.insert(pair<string,wGraph_t *>(*gid,wg));

  return (wg != NULL);
}                                                 // processGraphSection