The SetBinError can't set right value

As you can see, I set the error with SetBinError in my custom function and read it with GetBinError immediately after that, and they are surprisingly different.

void DirectlyAdd(TProfile* prof, TProfile* prof1, TProfile* prof2, const char* choice) {
  //prof->Sumw2();
  if (choice == "+") {
    for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
      double value1 = prof1->GetBinContent(bin);
      double value2 = prof2->GetBinContent(bin);

      prof->Fill(prof1->GetBinCenter(bin), value1 + value2);
    }
  } else if (choice == "-") {
    for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
      double value1 = prof1->GetBinContent(bin);
      double value2 = prof2->GetBinContent(bin);

      prof->Fill(prof1->GetBinCenter(bin), value1 - value2);
    }
  } else {
    cout << "Please choose correct operator type: + or -" << endl;
  }
 
  for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
    double error1 = prof1->GetBinError(bin);
    double error2 = prof2->GetBinError(bin);
    const double Error = TMath::Sqrt(error1 * error1 + error2 * error2);
    prof->SetBinError(bin, Error);
    cout<<"error1: "<<error1<<" , "<<"error2: "<<error2<<" , "<<"Error theory1: "<<Error<<" , "<<"Error set: "<<prof->GetBinError(bin)<<endl;
  }
}

Here are some of the outputs:

error1: 0.000180288 , error2: 9.53529e-05 , Error theory1: 0.000203951 , Error set: 0.000203623
error1: 0.000179972 , error2: 9.52053e-05 , Error theory1: 0.000203603 , Error set: 0.000203026
error1: 0.000179682 , error2: 9.50576e-05 , Error theory1: 0.000203277 , Error set: 0.000149299
error1: 0.00017947 , error2: 9.4921e-05 , Error theory1: 0.000203026 , Error set: 0.000129671
error1: 0.000179197 , error2: 9.47892e-05 , Error theory1: 0.000202723 , Error set: 0.000198568
error1: 0.000178895 , error2: 9.46458e-05 , Error theory1: 0.000202388 , Error set: 0.000183426
error1: 0.000178722 , error2: 9.45217e-05 , Error theory1: 0.000202178 , Error set: 0.000174146
error1: 0.000178543 , error2: 9.4421e-05 , Error theory1: 0.000201972 , Error set: 0.000195398
error1: 0.000178271 , error2: 9.42926e-05 , Error theory1: 0.000201672 , Error set: 2.57332e-05
error1: 0.000178117 , error2: 9.4196e-05 , Error theory1: 0.00020149 , Error set: 4.60081e-05
error1: 0.000177876 , error2: 9.40846e-05 , Error theory1: 0.000201226 , Error set: 7.52386e-05
error1: 0.000177716 , error2: 9.39796e-05 , Error theory1: 0.000201035 , Error set: 0.000141463
error1: 0.000177549 , error2: 9.38896e-05 , Error theory1: 0.000200845 , Error set: 0.000115294
error1: 0.000177326 , error2: 9.37938e-05 , Error theory1: 0.000200604 , Error set: 0.000176073
error1: 0.00017722 , error2: 9.37162e-05 , Error theory1: 0.000200474 , Error set: 0.000128674
error1: 0.000177058 , error2: 9.36299e-05 , Error theory1: 0.00020029 , Error set: 0.000347946
error1: 0.000176824 , error2: 9.35237e-05 , Error theory1: 0.000200034 , Error set: 8.87428e-05
error1: 0.000176775 , error2: 9.34838e-05 , Error theory1: 0.000199971 , Error set: 0.00033488
error1: 0.000176602 , error2: 9.34058e-05 , Error theory1: 0.000199782 , Error set: 0.000137488
error1: 0.0001765 , error2: 9.33391e-05 , Error theory1: 0.000199661 , Error set: 0.000138535
error1: 0.000176403 , error2: 9.32862e-05 , Error theory1: 0.00019955 , Error set: 0.000157256
error1: 0.000176261 , error2: 9.32243e-05 , Error theory1: 0.000199396 , Error set: 0.000167283
error1: 0.000176208 , error2: 9.31771e-05 , Error theory1: 0.000199327 , Error set: 0.000198607
error1: 0.00017611 , error2: 9.31416e-05 , Error theory1: 0.000199224 , Error set: 0.000166912
error1: 0.000176061 , error2: 9.31119e-05 , Error theory1: 0.000199167 , Error set: 7.92794e-05

I have few remarks on your code.

  • Why you declare Error as const? Error will change at each cycle no need to be a const.

  • Do not declare variables inside the for cycles, in this way you declare variables many times instead of just once. Declaration outside cycles are better for memory management.

double value1,value2;
for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
     value1 = prof1->GetBinContent(bin);
     value2 = prof2->GetBinContent(bin);

      prof->Fill(prof1->GetBinCenter(bin), value1 + value2);
    }
  • Why not use TProfle::Add() method to add or subtract two histograms?

Best,
Stefano

Thank you so much for your suggestion of my code. The reason I don’t use TProfile::Add is because it takes into account the number of entries within each bin of the two graphs when adding/subtracting from the TProfile, and what I need is a simple subtraction of their values, which doesn’t seem to be possible with it. Also, the problem in my article still can’t be solved, I can’t get the error of my Set, the difference is more obvious when the amount of data is large, and it seems to be closer to the Content value in the bin, do you know why. Thank you so much!
There are some other results:

error1: 9.64498e-05 , error2: 5.23786e-05 , Error theory1: 1 , Error set: 0.00773844 , Bin Content: -0.00773922
error1: 9.62826e-05 , error2: 5.22766e-05 , Error theory1: 1 , Error set: 0.00795233 , Bin Content: -0.00795309
error1: 9.61095e-05 , error2: 5.21893e-05 , Error theory1: 1 , Error set: 0.00850234 , Bin Content: -0.00850304
error1: 9.59173e-05 , error2: 5.20838e-05 , Error theory1: 1 , Error set: 0.00888464 , Bin Content: -0.00888531
error1: 9.57528e-05 , error2: 5.19946e-05 , Error theory1: 1 , Error set: 0.00919615 , Bin Content: -0.0091968
error1: 9.55749e-05 , error2: 5.18993e-05 , Error theory1: 1 , Error set: 0.00974069 , Bin Content: -0.0097413
error1: 9.5409e-05 , error2: 5.18002e-05 , Error theory1: 1 , Error set: 0.0102116 , Bin Content: -0.0102122
error1: 9.52324e-05 , error2: 5.1707e-05 , Error theory1: 1 , Error set: 0.010684 , Bin Content: -0.0106845
error1: 9.50607e-05 , error2: 5.16102e-05 , Error theory1: 1 , Error set: 0.0112138 , Bin Content: -0.0112143
error1: 9.48702e-05 , error2: 5.15192e-05 , Error theory1: 1 , Error set: 0.0116422 , Bin Content: -0.0116427
error1: 9.47079e-05 , error2: 5.14282e-05 , Error theory1: 1 , Error set: 0.0124259 , Bin Content: -0.0124264
error1: 9.4553e-05 , error2: 5.13388e-05 , Error theory1: 1 , Error set: 0.0129409 , Bin Content: -0.0129413
error1: 9.43782e-05 , error2: 5.12476e-05 , Error theory1: 1 , Error set: 0.0132462 , Bin Content: -0.0132466
error1: 9.42074e-05 , error2: 5.11529e-05 , Error theory1: 1 , Error set: 0.0138244 , Bin Content: -0.0138248
error1: 9.40506e-05 , error2: 5.10658e-05 , Error theory1: 1 , Error set: 0.0144959 , Bin Content: -0.0144963
error1: 9.3884e-05 , error2: 5.09774e-05 , Error theory1: 1 , Error set: 0.0149851 , Bin Content: -0.0149855
error1: 9.37307e-05 , error2: 5.08878e-05 , Error theory1: 1 , Error set: 0.0155961 , Bin Content: -0.0155964
error1: 9.35503e-05 , error2: 5.07925e-05 , Error theory1: 1 , Error set: 0.016114 , Bin Content: -0.0161144
error1: 9.33821e-05 , error2: 5.07056e-05 , Error theory1: 1 , Error set: 0.0166249 , Bin Content: -0.0166252
error1: 9.32606e-05 , error2: 5.06275e-05 , Error theory1: 1 , Error set: 0.0170576 , Bin Content: -0.0170579
error1: 9.30847e-05 , error2: 5.05392e-05 , Error theory1: 1 , Error set: 0.0177722 , Bin Content: -0.0177725
error1: 9.2963e-05 , error2: 5.04648e-05 , Error theory1: 1 , Error set: 0.0184231 , Bin Content: -0.0184234
error1: 9.28487e-05 , error2: 5.03909e-05 , Error theory1: 1 , Error set: 0.0186517 , Bin Content: -0.018652
error1: 9.27057e-05 , error2: 5.03109e-05 , Error theory1: 1 , Error set: 0.0192681 , Bin Content: -0.0192684
error1: 9.25808e-05 , error2: 5.02408e-05 , Error theory1: 1 , Error set: 0.0193998 , Bin Content: -0.0194001
error1: 9.24717e-05 , error2: 5.01766e-05 , Error theory1: 1 , Error set: 0.019858 , Bin Content: -0.0198583
error1: 9.23579e-05 , error2: 5.01131e-05 , Error theory1: 1 , Error set: 0.0201176 , Bin Content: -0.0201178

Please ignore the value of this errortheory1, which is caused by a mistake in the code I later wrote

Try to use SetBinContent instead of Fill when modifying the new bin content.

I modified the code as you suggested as follows:

void DirectlyAdd(TProfile* prof, TProfile* prof1, TProfile* prof2, const char* choice) {
  double value1,value2,error1,error2,Error_final;
  if (choice == "+") {
    for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
      value1 = prof1->GetBinContent(bin);
      value2 = prof2->GetBinContent(bin);

      prof->SetBinContent(bin, value1 + value2);
    }
  } else if (choice == "-") {
    for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
      value1 = prof1->GetBinContent(bin);
      value2 = prof2->GetBinContent(bin);

      prof->SetBinContent(bin, value1 - value2);
    }
  } else {
    cout << "Please choose correct operator type: + or -" << endl;
  }
  // 单独的循环设置误差
  for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
    error1 = prof1->GetBinError(bin);
    error2 = prof2->GetBinError(bin);
    Error_final = TMath::Sqrt(error1 * error1 + error2 * error2);
    prof->SetBinError(bin, Error_final);
    cout<<"error1: "<<error1<<" , "<<"error2: "<<error2<<" , "<<"Error theory1: "<<Error_final<<" , "<<"Error set: "<<prof->GetBinError(bin)<<" , "<<"Bin Content: "<<prof->GetBinContent(bin)<<endl;
  }

The output turns out like this, BinContent and error all become 0.BinContent becomes 0 maybe it’s because of my improper usage? Why does the error change with the change of BinContent, I obviously set it manually.

error1: 0.000180288 , error2: 9.53529e-05 , Error theory1: 0.000203951 , Error set: 0 , Bin Content: 0
error1: 0.000179972 , error2: 9.52053e-05 , Error theory1: 0.000203603 , Error set: 0 , Bin Content: 0
error1: 0.000179682 , error2: 9.50576e-05 , Error theory1: 0.000203277 , Error set: 0 , Bin Content: 0
error1: 0.00017947 , error2: 9.4921e-05 , Error theory1: 0.000203026 , Error set: 0 , Bin Content: 0
error1: 0.000179197 , error2: 9.47892e-05 , Error theory1: 0.000202723 , Error set: 0 , Bin Content: 0
error1: 0.000178895 , error2: 9.46458e-05 , Error theory1: 0.000202388 , Error set: 0 , Bin Content: 0
error1: 0.000178722 , error2: 9.45217e-05 , Error theory1: 0.000202178 , Error set: 0 , Bin Content: 0
error1: 0.000178543 , error2: 9.4421e-05 , Error theory1: 0.000201972 , Error set: 0 , Bin Content: 0
error1: 0.000178271 , error2: 9.42926e-05 , Error theory1: 0.000201672 , Error set: 0 , Bin Content: 0
error1: 0.000178117 , error2: 9.4196e-05 , Error theory1: 0.00020149 , Error set: 0 , Bin Content: 0

Oh, I seem to know why, it’s ridiculous. There is no SetBinError function in the TProfile class, and its error is completely calculated by itself and cannot be set manually.

SetBinError is listed in the TProfile page under the method inherited by TH1 class.
If no such method was in TProfile the program should have crashed.

Thanks for the correction, then I still don’t know what went wrong…

Could you provide a small reproducer, in order to investigate the issue

This is a simple piece of code that can be run directly and has the same problems.


//thank you for your help

#include <iostream>  
#include "TProfile.h"
#include "TMath.h"
#include "TRandom3.h"

using namespace std;

void DirectlyAdd(TProfile* prof, TProfile* prof1, TProfile* prof2, const char* choice) {
  double value1,value2,error1,error2,Error_final;
  prof->Sumw2();
  if (choice == "+") {
    for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
      value1 = prof1->GetBinContent(bin);
      value2 = prof2->GetBinContent(bin);

      prof->Fill(prof1->GetBinCenter(bin), value1 + value2);
    }
  } else if (choice == "-") {
    for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
      value1 = prof1->GetBinContent(bin);
      value2 = prof2->GetBinContent(bin);

      prof->Fill(prof1->GetBinCenter(bin), value1 - value2);
    }
  } else {
    cout << "Please choose correct operator type: + or -" << endl;
  }
  
  for (int bin = 1; bin <= prof1->GetNbinsX(); bin++) {
    error1 = prof1->GetBinError(bin);
    error2 = prof2->GetBinError(bin);
    Error_final = TMath::Sqrt(error1 * error1 + error2 * error2);
    prof->SetBinError(bin, Error_final);
    cout<<"error1: "<<error1<<" , "<<"error2: "<<error2<<" , "<<"Error theory1: "<<Error_final<<" , "<<"Error set: "<<prof->GetBinError(bin)<<" , "<<"Bin Content: "<<prof->GetBinContent(bin)<<endl;
  }
}

int main(){
    // Create TProfile histograms
    TProfile* prof1 = new TProfile("prof1", "Profile 1", 100, 0, 10);
    TProfile* prof2 = new TProfile("prof2", "Profile 2", 100, 0, 10);
    TProfile* prof = new TProfile("prof", "Result Profile", 100, 0, 10);

    // Fill histograms with random data
    TRandom3 randGen;
    for (int i = 0; i < 1000; i++) {
        prof1->Fill(randGen.Uniform(10), randGen.Gaus(5, 1));
        prof2->Fill(randGen.Uniform(10), randGen.Gaus(5, 1));
    }

    // Perform the addition (you can choose "+" or "-" as the third argument)
    DirectlyAdd(prof, prof1, prof2, "+");


    return 0;
}

If you follow the TProfile documentation, the bin errors are calculated when you do GetBinError, i.e. it does not simply “retrieve” a value stored for each bin. Following the code, eventually you get here, where you can see what happens.
If you want to manipulate the bins and errors, it’s better to use TH1D or TH1F instead of TProfile.

1 Like

Thank you very much for the answer, I finally know what the problem is and solved it successfully, thanks!