From b46c6d8982f74ca4a2407677c1812c5ec8409b02 Mon Sep 17 00:00:00 2001
From: Andre Sailer <andre.philippe.sailer@cern.ch>
Date: Mon, 30 Nov 2015 17:37:03 +0000
Subject: [PATCH] Add dumpSteeringFile option to print steeringFile to stdout

changed member variables to private: _errorMessages, _dumpParameter, _dumpSteeringFile

removed abspath from macroFile and compactFile because otherwise the default values break error checking
---
 DDSim/DD4hepSimulation.py | 117 +++++++++++++++++++++++++++++---------
 1 file changed, 89 insertions(+), 28 deletions(-)

diff --git a/DDSim/DD4hepSimulation.py b/DDSim/DD4hepSimulation.py
index 11854b30e..03b0117ef 100644
--- a/DDSim/DD4hepSimulation.py
+++ b/DDSim/DD4hepSimulation.py
@@ -15,6 +15,8 @@ try:
 except ImportError:
   ARGCOMPLETEENABLED=False
 
+POSSIBLEINPUTFILES = (".stdhep", ".slcio", ".HEPEvt", ".hepevt", ".hepmc")
+
 def outputLevel( level ):
   """return INT for outputlevel"""
   if isinstance(level, int):
@@ -63,10 +65,11 @@ class DD4hepSimulation(object):
     self.enableGun = False
     self.vertexSigma = [0.0, 0.0, 0.0, 0.0]
     self.vertexOffset = [0.0, 0.0, 0.0, 0.0]
-    self.detailedShowerMode = False
+    self.enableDetailedShowerMode = False
 
-    self.errorMessages = []
-    self.dumpParameter = False
+    self._errorMessages = []
+    self._dumpParameter = False
+    self._dumpSteeringFile = False
 
     ## objects for extended configuration option
     self.output = Output()
@@ -122,7 +125,7 @@ class DD4hepSimulation(object):
                         "\nshell: enable interactive session")
 
     parser.add_argument("--inputFiles", "-I", nargs='+', action="store", default=self.inputFiles,
-                        help="InputFiles for simulation, lcio, stdhep, HEPEvt, and hepevt files are supported")
+                        help="InputFiles for simulation %s files are supported" % ", ".join(POSSIBLEINPUTFILES) )
 
     parser.add_argument("--outputFile","-O", action="store", default=self.outputFile,
                         help="Outputfile from the simulation,only lcio output is supported")
@@ -156,12 +159,15 @@ class DD4hepSimulation(object):
     parser.add_argument("--enableGun", "-G", action="store_true", dest="enableGun", default=self.enableGun,
                         help="enable the DDG4 particle gun")
 
-    parser.add_argument("--dumpParameter", "--dump", action="store_true", dest="dumpParameter", default=self.dumpParameter,
+    parser.add_argument("--dumpParameter", "--dump", action="store_true", dest="dumpParameter", default=self._dumpParameter,
                         help="Print all configuration Parameters and exit")
 
-    parser.add_argument("--enableDetailedShowerMode", action="store_true", dest="detailedShowerMode", default=self.detailedShowerMode,
+    parser.add_argument("--enableDetailedShowerMode", action="store_true", dest="enableDetailedShowerMode", default=self.enableDetailedShowerMode,
                         help="use detailed shower mode")
 
+    parser.add_argument("--dumpSteeringFile", action="store_true", dest="dumpSteeringFile", default=self._dumpSteeringFile,
+                        help="print an example steering file to stdout")
+
     #FIXME: Add all the things here, then they will show up in the help usage
     #output, or do something smarter with fullHelp only for example
     self.__addAllHelper( parser )
@@ -172,11 +178,12 @@ class DD4hepSimulation(object):
       argcomplete.autocomplete(parser)
     parsed = parser.parse_args()
 
-    self.dumpParameter = parsed.dumpParameter
+    self._dumpParameter = parsed.dumpParameter
+    self._dumpSteeringFile = parsed.dumpSteeringFile
 
-    self.compactFile = os.path.abspath(parsed.compactFile)
+    self.compactFile = parsed.compactFile
     self.inputFiles = parsed.inputFiles
-    self.inputFiles = self.__checkFileFormat( self.inputFiles, (".stdhep", ".slcio", ".HEPEvt", ".hepevt", ".hepmc"))
+    self.inputFiles = self.__checkFileFormat( self.inputFiles, POSSIBLEINPUTFILES)
     self.outputFile = parsed.outputFile
     self.__checkFileFormat( self.outputFile, ('.root', '.slcio'))
     self.runType = parsed.runType
@@ -186,25 +193,36 @@ class DD4hepSimulation(object):
     self.skipNEvents = parsed.skipNEvents
     self.physicsList = parsed.physicsList
     self.crossingAngleBoost = parsed.crossingAngleBoost
-    self.macroFile = os.path.abspath(parsed.macroFile)
+    self.macroFile = parsed.macroFile
     self.enableGun = parsed.enableGun
-    self.detailedShowerMode = parsed.detailedShowerMode
+    self.enableDetailedShowerMode = parsed.enableDetailedShowerMode
     self.vertexOffset = parsed.vertexOffset
     self.vertexSigma = parsed.vertexSigma
 
     if not self.compactFile:
-      self.errorMessages.append("ERROR: No geometry compact file provided")
+      self._errorMessages.append("ERROR: No geometry compact file provided")
 
     if self.runType == "batch":
       if not self.numberOfEvents:
-        self.errorMessages.append("ERROR: Batch mode requested, but did not set number of events")
+        self._errorMessages.append("ERROR: Batch mode requested, but did not set number of events")
       if not self.inputFiles and not self.enableGun:
-        self.errorMessages.append("ERROR: Batch mode requested, but did not set inputFile(s) or gun")
+        self._errorMessages.append("ERROR: Batch mode requested, but did not set inputFile(s) or gun")
+
+    if self._dumpParameter:
+      from pprint import pprint
+      print "="*80
+      pprint(vars(self))
+      print "="*80
+      exit(1)
+
+    if self._dumpSteeringFile:
+      self.__printSteeringFile( parser )
+      exit(1)
 
     #self.__treatUnknownArgs( parsed, unknown )
     self.__parseAllHelper( parsed )
-    if self.errorMessages:
-      parser.epilog = "\n".join(self.errorMessages)
+    if self._errorMessages:
+      parser.epilog = "\n".join(self._errorMessages)
       parser.print_help()
       exit(1)
 
@@ -399,13 +417,6 @@ class DD4hepSimulation(object):
 
     DD4hep.setPrintLevel(self.printLevel)
 
-    if self.dumpParameter:
-      from pprint import pprint
-      print "="*80
-      pprint(vars(self))
-      print "="*80
-      exit(1)
-
     kernel.configure()
     kernel.initialize()
 
@@ -456,7 +467,7 @@ class DD4hepSimulation(object):
     if isinstance( fileNames, basestring ):
       fileNames = [fileNames]
     if not all( fileName.endswith( extensions ) for fileName in fileNames ):
-      self.errorMessages.append("ERROR: Unknown fileformat for file: %s" % fileNames)
+      self._errorMessages.append("ERROR: Unknown fileformat for file: %s" % fileNames)
     return fileNames
 
   def __applyBoostOrSmear( self, kernel, actionList, mask ):
@@ -499,7 +510,7 @@ class DD4hepSimulation(object):
             try:
               obj.setOption( var, parsedDict[key] )
             except RuntimeError as e:
-              self.errorMessages.append( "ERROR: %s " % e )
+              self._errorMessages.append( "ERROR: %s " % e )
 
   def __checkOutputLevel(self, level):
     """return outputlevel as int so we don't have to import anything for faster startup"""
@@ -512,10 +523,10 @@ class DD4hepSimulation(object):
       try:
         return outputLevel(level.upper())
       except ValueError:
-        self.errorMessages.append( "ERROR: printLevel is neither integer nor string" )
+        self._errorMessages.append( "ERROR: printLevel is neither integer nor string" )
         return -1
     except KeyError:
-      self.errorMessages.append( "ERROR: printLevel '%s' unknown" % level )
+      self._errorMessages.append( "ERROR: printLevel '%s' unknown" % level )
       return -1
 
   def __addParametersToRunHeader( self ):
@@ -586,13 +597,63 @@ class DD4hepSimulation(object):
           print "Adding filter '%s' matched with '%s' to sensitive detector for '%s' " %( filt, pattern, det )
           seq.add( self.filter.filters[filt]['filter'] )
       ##set detailed hit creation mode for this
-      if self.detailedShowerMode:
+      if self.enableDetailedShowerMode:
         act.HitCreationMode = 2
 
+  def __printSteeringFile( self, parser):
+    """print the parameters formated as a steering file"""
+
+    steeringFileBase="""from DDSim.DD4hepSimulation import DD4hepSimulation
+from SystemOfUnits import mm, GeV, MeV
+SIM = DD4hepSimulation()
+
+"""
+    optionDict = parser._option_string_actions
+    parameters = vars(self)
+    for parName, parameter in sorted(parameters.items(), sortParameters ):
+      if parName.startswith("_"):
+        continue
+      if isinstance( parameter, ConfigHelper ):
+        steeringFileBase += "\n\n"
+        options = parameter.getOptions()
+        for opt,valAndDoc in options.iteritems():
+          parValue, parDoc = valAndDoc
+          if parDoc:
+            steeringFileBase += "## %s\n" % "\n## ".join(parDoc.splitlines())
+          if isinstance( parValue, basestring ):
+            steeringFileBase += "SIM.%s.%s = \"%s\"\n" %(parName, opt, parValue)
+          else:
+            steeringFileBase += "SIM.%s.%s = %s\n" %(parName, opt, parValue)
+      else:
+        optionObj = optionDict.get("--"+parName, None)
+        if isinstance(optionObj, argparse._StoreAction ):
+          steeringFileBase += "## %s\n" % "\n## ".join(optionObj.help.splitlines())
+        if isinstance( parameter, basestring):
+          steeringFileBase += "SIM.%s = \"%s\"" %( parName, str(parameter))
+        else:
+          steeringFileBase += "SIM.%s = %s" %( parName, str(parameter))
+        steeringFileBase += "\n"
+    print steeringFileBase
+
 ################################################################################
 ### MODULE FUNCTIONS GO HERE
 ################################################################################
 
+def sortParameters( parA, parB ):
+  """sort the parameters by name: first normal parameters, then set of
+  parameters based on ConfigHelper objects
+  """
+  parTypeA = parA[1]
+  parTypeB = parB[1]
+  if isinstance(parTypeA, ConfigHelper) and isinstance(parTypeB, ConfigHelper):
+    return 1 if str(parA[0]) > str(parB[0]) else -1
+  elif isinstance(parTypeA, ConfigHelper):
+    return 1
+  elif isinstance(parTypeB, ConfigHelper):
+    return -1
+  else:
+    return 1 if str(parA[0]) > str(parB[0]) else -1
+
 def getOutputLevel(level):
   """return output.LEVEL"""
   from DDG4 import OutputLevel
-- 
GitLab