Problem with ntuple in loop

Hi all,

I’ve encountered a strange bug today when setting up/filling an ntuple. The issue seems to arise when creating the columns in a for loop with/without a variable:

RunAction::RunAction(DetectorConstruction* dc, PrimaryGenerator* pg, G4int nDet) : geometry(dc), source(pg), num_det(nDet) {    
    timer = new G4Timer();

    auto aMan = G4AnalysisManager::Instance();

    aMan->SetDefaultFileType("root");
    aMan->SetVerboseLevel(0);
    aMan->SetNtupleMerging(true);
    aMan->SetFileName("output");
    aMan->Clear();
    aMan->Reset();

    aMan->CreateNtuple("event_info", "kinematics and whatnot for each event");

    aMan->CreateNtupleIColumn("nevt"); // event ID
    aMan->CreateNtupleFColumn("ene"); // energy

    aMan->CreateNtupleFColumn("posx"); // initial position
    aMan->CreateNtupleFColumn("posy");
    aMan->CreateNtupleFColumn("posz");

    aMan->CreateNtupleFColumn("momx"); // initial momentum direction
    aMan->CreateNtupleFColumn("momy");
    aMan->CreateNtupleFColumn("momz");

    G4int nam = num_det_max;
    if( num_det < num_det_max ) { nam = num_det; }
    for( G4int i = 1; i <= nam; i++ ) { 
        G4String cid = "e" + std::to_string(i);
        aMan->CreateNtupleDColumn(cid);
    }

    aMan->FinishNtuple();
}

When setting the upper range to be the variable nam, the following errors appear when trying to fill the ntuple during an event. It’s as if the ntuple doesn’t exist anymore:

G4WT0 > tools::wroot::base_pntuple_column_wise : a_basket_sizes.size() (8) != a_bkg.columns().size() (14).
G4WT0 >
-------- WWWW ------- G4Exception-START -------- WWWW -------
*** G4Exception : Analysis_W001
      issued by : G4RootPNtupleManager::FillNtupleTColumn
ntupleId 2 columnId 0 does not exist.
*** This is just a warning message. ***
-------- WWWW -------- G4Exception-END --------- WWWW -------

(this goes on)

G4WT0 >
-------- WWWW ------- G4Exception-START -------- WWWW -------
*** G4Exception : Analysis_W001
      issued by : G4RootPNtupleManager::FillNtupleTColumn
ntupleId 2 columnId 13 does not exist.
*** This is just a warning message. ***
-------- WWWW -------- G4Exception-END --------- WWWW -------
G4WT0 >
-------- WWWW ------- G4Exception-START -------- WWWW -------
*** G4Exception : Analysis_W001
      issued by : G4RootPNtupleManager::AddNtupleRow
NtupleId 2adding row failed.
*** This is just a warning message. ***
-------- WWWW -------- G4Exception-END --------- WWWW -------

G4WT0 > tools::wroot::mt_ntuple_column_wise::end_fill : m_main_branches.size() (8) != m_cols.size() (0).
G4WT0 >
-------- WWWW ------- G4Exception-START -------- WWWW -------
*** G4Exception : Analysis_W001
      issued by : G4RootPNtupleManager::Merge
Ntuple event_infoend fill has failed.
*** This is just a warning message. ***
-------- WWWW -------- G4Exception-END --------- WWWW -------

The variable nam is 6 in this case, and if I replace the for loop upper bound with an explicit 6, everything works normally. The error only appears when passing a G4int argument (num_det) from my user action initialization:

void ActionInitialization::Build() const {
    auto generator = new PrimaryGenerator(geometry);
    SetUserAction(generator);
    auto runAction = new RunAction(geometry, generator, nDet);
    SetUserAction(runAction);
    auto eventAction = new EventAction(runAction);
    SetUserAction(eventAction);
    if( is_doStep ) { SetUserAction(new SteppingAction()); }
    if( is_doTrack ) { SetUserAction(new TrackingAction(eventAction)); } 
}

class RunAction : public G4UserRunAction {
public:
	RunAction(DetectorConstruction*, PrimaryGenerator*, G4int);
    ~RunAction() override;
    (etc)
private:
	G4int num_det = 0;
	const G4int num_det_max = 20;
    (etc)
};

RunAction::RunAction(DetectorConstruction* dc, PrimaryGenerator* pg, G4int nDet) : geometry(dc), source(pg), num_det(nDet) { 
    (see above)
}

Because when I try this:

    G4int q = 6;
    for( G4int i = 1; i <= q; i++ ) { 
        G4String cid = "e" + std::to_string(i);
        aMan->CreateNtupleDColumn(cid);
    }

then everything also works fine. My goal was just to have a user-defined (in a macro) number of columns in the ntuple, but this issue makes that impossible. Does anyone have ideas for how to fix this?

Thank you!

First guess is that your variable is not being passed to other threads (which default to the 0 set in your constructor). Each thread gets a copy of the ntuples that merge later so if that variable is not being passed then all but your master thread might not be registering the value you think they are. That is very easy to accidentally do when also trying to run messengers.

I think what you want to do is initialize this in a singleton class, and given its nDet I’d do it in the detector construction (and have the UI messenger pass it that variable). Then have all the threads access that.

1 Like

That worked perfectly—thanks!

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