I have an application which is purely macro driven. I instantiate G4GDMLParser, which creates the /persistency/gdml/* set of macro commands. The application may create a geometry programmatically (with user macro commands specifying which components are to be included), or it can make use of a geometry which was loaded from GDML, using /persistency/gdml/read. There is no way for the application to detect whether or not the user has specified a GDML readback or not! The only possible method, asking the parser for its internal world volume and testing for a null pointer, fails because G4GDMLReadSetup throws an exception: *** G4Exception : ReadError issued by : G4GDMLReadSetup::getSetup() Referenced setup 'Default' was not found! *** Fatal Exception *** core dump *** This exception could be replaced by returning a null pointer up the calling chain (as well as properly testing internal function return values for null). For code which is exclusively driven by C++, it may be safe to assume that an explicit G4GDMLParser::Read() call has been made prior to GetWorldVolume(), but that is not the case when the end user has macro-based control over execution.
Tatiana has kindly agreed to look into this.
Dear Michael, I will inspect your proposal and try to add it to GDMLParser, if it possible. Best Regards, Tatiana.
Hi Mike, we would need a bit more information on what exactly you wish to do, as it is not completely clear to me... The instantiation of the parser itself is completely decoupled from the reading of the GDML file, in the sense that this can be triggered directly from your detector-construction class or from a messenger, if this is invoked through UI commands (and therefore macros). This is done in order to also allow the possibility to 'mix' geometries predefined as C++ code and import of GDML modules (the pointer returned by a GDML import may not necessarily be the world volume...). It seems to me that should be your application to properly identify how the main world volume is created and therefore check the validity of its pointer out of your DetectorConstruction. Or am I missing something? Cheers, Gabriele
Hi, Gabriele and Tatiana. As I noted, in my application the geometry configuration is driven entirely via user macro commands, which are issued at the PreInit state (i.e., _before_ DetectorConstruction::Construct() is ever called). We have two ways the user may specify a geometry: 1) They can use our local macro commands to select a C++ geometry model, for example /CDMS/Lab SnoLab /CDMS/Detector snolab /CDMS/UseShield active This gets our planned SNOLAB detector, placed inside an appropriate cavern hall, and with shielding including an active neutron veto. The world volume and all of the detector components will be built at /run/initialize. 2) They can read in a GDML geometry using the existing parser and its macro commands: /persistency/gdml/read FNAL_131011.gdml This will read in a detector and shielding design specified in a GDML file (in this case, one from the Fermilab engineers back in October 2013). Case (2) does not interact with our internal messenger (the /CDMS/... tree), and so ::Construct() has no way to know in advance whether it was executed or not! The way I wanted to write the code, in order to distinguish cleanly between the two cases, was: G4VPhysicalVolume* CDMSDetectorConstruction::Construct() { G4VPhysicalVolume* theWorld = 0; // We have GDML active and the user read in a GDML geometry if (gdmlParser && (theWorld = gdmlParser->GetWorldVolume())) return theWorld; // User specified a geometry via macros theWorld = ConstructCavern(); PlaceDetector(theWorld); PlaceShielding(theWorld); PlaceMechanicals(theWorld); PlaceSources(theWorld); return theWorld; } The idea here, which seems obvious to me, is that if the GDML parser was used to create a geometry, then GetWorldVolume() will return whatever it constructed. If not, it should return a null pointer (since it didn't build anything), and that null pointer can be tested by the user code. In fact, what happens is that GetWorldVolume() throws a fatal exception internally and aborts the job. That means that user code has NO WAY to determine if the GDML parser was actually invoked or not. This is clearly a missing piece in the design, and I would argue is a bug in the API.
Thanks for the more detailed explanation. I now better see the dilemma... Still... why you do not define a dedicated macro command for the case of importing geometries from GDML, instead on relying on creating the parser first and then allow the user to directly call the "/persistency/gdml/read" command ! This way, the creation of the parser and the file import would consistently happen within your macro command and you don't need to perform any check... I can modify the GDML reader to return a null pointer in case an invalid setup call is made; this however will have to throw at least a warning... I see this a rather twisted logic!
A new tag "gdml-V10-01-00" is made in the development branch, where the fatal exception has been removed, allowing for the return of a NULL pointer in call to GetWorldVolume(), if GDML import is not yet issued or invalid.