Project

General

Profile

Geant4 Physics Factories

Two Separate Factories

Geant4 has two separate factories that use the same paradigm. A general overview of the factory pattern can be found here. The factories in Geant4 under discussion here are those having to do with:

These two factories are partially interconnected. There exists a G4GenericPhysicsList that serves as an empty physics list that can be populated with a series of physics constructors by using the G4PhysicsConstructorRegistry. The G4GenericPhysicsList is also one of the available physics lists that can be returned by the g4alt::G4PhysListFactory. The g4alt::G4PhysListFactory also uses the G4PhysicsConstructorRegistry to make the EM "options" (_EMV, _EMX, _EMY, _EMZ, _LIV, _PEN, __GS) available, as well as user specified extension.

History of G4PhysListFactory

The original G4PhysListFactory supplied as part of Geant4 is the simplest of factory pattern: a hardcoded list of if/then/else conditionals that map to explicit calls to constructors. It is not user extendable, and must be updated to reference C++ headers for all classes that it is to serve. In use it was generally created as a simple object on the stack and then left to fall out of scope and be deleted -- this paradigm did not allow for the long term memory needed for extensibility.

A replacement for G4PhysListFactory was initiated by myself (Robert Hatcher) circa October 2011 to support the needs of NOvA and the Fermilab LAr experiments. Their needs included additional non-standard physics lists and the ability to extend those lists by registering additional physics constructors (e.g. monopole physics) with any physics list. This called for two "factories". Because of the desire for drop in compatibility the physics list "factory" was a simple light weight adaptor that redirected calls to the main singleton. This version of the factories created small C++ functions (to call the class ctor) that were registered with the singleton.

In 2012 Witold Pokorski introduced a physics constructor factory and the G4GenericPhysicsList into the Geant4 code base. This code used the same concepts as the one at Fermilab, but it differed in a number of details. It used templates instead of named functions and the class naming differed.

In Nov 2014 the Fermilab physics list factory was re-written using the same template-style and added to the Geant4 code base in an alternative namespace g4alt::.

A Few Notes on Nomenclature

role physics constructors physics lists
base class of returned objects G4VPhysicsConstructor G4VModularPhysicsList
(standard) user interface G4PhysicsConstructorRegistry g4alt::G4PhysListFactory
actual repository of patterns G4PhysicsConstructorRegistry G4PhysListRegistry
template for registering class;
header defines macro to use
G4PhysicsConstructorFactory G4PhysListStamper

Because of the forward facing nature of the existing G4PhysListFactory, the g4alt:: version could not exactly mimic the nomenclature used for the physics constructor (where factory is used to denote the individual mechanism for creating one class type), so 'Stamper' (think individual machine in a factory) was substituted.

User-Facing Interface

Implementation Details

On this page we won't go into to get objects -- the two Registry singles operate similarly, but the physic list Registry also has a lightweight "factory" available for drop-in compatibility -- but focus on how classes get registered (the extensibility functionality).

The G4PhysListStamper.hh header has the macros:


#define G4_DECLARE_PHYSLIST_FACTORY(physics_constructor) \
  const G4PhysListStamper<physics_list>& physics_list##Factory = \
        G4PhysListStamper<physics_list>(#physics_list)

// support for physics list defined within a namespace
// a bit tricky because cpp macro expansion doesn't like "::" 
// ala  G4_DECLARE_PHYSLIST_FACTORY_NS(myns::MyPL,myns,MyPL)   // without trailing ";" 

#define G4_DECLARE_PHYSLIST_FACTORY_NS( physics_list , nsname , plbase )    \
  namespace nsname {                                                    \
    const G4PhysListStamper<physics_list>& plbase##Factory = \
          G4PhysListStamper<physics_list>(#physics_list); \
  }

A physics list is then registered by:

#include "G4PhysListStamper.hh" 

#include "FTFP_BERT.hh" 
G4_DECLARE_PHYSLIST_FACTORY(FTFP_BERT);

What this does is create a global (here physics_listFTFP_BERT of type const G4PhysListStamper<physics_list>&), the initialization of which causes the registration with the Registry.

The G4PhysicsConstructorFactory.hh header has similar definitions:

#define G4_DECLARE_PHYSCONSTR_FACTORY(physics_constructor) [...]
#define G4_DECLARE_PHYSCONSTR_FACTORY_NS( physics_constructor, nsname, pcbase ) [...]

Care and Feeding

The registration mechanism relies on that initialization of the global variable. When a shared library is dynamically loaded such globals are created and initialized.

Problems arise when using static libraries. In this case the linker makes decisions about what code to include. Traditionally it is the case that linker, in order to minimize executable sizes and initialization times, will not include code or globals that aren't somehow referenced. This generally means that they will not pick up the physics_listFTFP_BERT global of the example by default and this must be forced by some external means.

-------- EEEE ------- G4Exception-START -------- EEEE -------
*** G4Exception : PhysicsList001
      issued by : G4PhysicsConstructorRegistry::GetPhysicsConstructor
The factory for the physics constructor [G4EmStandardPhysics] does not exist!

*** Fatal Exception *** core dump ***
-------- EEEE -------- G4Exception-END --------- EEEE -------

A simple solution would be to treat the static library similarly to a dynamic one and load the entire library. This is an option for gcc/GNU, icc/Intel and Clang as seen in cmake/Templates/Geant4Config.cmake.in where there is the following:

# - Factory registration mechanism in physics_lists requires whole
# archive to be linked when using static libs, so requires wrapping
# with suitable compiler dependent flags
set(_geant4_physicslists_library G4physicslists${_geant4_lib_use_suffix})
if(_geant4_lib_use_suffix STREQUAL "-static")
  # - Use CMAKE_CXX_COMPILER_ID, which should be reliable enough...
  # Though the GNU/Clang/Intel compilers/linkers *should* use identical
  # flags,keep their sections separate until behaviour confirmed
  #
  if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
    set(_geant4_physicslists_library -Wl,--whole-archive G4physicslists${_geant4_lib_use_suffix} -Wl,--no-whole-archive)
  elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    set(_geant4_physicslists_library -Wl,-force_load G4physicslists${_geant4_lib_use_suffix})
  elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
    set(_geant4_physicslists_library -Wl,--whole-archive G4physicslists${_geant4_lib_use_suffix} -Wl,--no-whole-archive)
  else()
    # Needs determination of other compiler options.
    # NB: MSVC has /OPT:NOREF, but may apply globally...
    set(_geant4_physicslists_library G4physicslists${_geant4_lib_use_suffix})
  endif()

Alas, Microsoft Visual Studio (MSVC) does not seem to have this capability.

http://stackoverflow.com/questions/3867254/what-is-the-microsoft-visual-studio-equivalent-to-gcc-ld-option-whole-archive

http://www.randygaul.net/2013/05/05/object-linking-with-static-libraries-in-visual-studio/

/OPT:NOREF

MSVC does have a OPT:NOREF option that looks promising, but further investigation on google shows a number of people trying to solve this same problem (often in the context of the factory paradigm) using /OPT:NOREF in MSVS without success for the last 10-ish years.

https://social.msdn.microsoft.com/Forums/vstudio/en-US/2aa2e1b7-6677-4986-99cc-62f463c94ef3/linkexe-bug-optnoref-option-doesnt-work?forum=vclanguage

Alternative approach: __pragma

MSVC Pragma Directives and the __Pragma Keyword
MSVC Pragma: comment

There is the suggestion that a pragma can be used to force an otherwise unreferenced linkage.

If a source file has a global line such as:

int ABC_XYZZY_INT = 42;
then for static builds (RelWithDebInfo) under MSVC:
C:\Users\rhatcher\geant4-trunk-build>dumpbin.exe /SYMBOLS BuildProducts\RelWithDebInfo\lib\G4physicslists-static.lib | findstr ABC_XYZ
00A 00000000 SECT4  notype       External     | ?ABC_XYZZY_INT@@3HA (int ABC_XYZZY_INT)
which indicates a need to use the mangled name in the __pragma
__pragma(comment(linker, "/include:?ABC_XYZZY_INT@@3HA"))

This is problematic for the use with the existing factory macros as it relies on knowing, understanding, depending on the name mangling scheme.

One possibility is to use:

extern "C" {
  int ABC_XYZZY_MYINT = 42;
  __pragma(comment(linker, "/include:_ABC_XYZZY_MYINT"))
}
Thus, if instead, the macros were to expand to:
extern "C" {
  const G4PhysicsConstructorFactory<G4EmStandardPhysics>& G4EmStandardPhysicsFactory = 
        G4PhysicsConstructorFactory<G4EmStandardPhysics>("G4EmStandardPhysics");
  __pragma(comment(linker, "/include:_G4EmStandardPhysicsFactory"))
}
then the linkage is matched without relying on a particular name mangling scheme.

Alas, this doesn't seem to help as the linker command is included in the library, and apparently ignored unless it is in an actual object that is being forced to be linked (e.g. the main program).

Desperate Measures

Given that the linker is determined never to pick up bits that aren't explicitly linked in, and there is no way to force the entire library to be loaded, I think one has to resort to external measures.

One approach would for the build system to run a script collecting together all the instances where the macro(s) [one for physics constructors, one for physic lists] are used; extract the name they're passed and make an explicit alwaysLink.cc file that basically just has the pragmas; compile that into a alwaysLink.o file that is forced to be linked against any executable. Very, very, inelegant.