(pyroot) properly releasing memory/ending this script

I have a short script, which uses some pyroot functions to fit a histogram and find the location of the mean of each bin according to the fitted function.

My code is running fine, and giving the output I expect, but creates an error when the program closes. That sounds like I might be failing to release some memory or otherwise not calling the correct closing functions. Curiously, it only creates an error if I also try to plot something using pyplot. It doesn’t matter if the thing I’m plotting is utterly unrelated to what’s been calculated by pyroot.

Here is the code (saved to a file binmeans.py);

import numpy as np

def get_basic_fit(bin_edges, bin_values):
    import ROOT
    import array
    bin_centers = 0.5*(bin_edges[1:] + bin_edges[:-1])
    # seems to be needed
    bin_edges = array.array('d', bin_edges)
    n_bins = len(bin_edges) - 1
    histogram = ROOT.TH1D("temp", "temp", n_bins, bin_edges)
    #import ipdb; ipdb.set_trace()
    for v, c in zip(bin_values, bin_centers):
        histogram.Fill(c, v)
        
    basic_fit = ROOT.TF1("temp_fit", "[0]*pow(x/100,[1])*exp(-1*[2]*x)", bin_edges[0], bin_edges[-1])
    basic_fit.SetParameters(1, -0.01, 0.01)
        
    histogram.Fit(basic_fit, "RISAME")
    fit_params = np.array([basic_fit.GetParameter(i) for i in range(3)])
    histogram.Delete()
    return fit_params, basic_fit


def locate(bin_edges, bin_values):
    n_bins = len(bin_edges) - 1
    import ROOT
    fit_params, basic_fit = get_basic_fit(bin_edges, bin_values)
    bin_means = np.empty(n_bins)
    for bin_n in range(n_bins):
        upper = bin_edges[bin_n+1]
        lower = bin_edges[bin_n]
        mean = basic_fit.Integral(lower, upper)/(upper-lower)
        mean_loc = basic_fit.GetX(mean, lower, upper)
        bin_means[bin_n] = mean_loc
    return bin_means


if __name__ == "__main__":
    n_bins = 10
    bin_edges = np.sort(np.random.rand(n_bins+1)*10+1)
    bin_values = np.sort(np.random.normal(1, 2, n_bins))
    bin_means = locate(bin_edges, bin_values)
    # only get an error if I also try to plot something.....
    from matplotlib import pyplot as plt
    plt.ion()  # error with or without ion
    plt.scatter(bin_edges[:-1], bin_means)
    input("Hit enter to close.")
    plt.close()

This can be invoked with;

$ ipython3 binmeans.py

And when I call that I get the error message;

 *** Break *** <TUnixSystem::DispatchSignals>: segmentation violation
[/usr/lib/system/libsystem_platform.dylib] _sigtramp (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] PyGILState_Ensure (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] PyGILState_Ensure (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/lib/python3.9/site-packages/matplotlib/backends/_macosx.cpython-39-darwin.so] -[Window dealloc] (no debug info)
[/usr/lib/libobjc.A.dylib] AutoreleasePoolPage::releaseUntil(objc_object**) (no debug info)
[/usr/lib/libobjc.A.dylib] objc_autoreleasePoolPop (no debug info)
[/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation] _CFAutoreleasePoolPop (no debug info)
[/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation] -[NSAutoreleasePool release] (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] ROOT::MacOSX::Util::AutoreleasePool::~AutoreleasePool() (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] ROOT::MacOSX::Details::MacOSXSystem::~MacOSXSystem() (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] TMacOSXSystem::~TMacOSXSystem() (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] TROOT::~TROOT() (no debug info)
[/usr/lib/system/libsystem_c.dylib] __cxa_finalize_ranges (no debug info)
[/usr/lib/system/libsystem_c.dylib] exit (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] _Py_RestoreSignals (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] _PyErr_PrintEx (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] PyRun_SimpleFileExFlags (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] Py_RunMain (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] pymain_main (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] main (no debug info)

Am I doing anything obviously silly?
If not, this might need some experimentation to untangle. If you have any ideas about what I should try that would be fab!

Thanks, Henry

P.S. as an aside, if anyone has any more general critique on that code sample I’d be very grateful for advice on how to improve.


Please read tips for efficient and successful posting and posting code

ROOT Version: pyroot; ROOT.__version__==6.27/01, python 3.9.12
Platform: MacOS - Monterey 12.2.1
Compiler: pyroot, under ipython3 (1.29.0), from homebrew


Hello,

Thank you for reporting, I will have a look.

Two quick questions:

  • Have you identified what part of your code triggers the teardown error?
  • Is this only with ipython or python also crashes with the same error?

Your second question is quickest to answer; python3 also creates an error, but it’s slightly shorter

[/usr/lib/system/libsystem_platform.dylib] _sigtramp (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] PyGILState_Ensure (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/bin/python3.9] PyGILState_Ensure (no debug info)
[/opt/homebrew/Caskroom/miniconda/base/envs/gen/lib/python3.9/site-packages/matplotlib/backends/_macosx.cpython-39-darwin.so] -[Window dealloc] (no debug info)
[/usr/lib/libobjc.A.dylib] AutoreleasePoolPage::releaseUntil(objc_object**) (no debug info)
[/usr/lib/libobjc.A.dylib] objc_autoreleasePoolPop (no debug info)
[/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation] _CFAutoreleasePoolPop (no debug info)
[/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation] -[NSAutoreleasePool release] (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] ROOT::MacOSX::Util::AutoreleasePool::~AutoreleasePool() (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] ROOT::MacOSX::Details::MacOSXSystem::~MacOSXSystem() (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] TMacOSXSystem::~TMacOSXSystem() (no debug info)
[/Users/henry/Programs/root_build/lib/libCore.so] TROOT::~TROOT() (no debug info)
[/usr/lib/system/libsystem_c.dylib] __cxa_finalize_ranges (no debug info)
[/usr/lib/system/libsystem_c.dylib] exit (no debug info)
[/usr/lib/system/libdyld.dylib] dyld4::LibSystemHelpers::getenv(char const*) const (no debug info)
[/usr/lib/dyld] start (no debug info)

That’s not too surprising, because ipython generally has better stack traces.

I will have a look at the first point, and see if there is anything I can remove and still error :slight_smile:

Ok, so for your first point, the simplest example I could make that replicates the error is;


def get_basic_fit():
    import ROOT
    import array
    n_bins = 2
    bin_values = [2., 1.]
    bin_centers = [0.5, 1.5]
    # seems to be needed
    bin_edges = array.array('d', [0., 1., 2.])
    histogram = ROOT.TH1D("temp", "temp", n_bins, bin_edges)
    for v, c in zip(bin_values, bin_centers):
        histogram.Fill(c, v)
        
    basic_fit = ROOT.TF1("temp_fit", "[0]*pow(x/100,[1])*exp(-1*[2]*x)", bin_edges[0], bin_edges[-1])
    histogram.Fit(basic_fit, "RISAME")


if __name__ == "__main__":
    get_basic_fit()
    # only get an error if I also try to plot something.....
    from matplotlib import pyplot as plt
    plt.ion()  # error with or without ion
    plt.scatter([1], [1])
    input("Hit enter to close.")
    plt.close()

So the Fit function has to be called, and so does pyplot, or I can’t make the error appear. Does that error for you?

Edit; the Fit function complains it cannot get a good fit, that’s not the error I’d like to resolve, it doesn’t appear if I offer it real data. The error I’d like to resolve appears after you hit enter.

Hello,

I can’t reproduce on Linux, it might be some interference between ROOT and matplotlib on MacOS (this has been reported in the past).

Can you try doing, at the very beginning of your script:

import ROOT
ROOT.gROOT.SetBatch(True)

You have resolved the error, with SetBatch(True) I get no error.

Does the function prevent ROOT from trying to open windows? I can sort of see how these might be related.

SetBatch(True) disables the ROOT graphics, which seem to conflict with matplotlib. Since you are using matplotlib and not the ROOT graphics, this solution should be fine.

1 Like

Thanks, I can’t say I really see what went wrong, but I understand when I’d need to use SetBatch(True).

Thanks again for your help.

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