Segmentation Violation with RDataFrame with user-defined object (struct) columns

Hi experts,
I am trying to build a TTree with custom object branches using RDataFrame.
Unfortunately, I get a Segmentation Violation error. After some tests I figured out that it might be related to Snapshot not properly recognizing my user-defined type. I tried also to explicitly specify the types in the template of the snapshot but nothing.

I paste here the relevant parts of the code:

#include <ROOT/RDataFrame.hxx>
#include <TInterpreter.h>

typedef struct {
	double sqFall, sqFallErr;
	double sqRise, sqRiseErr;
	double sqWdt = sqFall - sqRise;
	double sqWdtErr = TMath::Sqrt(sqFall*sqFall + sqRise*sqRise);
} Square_Signal;

typedef struct {
	Square_Signal start;
	Square_Signal stop;
	double dtFall = stop.sqFall - start.sqFall;
	double dtFallErr = TMath::Sqrt(stop.sqFallErr*stop.sqFallErr + start.sqFallErr*start.sqFallErr);
	double dtRise = stop.sqRise - start.sqRise;
	double dtRiseErr = TMath::Sqrt(stop.sqRiseErr*stop.sqRiseErr + start.sqRiseErr*start.sqRiseErr);
} Decay_Event;

Decay_Event GetSameChSquare( RVec<double> vFall, RVec<double> vFallErr, RVec<double> vRise, RVec<double> vRiseErr  ){
	Square_Signal start = { vFall[0], vFallErr[0], vRise[0], vRiseErr[0] };
	Square_Signal stop = { vFall[1], vFallErr[1], vRise[1], vRiseErr[1] };
	Decay_Event decay = { start, stop };
	return decay;
}

int main(int argc, char** argv)
{
	//declare my struct data types
	gInterpreter->Declare("typedef struct {double sqFall, sqFallErr; double sqRise, sqRiseErr; double sqWdt = sqFall - sqRise; double sqWdtErr = TMath::Sqrt(sqFall*sqFall + sqRise*sqRise);} Square_Signal;");
	gInterpreter->Declare("typedef struct {Square_Signal start; Square_Signal stop; double dtFall = stop.sqFall - start.sqFall; double dtFallErr = TMath::Sqrt(stop.sqFallErr*stop.sqFallErr + start.sqFallErr*start.sqFallErr); double dtRise = stop.sqRise - start.sqRise; double dtRiseErr = TMath::Sqrt(stop.sqRiseErr*stop.sqRiseErr + start.sqRiseErr*start.sqRiseErr); } Decay_Event;");
	
	//setting I\O file names
    ...
    //	

	//open file(s)
	TChain myChain("amulet");
	for(auto measN : measNs)
		myChain.Add( (inDir+"run"+runN+"meas"+measN+"_amulet.root").c_str() );
	
	ROOT::EnableImplicitMT(); //the problem persists also with MT disabled
	
	//create df
	ROOT::RDataFrame d(myChain);

	//define filters and print report
	auto upDecays = d.Filter(ch0NupNdwn, "Ch0 Nup == Ndwn").Filter(UpDecayCut, "UpDecay (ch0Nup==2)");
	upDecays.Report()->Print();

//up to this point everything seems to work
	
	//evaluate lifetimes from digital signals defining new columns in the dataframe
	auto dtUpDec  = upDecays.Define("decayUP"   , GetSameChSquare, {"ch0timedwns","ch0timedwnsErr","ch0timeups","ch0timeupsErr" } ).Snapshot<short int, long long unsigned, Decay_Event>("DeltaT UpDecays", OutFileName.c_str(), {"measN","idx","decayUP"} ); //segmentation violation
	return 0;
}

I paste here the output of the code:

Ch0 Nup == Ndwn: pass=61         all=62         -- eff=98.39 % cumulative eff=98.39 %
UpDecay (ch0Nup==2): pass=28         all=61         -- eff=45.90 % cumulative eff=45.16 %

 *** Break *** segmentation violation
 Generating stack trace...
 0x0000564d13aba5b1 in ROOT::Detail::RDF::RDefine<Decay_Event (*)(ROOT::VecOps::RVec<double>, ROOT::VecOps::RVec<double>, ROOT::VecOps::RVec<double>, ROOT::VecOps::RVec<double>), ROOT::Detail::RDF::CustomColExtraArgs::None>::Update(unsigned int, long long) + 0x4d from ./lifetime
 0x0000564d13a9e4cf in ROOT::Internal::RDF::RDefineReader::GetImpl(long long) + 0x3d from ./lifetime
 0x0000564d13abd3ce in Decay_Event& ROOT::Detail::RDF::RColumnReaderBase::Get<Decay_Event>(long long) + 0x2e from ./lifetime
 0x0000564d13abbfc8 in _ZN4ROOT8Internal3RDF7RActionINS1_14SnapshotHelperIJsy11Decay_EventEEENS_6Detail3RDF13RJittedFilterENS_10TypeTraits8TypeListIJsyS4_EEEE8CallExecIJsyS4_EJLm0ELm1ELm2EEEEvjxNSA_IJDpT_EEESt16integer_sequ + 0x60 from ./lifetime
 0x0000564d13ab9b76 in ROOT::Internal::RDF::RAction<ROOT::Internal::RDF::SnapshotHelper<short, unsigned long long, Decay_Event>, ROOT::Detail::RDF::RJittedFilter, ROOT::TypeTraits::TypeList<short, unsigned long long, Decay_Event> >::Run(unsigned int, long long) + 0x48 from ./lifetime
 0x00007f75c8b9fefa in ROOT::Detail::RDF::RLoopManager::RunAndCheckFilters(unsigned int, long long) + 0x4a from /usr/lib/root/libROOTDataFrame.so
 0x00007f75c8ba8afb in ROOT::Detail::RDF::RLoopManager::RunTreeReader() + 0x20b from /usr/lib/root/libROOTDataFrame.so
 0x00007f75c8ba9566 in ROOT::Detail::RDF::RLoopManager::Run() + 0x996 from /usr/lib/root/libROOTDataFrame.so
 0x0000564d13aa9977 in ROOT::RDF::RResultPtr<ROOT::RDataFrame>::TriggerRun() + 0x1b from ./lifetime
 0x0000564d13aa6593 in ROOT::RDF::RResultPtr<ROOT::RDataFrame>::Get() + 0x67 from ./lifetime
 0x0000564d13aa44f0 in ROOT::RDF::RResultPtr<ROOT::RDataFrame>::operator*() + 0x24 from ./lifetime
 0x0000564d13aa2922 in _ZN4ROOT3RDF10RInterfaceINS_6Detail3RDF13RJittedFilterEvE12SnapshotImplIJsy11Decay_EventEEENS0_10RResultPtrINS1_INS3_12RLoopManagerEvEEEESt17basic_string_viewIcSt11char_traitsIcEESF_RKSt6vectorINSt7__ + 0x286 from ./lifetime
 0x0000564d13aa075d in _ZN4ROOT3RDF10RInterfaceINS_6Detail3RDF13RJittedFilterEvE8SnapshotIJsy11Decay_EventEEENS0_10RResultPtrINS1_INS3_12RLoopManagerEvEEEESt17basic_string_viewIcSt11char_traitsIcEESF_RKSt6vectorINSt7__cxx11 + 0x6f from ./lifetime
 0x0000564d13a9d2cd in main + 0xf14 from ./lifetime
 0x00007f75c85cfb25 in __libc_start_main + 0xd5 from /usr/lib/libc.so.6
 0x0000564d13a9b98e in _start + 0x2e from ./lifetime

I would appreciate any help,
thanks in advance.


ROOT Version: 6.24/00
Platform: Manjaro Linux
Compiler: GCC


Hi,
ROOT warns or errors out if you try to do I/O of a type that it doesn’t know.

If that’s not the case, are you sure vFall, vFallErr etc. always have at least two elements? If not,GetSameChSquare will try to access non-existing elements (you just need to prepend the appropriate Filter).

Cheers,
Enrico

Hi,
yes the filter is there, also in my true function I have an if condition that checks the number of elements in the vectors.

So I do not understand: he should know the type since I have declared them, right?
Do you know if there is something I can try?

Thanks

I don’t see anything that indicates this is an I/O problem (yet? :grinning_face_with_smiling_eyes: )

You can compile your program with debug symbols (-g compilation flag) and possibly run it within gdb to check at what line the segfault happens and what causes it exactly.

Ok, thanks a lot for your help! I am not an expert and I didn’t know about gdb, that really helped!
And it turns out you were right, one of the vectors had only one element due to a filter not beeing applied as I expected.

Just a side question (that I think could be partially related): at the end of the script root complains about not finding dictionaries about my class and the same applies if I try to open the freshly created root files with a tbrowser, is it something I should worry about? – the output data looks ok

just before end of script execution:

Warning in <TStreamerInfo::Build>: Decay_Event: Square_Signal has no streamer or dictionary, data member "start" will not be saved
Warning in <TStreamerInfo::Build>: Decay_Event: Square_Signal has no streamer or dictionary, data member "stop" will not be saved

when opening TBrowser:

Warning in <TClass::Init>: no dictionary for class Decay_Event is available
Warning in <TClass::Init>: no dictionary for class Square_Signal is available

Ok,
great that you solved the RVec problem!

Yes, those warnings are a problem, ROOT is “not sure” to be able to read/write your custom type correctly because it doesn’t have dictionaries for it. To perform I/O of anything but trivial user-defined types, you need dictionaries. Some resources on how to generated dictionaries are:

Cheers,
Enrico

1 Like

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