root-project / root

The official repository for ROOT: analyzing, storing and visualizing big data, scientifically
https://root.cern
Other
2.7k stars 1.28k forks source link

RooInt removed from ROOT, data can't be read any more #16380

Closed PetrilloAtWork closed 1 month ago

PetrilloAtWork commented 1 month ago

Check duplicate issues.

Description

Reporting on behalf of Fermilab SBN collaboration and SciSoft group.


We have some ROOT data files containing RooInt objects (we used then for storing "metadata"). That class was removed from ROOT (ca29ccf1) and we can't read that data any more. This is not exactly a bug, since ROOT works as intended — but that intention breaks our data.

Twofold question:

  1. how to work around the problem for existing data using newer ROOT
  2. are there other recommended ways to simply store an integer with a name in a ROOT file? TNamed comes to mind, but it needs explicit conversions, and that is why RooInt was preferred.

For people with Fermilab access, there is a related Redmine ticket #28974.

Reproducer

  1. Write a RooInt object in a new TFile with ROOT 6.28
  2. Try to read that object from that TFile with the latest ROOT

ROOT version

v6-32-00

Installation method

Build from source

Operating system

Linux

Additional context

No response

guitargeek commented 1 month ago

Hi, thanks for the question!

The standard way of do this in ROOT is to use TParameter or an std:: container, as also discussed here: https://root-forum.cern.ch/t/writing-simple-variable-in-root-files/11094/5

For example:

void write() {

    TParameter<int> x1{"x1", 5};
    std::vector<int> x2{4};

    std::unique_ptr<TFile> file{TFile::Open("myfile.root", "RECREATE")};

    file->WriteObject(&x1, "x1");
    file->WriteObject(&x2, "x2");
}

Therefore, having this functionality is redundant as therefore it was removed.

If you still need to use RooInt in your framework for backwards compatibility, please just copy-paste its source code into your framework. It's very simple:

Are these possible ways forward? I would be very reluctant to bring this class back, because RooFit is for statistical analysis. Using its classes to store metadata in a ROOT file is really not the idea.

guitargeek commented 1 month ago

If your framework is in Python and not in C++, you can also declare the class to the interpreter when you need it:

ROOT.gInterpreter.Declare("""

class RooInt : public TNamed {
public:

  RooInt() = default;
  RooInt(Int_t value) : _value(value) {}
  RooInt(const RooInt& other) : TNamed(other), _value(other._value) {}

  // double cast operator
  inline operator Int_t() const { return _value ; }
  RooInt& operator=(Int_t value) { _value = value ; return *this ; }

protected:

  Int_t _value = 0; ///< Payload
  ClassDefOverride(RooInt,1) // Container class for Int_t
};

""")

You can change the interface as you like, as long as you don't change the data members.

PetrilloAtWork commented 1 month ago

Thank you for the answer: I wish I had noticed TParameter years ago, since RooInt did the job but it was clearly not the semantically correct choice. We'll give a chance to TParameter for the future, and try to surrogate RooInt (and RooFloat) in the new code. I'll update and eventually close this issue when we see it works.

dpiparo commented 1 month ago

Hi @PetrilloAtWork , could you verify that using TParameter works for you?

guitargeek commented 1 month ago

Closing, since we didn't hear anything back. I assume no news it god news! Feel free to open a new issue if there is a problem with TParameter for your usecase.