Extending remage

Advanced applications can extend remage and link against libremage with the usual CMake syntax:

project(myapp)
find_package(remage REQUIRED)
# add_library(myapp ...)
# add_executable(myapp ...)
target_link_libraries(myapp PRIVATE RMG::remage)

Forwarding arguments

The RMGManager is crucial for any of your code to extend remage. You can access it via

#include "RMGManager.hh"
/*...*/
RMGManager manager("myapp", argc, argv);

Using the RMGManager you can forward the properties that you otherwise would have forwarded through CLI arguments:

manager.IncludeMacroFile(macroName);
manager.SetInteractive(true);
manager.SetNumberOfThreads(nthreads);
manager.GetOutputManager()->SetOutputFileName(outputfilename);
manager.GetOutputManager()->SetOutputOverwriteFiles(overwrite);

For all of the possible options check the public functions of the RMGManager and RMGOutputManager.

Registering custom classes

To register your own custom C++ classes within remage you can use some pre-defined methods of remage. They are distributed in two places: as class methods of either RMGManager or RMGUserInit.

manager.SetUserInit(new MyGeometry());
manager.SetUserInit(new MyPhysicsList());

The SetUserInit() method supports a detector geometry inheriting from RMGHardware, a run manager inheriting from G4RunManager, a visualization manager inheriting from G4VisManager and a custom physics list inheriting from G4VUserPhysicsList.

If you want to register more custom classes, you will have to use the RMGUserInit class. Access it with auto user_init = RMGManager::Instance()->GetUserInit();. The obtained instance now lets you register more custom classes that can customize the simulation flow more than macro commands:

user_init->AddSteppingAction<T>(/*...*/);
user_init->AddTrackingAction<T>(/*...*/);
user_init->SetUserGenerator<T>(/*...*/);
user_init->AddOutputScheme<T>(/*...*/);
user_init->AddOptionalOutputScheme<T>("name", /*...*/);
user_init->ActivateOptionalOutputScheme("name");

Where you replace T with the name of your class and /*...*/ with the arguments your class constructor would take when doing new T(/*...*/). Your stepping action should inherit from G4UserSteppingAction, the tracking action from G4UserTrackingAction, the generator from RMGVGenerator and your custom output scheme from RMGVOutputScheme. For more info about RMGUserInit check the API docs.

Starting the run

After setting up your C++ code and classes, you will have to start remage. You do that with

manager.Initialize();
manager.Run();

This means after RMGManager::Run() you can add more custom C++ code that you wish to be run after finishing the simulation.

Inheriting from the default CLI

The easiest way to do all this while changing some detail is to inherit from the default CLI.

#include "RMGDefaultCli.hh"

class MyCLI : public RMGDefaultCli {

  public:

    void SetupRuntime(RMGManager& manager) override {
      RMGDefaultCli::SetupRuntime(manager);
      manager.SetUserInit(...); // for custom physics etc.
    }
    void SetupGeometry(RMGManager& manager) override {
      manager.SetUserInit(...); // for custom C++-based geometries.
    }
};

int main(int argc, char** argv) {

  MyCLI app;
  app.ParseCliArgs(argc, argv);
  app.SetupLoggingAndIpc();
  return app.RunSimulation(argc, argv);
}

Using a custom remage-cpp with the stock Python wrapper

When you build your own application as described above, you produce a replacement for the remage-cpp executable (see That remage executable…), but you usually still want to drive it through the stock remage Python wrapper to keep its input pre-processing, LH5 conversion and process-parallel orchestration.

Point the REMAGE_CPP_PATH environment variable directly at your executable; when set and existing, it takes precedence over the app path burnt into the python wrapper:

$ export REMAGE_CPP_PATH=/path/to/your/build/myapp
$ remage [options...] macro.mac

Normally the wrapper aborts if the version announced by remage-cpp over the IPC channel does not exactly match its own. This check is intentionally disabled when REMAGE_CPP_PATH is set, since your application will generally report a different version. You are therefore responsible for pairing compatible halves: neither the IPC protocol nor the on-disk output layout are stable APIs, so build your application against the same remage version as the wrapper you drive it with, and update both together.