Segmentation violation when fitting histogram with spline

Hello!
I am working on subtracting background noise from experimental data. Formula for noise distribution is known, and signal distribution is taken as a spline based on Monte-Carlo data. So I try to fit experimental histograms with sum of these distributions. However, I am getting segfault with my analysis code.

I worked out a simple reproducer, which basically fits histogram with its own spline.

{
	TF1 *f1 = new TF1("f1", "[0] * x", 0, 1);
	f1->SetParameter(0, 1);

	TH1F *h1 = new TH1F("h1", "", 10, 0, 1);
	h1->FillRandom("f1");

	TObjArray *hs = new TObjArray();
	hs->AddLast(h1);

	for (int i = 0; i < hs->GetEntries(); ++i) {
		TH1F *h = (TH1F*)hs->At(i);

		TSpline3 *spline = new TSpline3(h);

		TF1 *fit = new TF1("fit", [&](double * x, double * p) {
			// cout << "lambda call" << endl;
			return p[0] * spline->Eval(x[0]);
		}, 0, 1, 1);

		fit->SetParameter(0, 1);

		h->Fit("fit");
	}

	cout << "success" << endl;
}

This yields an empty canvas and this:

Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
 FCN=0 FROM MIGRAD    STATUS=CONVERGED      11 CALLS          12 TOTAL
                     EDM=4.65288e-29    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  p0           1.00000e+00   1.41421e-02   3.00000e-04  -6.82120e-13
success

 *** Break *** segmentation violation



===========================================================
There was a crash.
This is the entire stack trace of all threads:
===========================================================
#0  0x00007f4cfb9ec60c in waitpid () from /lib64/libc.so.6
#1  0x00007f4cfb969f62 in do_system () from /lib64/libc.so.6
#2  0x00007f4cfcb4335d in TUnixSystem::StackTrace() () from /home/user/programs/root-6.26.06-cxx17/bin/../lib/libCore.so
#3  0x00007f4cfcb42cf4 in TUnixSystem::DispatchSignals(ESignals) () from /home/user/programs/root-6.26.06-cxx17/bin/../lib/libCore.so
#4  <signal handler called>
#5  0x00007f4cfcf77be1 in ?? ()
#6  0x0000000000000000 in ?? ()
===========================================================


The lines below might hint at the cause of the crash.
You may get help by asking at the ROOT forum https://root.cern/forum
Only if you are really convinced it is a bug in ROOT then please submit a
report at https://root.cern/bugs Please post the ENTIRE stack trace
from above as an attachment in addition to anything else
that might help us fixing this issue.
===========================================================
#5  0x00007f4cfcf77be1 in ?? ()
#6  0x0000000000000000 in ?? ()
===========================================================

If I uncomment // cout << "lambda call" << endl;, then I can see

...
lambda call
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
...
success
lambda call

 *** Break *** segmentation violation
...

which hints that lambda is called after for cycle. Probably the reason for crash is that TSpline3 object doesn’t exist at this moment, but I don’t understand why lambda is called after fit is done.

Am I missing something? I would appreciate any help!


Please read tips for efficient and successful posting and posting code

ROOT Version: 6.26/06
Platform: CentOS 7 x86_64
Compiler: gcc (GCC) 12.2.0


TF1 *fit = new TF1("fit", [=](double * x, double * p) {

1 Like

Thank you!
As I figured it out, in this way lambda saves a copy of TSpline3 object for itself so it’s never lost (Lambda expressions (since C++11) - cppreference.com).
Although I still wonder why there is lambda call after fit. Probably it is related to object destructor work.

Before and after the fit, try: h->GetListOfFunctions()->ls();

This yields

OBJ: TList      TList   Doubly linked list : 0
...
OBJ: TList      TList   Doubly linked list : 0
 OBJ: TF1       fit     fit : 0 at: 0x5218f30

So I made this edit

TF1 *fit = new TF1("fit", [=](double * x, double * p) {
    cout << "spline->Eval(" << x[0] << ") = ";
    double temp = spline->Eval(x[0]);
    cout << temp << endl;
    return p[0] * temp;
}, 0, 1, 1);

and got this

spline->Eval(0.05) = 51
spline->Eval(0.15) = 150
spline->Eval(0.25) = 252
...
spline->Eval(0.95) = 978

But then I accidentally hovered a cursor over the plot of fitted histogram, and it started to send these messages again!

Apparently ROOT uses saved fit function further to calculate points on the plot, especially if I add, for example, fit->SetNpx(1000).
If TSpline3 object is captured by reference, then ROOT will fail to draw the plot because TSpline3 object lifetime will be over.

The object is still there (it was created with “new”), but the original “spline” variable is gone.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.