Output std stream per thread in multi-threaded mode

Dear all,

I have used the general framework of example B1 to write my simulation. Its scope is to collect the phase space of photons that arrive at some volume. I do this at my SteppingAction class(if post step is inside the volume, give me kinematics).

Because of already existing analysis scripts, I want to score the phase space (lines of 8 colums: particle type, energy, x,y,z, cx,cy,cz) in ASCII format but I would like to do it in multi-threaded mode so that each thread will have its own .txt output file. My unsuccessful efforts from within my SteppingAction class are the following:

  • Using G4cout with macro command /control/cout/setCoutfile which does write the .txt files but some of the photons are still written on the terminal. Also, some lines are written half way. That might be because even though I use in main: G4VmodularPhysicsList* physicslist = new QBBC(0), I still get the hadronic interactions info on my terminal?

  • Opening an std::ofstream each time RunAction is initialised by each thread but I haven’t managed to pass the stream pointer to my SteppingAction class. To do this, my RunAction class has a private std::ofstream* outputfile data member and a public Get method to return it. The pointer to the instance of RunAction is passed as an argument to SteppingAction in the ActionInitialisation (following B1 example methodology) so that I can call the Get method from within SteppingAction. I only know that at least I open the stream correctly in the RunAction class because if I “<<” some string in BeginOfRunAction and in EndOfRunAction it gets written correctly at the proper output file.

Unless there is a way to correct the half-way writing of G4cout from the first example, I think I need a way to correctly pass the thread-local std::ofstream as a pointer or reference in my thread-local SteppingAction. Then I should be able to use “<<” to write my lines.

Are there any suggestions?

Hello Thomas_Primidis,
Regarding your question: there is a function
int thr=G4Threading::G4GetThreadId();
that (obviously) returns the id of thread you are currently in (side note: it’s return of ‘-1’ means that you are in sequential mode).
You could use that function to generate an output filename in each RunAction independently, as the id is unique.

Having said that, I also would like to mention that writing into individual files for different threads may be not solution out there. One of the ways to gather data from all the different threads in your Geant4 application is to use G4Run’s virtual function Merge(const G4Run* other_run).
To use that, you first need to create your own heir of G4Run (note: you will also need to create an instance of your Run instead of G4Run in run action’s GenerateRun()). There, you’ll need to override G4Run’s virtual RecordEvent(const G4Event* event) and Merge(const G4Run* ).
The former can be used to extract hit collection of the event from detectors. This function will be called by system by the end of each event. Use event->GetHCofThisEvent() to retrieve hit collection of this event. Then you’d store the retrieved collection in some members of your Run class.
The latter is called by system at the point in time when all threads have finished their event cycle, and their Run objects are merged into one. The thread from which the Merge(other_run) is called is the one in a pair of being merged that will survive – so you need to extract data from other_run in this function.
Later, a RunAction’s EndOfRunAction(const G4Run* run) will be called one last time – this time, the ‘run’ will be the one Run object every other Run was merged into, and this time the application will be in sequential mode. This is the perfect opportunity to output data contained in ‘run’ to external file.

Hello @akimzav and thank you for the reply.

Yeah, getting the thread id was the easy part. But if I understand Hits correctly, the solution you suggest implies saving results to RAM and after the run ends you pass them to a single external file. However, in multiple online presentations I have seen that each thread can have its own output file and because I already have analysis scripts suited for multiple ASCII files I want to exploit this capability.

Isn’t there a way to keep std::ofstreamS open (1 std::ofstream per thread) while the run is performed and write ASCII in it (each thread to its respective stream) at the end of every step? That way, in case of a long simulation, if that simulation ends at least you are left with the data already written in the external file. If everything is left on RAM until the run ends, then an unwanted simulation end (e.g. duration exceeds the time limit in a cluster, power cut etc) leaves you with nothing.

I think I can now close this thread. The inspiration for the solution can be found here: http://www.cplusplus.com/forum/beginner/15771/

So, RunAction must include

in YourRunAction.hh
private
std::ofstream fileName;

public:
void writetofile(G4String buffer);

The RunAction constructor then opens the thread-local stream with fileName.open(…) using the thread id to make unique files and the destructor closes the thread-local stream with a simple fileName.close().

The writetofile method can be as simple as

in YourRunAction.cc
writetofile{ fileName << buffer << G4endl; }

Moving to the SteppingAction class it must include

in YourSteppingAction.hh
private:
YourRunAction* frunAction;

public:
YourSteppingAction(YourRunAction* runAction);

and the constructor of course initialises the data member inline with

in YourSteppingAction.cc
YourSteppingAction::YourSteppingAction(YourRunAction* runAction)
:G4UserSteppingAction,
frunAction(runAction)
{}

Finally, inside the UserSteppingAction(const G4Step* step) method simply use

frunAction->writetofile(some_string);

The some_string looks like it happily emerges after G4intS and G4doubleS are made into an std::stream and the stream is then converted to string with mysteam.str().

std::stringstream mystream;
mystream << formatted G4doubleS and G4intS …;
G4String buffer = stream.str();
frunAction->writetofile(buffer);

Final result is a separate ASCII file from each thread comprised of the thread-local buffer for each of its lines.