Пример #1
0
class WhizardAnalysis(ModuleBase):
  """
  Specific Module to run a Whizard job.
  """
  def __init__(self):
    super(WhizardAnalysis, self).__init__()
    self.enable = True
    self.STEP_NUMBER = ''
    self.debug = True
    self.SteeringFile = ''
    self.OutputFile = ''
    self.NumberOfEvents = 1
    self.Lumi = 0
    self.applicationName = 'whizard'
    self.evttype = ""
    self.RandomSeed = 0
    self.getProcessInFile = False
    self.datMan = DataManager()
    self.processlist = None
    self.parameters = {}
    self.susymodel = 0
    self.Model = ''
    self.genmodel = GeneratorModels()
    self.eventstring = ['! ', 'Fatal error:', 'PYSTOP', 'No matrix element available',
                        'Floating point exception', 'Event generation finished.', " n_events","luminosity", 
                        "  sum            "]
    self.excludeAllButEventString = False
    self.steeringparameters = ''
    self.options = None
    self.optionsdict = {}
    self.OptionsDictStr = ''
    self.GenLevelCutDictStr = ''
    self.genlevelcuts = {}
    self.willCut = False
    self.useGridFiles = False
    
    
  def obtainProcessList(self):
    """Internal function
    
    Get the process list from storage if whizard.in was not provided

    :return: S_OK(), S_ERROR()
    """
    
    res = self.ops.getValue("/ProcessList/Location", "")
    if not res:
      return S_ERROR("No process list found")
    processlistloc = res
    if not os.path.exists(os.path.basename(processlistloc)):
      res = self.datMan.getFile(processlistloc)
      if not res['OK']:
        LOG.error('Could not get processlist: %s' % res['Message'])
        return res
    self.processlist = ProcessList(os.path.basename(processlistloc))
    return S_OK()
    
  def applicationSpecificInputs(self):
    """Resolve module input

    :return: S_OK()
    """
    self.parameters['ENERGY'] = self.energy

    if not self.RandomSeed and self.jobID:
      self.RandomSeed = self.jobID
    if 'IS_PROD' in self.workflow_commons or 'IS_DBD_GEN_PROD' in self.workflow_commons:
      self.RandomSeed = int(str(int(self.workflow_commons["PRODUCTION_ID"])) + str(int(self.workflow_commons["JOB_ID"])))  

    self.parameters['SEED'] = self.RandomSeed
    self.parameters['NBEVTS'] = self.NumberOfEvents
    self.parameters['LUMI'] = self.Lumi

    ##EVER USED???
    if 'SusyModel' in self.step_commons:
      self.susymodel = self.step_commons['SusyModel']

    self.SteeringFile = os.path.basename(self.step_commons.get("InputFile", self.SteeringFile))
    if self.SteeringFile == "whizard.in":
      os.rename(self.SteeringFile, "whizardnew.in")
      self.SteeringFile = "whizardnew.in"

    self.parameters['PROCESS'] = self.evttype

    listofparams = self.steeringparameters.split(";")
    for param in listofparams:
      if param.count("="):
        self.parameters[param.split("=")[0]] = param.split("=")[1]
 
    if self.OptionsDictStr:
      LOG.info("Will use whizard.in definition from WhizardOptions.")
      try:
        self.optionsdict = eval(self.OptionsDictStr)
        if 'integration_input' not in self.optionsdict:
          self.optionsdict['integration_input'] = {}
        if 'seed' not in self.optionsdict['integration_input']:
          self.optionsdict['integration_input']['seed'] = int(self.RandomSeed)
        if 'process_input' in self.optionsdict:
          if 'sqrts' in self.optionsdict['process_input']:
            self.energy = self.optionsdict['process_input']['sqrts']
      except:
        return S_ERROR("Could not convert string to dictionary for optionsdict")
    
    if self.GenLevelCutDictStr:
      LOG.info("Found generator level cuts")
      try:
        self.genlevelcuts = eval(self.GenLevelCutDictStr)
      except:
        return S_ERROR("Could not convert the generator level cuts back to dictionary")  
    
    if not len(self.SteeringFile) and not self.optionsdict:
      self.getProcessInFile = True
 
    if "IS_PROD" in self.workflow_commons:
      if self.workflow_commons["IS_PROD"] and not self.willCut:
        #self.OutputFile = getProdFilename(self.OutputFile,int(self.workflow_commons["PRODUCTION_ID"]),
        #                                  int(self.workflow_commons["JOB_ID"]))
        if 'ProductionOutputData' in self.workflow_commons:
          outputlist = self.workflow_commons['ProductionOutputData'].split(";")
          for obj in outputlist:
            if obj.lower().count("_gen_"):
              self.OutputFile = os.path.basename(obj)
              break
        else:
          #This is because most likely there is stdhepcut running after
          self.OutputFile = "willcut.stdhep" 
          
          #getProdFilename(self.OutputFile,int(self.workflow_commons["PRODUCTION_ID"]),
          #                                  int(self.workflow_commons["JOB_ID"]))
          
    if "IS_DBD_GEN_PROD" in self.workflow_commons and self.workflow_commons["IS_DBD_GEN_PROD"]:
      #self.OutputFile = getProdFilename(self.OutputFile,int(self.workflow_commons["PRODUCTION_ID"]),
      #                                  int(self.workflow_commons["JOB_ID"]))
      if 'ProductionOutputData' in self.workflow_commons:
        outputlist = self.workflow_commons['ProductionOutputData'].split(";")
        for obj in outputlist:
          self.OutputFile = os.path.basename(obj)
          break
      else:
        self.OutputFile = getProdFilename(self.OutputFile, int(self.workflow_commons["PRODUCTION_ID"]),
                                          int(self.workflow_commons["JOB_ID"]))
    return S_OK()

  def runIt(self):
    """ Called by Agent
    
    Executes the following
      - resolve input variables
      - resolve installation location
      - resolve dependencies location (beam_spectra)
      - get processlist if needed
      - define output file name
      - prepare whizard.in
      - make magic
      
    :return: S_OK(), S_ERROR()
    """
    self.result = S_OK()
    if not self.platform:
      self.result = S_ERROR( 'No ILC platform selected' )
    elif not self.applicationLog:
      self.result = S_ERROR( 'No Log file provided' )
    if not self.result['OK']:
      LOG.error("Failed to resolve input parameters:", self.result["Message"])
      return self.result

    if not self.workflowStatus['OK'] or not self.stepStatus['OK']:
      LOG.verbose('Workflow status = %s, step status = %s' % (self.workflowStatus['OK'], self.stepStatus['OK']))
      return S_OK('Whizard should not proceed as previous step did not end properly')

    #if self.debug:
    #  self.excludeAllButEventString = False

    res = getSoftwareFolder(self.platform, self.applicationName, self.applicationVersion)
    if not res['OK']:
      LOG.error("Failed getting software folder", res['Message'])
      self.setApplicationStatus('Failed finding software')
      return res
    mySoftDir = res['Value']

    ###Remove libc
    removeLibc(mySoftDir + "/lib")

    ##Need to fetch the new LD_LIBRARY_PATH
    new_ld_lib_path = getNewLDLibs(self.platform, self.applicationName, self.applicationVersion)
    #Don't forget to prepend the application's libs
    new_ld_lib_path = mySoftDir + "/lib:" + new_ld_lib_path
    ### Resolve dependencies (look for beam_spectra)
    deps = resolveDeps(self.platform, self.applicationName, self.applicationVersion)
    path_to_beam_spectra = ""
    path_to_gridfiles = ""
    for dep in deps:
      res = getSoftwareFolder(self.platform, dep[ "app" ], dep['version'])
      if not res['OK']:
        LOG.error("Failed getting software folder", res['Message'])
        self.setApplicationStatus('Failed finding software')
        return res
      depfolder = res['Value']
      if dep["app"] == "beam_spectra":
        path_to_beam_spectra = depfolder
      elif dep["app"] == "gridfiles":
        path_to_gridfiles = depfolder

    ##Env variables needed to run whizard: avoids hard coded locations
    os.environ['LUMI_LINKER'] = path_to_beam_spectra + "/lumi_linker_000"
    os.environ['PHOTONS_B1'] = path_to_beam_spectra + "/photons_beam1_linker_000"
    os.environ['PHOTONS_B2'] = path_to_beam_spectra + "/photons_beam2_linker_000"
    os.environ['EBEAM'] = path_to_beam_spectra + "/ebeam_in_linker_000"
    os.environ['PBEAM'] = path_to_beam_spectra + "/pbeam_in_linker_000"

    os.environ['LUMI_EE_LINKER'] = path_to_beam_spectra + "/lumi_ee_linker_000"
    os.environ['LUMI_EG_LINKER'] = path_to_beam_spectra + "/lumi_eg_linker_000"
    os.environ['LUMI_GE_LINKER'] = path_to_beam_spectra + "/lumi_ge_linker_000"
    os.environ['LUMI_GG_LINKER'] = path_to_beam_spectra + "/lumi_gg_linker_000"
    

    list_of_gridfiles = []
    if path_to_gridfiles and self.useGridFiles:
      tmp_list_of_gridfiles = [os.path.join(path_to_gridfiles, item) for item in os.listdir(path_to_gridfiles)]
      gridfilesfound = False
      for path in tmp_list_of_gridfiles:
        if os.path.isdir(path) and path.count(str(self.energy)): 
          #Here look for a sub directory for the energy related grid files
          list_of_gridfiles = [os.path.join(path, item) for item in os.listdir(path)]
          gridfilesfound = True
          LOG.info('Found grid files specific for energy %s' % self.energy)
          break
      if not gridfilesfound:
        LOG.info("Will use generic grid files found, hope the energy is set right")
        list_of_gridfiles = [item for item in glob.glob(os.path.join(path_to_gridfiles, "*.grb")) + glob.glob(os.path.join(path_to_gridfiles, "*.grc"))]
         
    template = False
    if self.SteeringFile.count("template"):
      template = True
    ## Get from process file the proper whizard.in file
    if self.getProcessInFile:
      whizardin = ""
      res = self.obtainProcessList()
      if not res['OK']:
        LOG.error("Could not obtain process list")
        self.setApplicationStatus('Failed getting processlist')
        return res
      whizardin = self.processlist.getInFile(self.evttype)
      if not whizardin:
        LOG.error("Whizard input file was not found in process list, cannot proceed")
        self.setApplicationStatus('Whizard input file was not found')
        return S_ERROR("Error while resolving whizard input file")
      if whizardin.count("template"):
        template = True
      try:
        shutil.copy("%s/%s" % (mySoftDir, whizardin), "./whizardnew.in")
        self.SteeringFile = "whizardnew.in"
      except EnvironmentError:
        LOG.error("Could not copy %s from %s" % (whizardin, mySoftDir))
        self.setApplicationStatus('Failed getting whizard.in file')
        return S_ERROR("Failed to obtain %s" % whizardin)

    ##Check existence of Les Houches input file
    leshouchesfiles = ''
    if not os.path.exists("LesHouches.msugra_1.in"):
      if self.susymodel:
        if self.susymodel == 1:
          if os.path.exists("%s/LesHouches_slsqhh.msugra_1.in" % (mySoftDir)):
            leshouchesfiles = "%s/LesHouches_slsqhh.msugra_1.in" % (mySoftDir)
        if self.susymodel == 2:
          if os.path.exists("%s/LesHouches_chne.msugra_1.in" % (mySoftDir)):
            leshouchesfiles = "%s/LesHouches_chne.msugra_1.in" % (mySoftDir)
      if self.Model:
        if self.genmodel.hasModel(self.Model)['OK']:
          if self.genmodel.getFile(self.Model)['OK']:
            if os.path.exists("%s/%s" % (mySoftDir, self.genmodel.getFile(self.Model)['Value'])):
              leshouchesfiles = "%s/%s" % (mySoftDir, self.genmodel.getFile(self.Model)['Value'])
            else:
              LOG.error("Request LesHouches file is missing, cannot proceed")
              self.setApplicationStatus("LesHouches file missing")
              return S_ERROR("The LesHouches file was not found. Probably you are using a wrong version of whizard.") 
          else:
            LOG.warn("No file found attached to model %s" % self.Model)
        else:
          LOG.error("Model undefined:", self.Model)
          self.setApplicationStatus("Model undefined")
          return S_ERROR("No Model %s defined" % self.Model)
    else:
      leshouchesfiles = "LesHouches.msugra_1.in"

    outputfilename = self.evttype
    
          
    if self.optionsdict:
      LOG.info("Using: %s" % self.optionsdict)
      self.options = WhizardOptions(self.Model)
      res = self.options.changeAndReturn(self.optionsdict)
      if not res['OK']:
        return res
      res = self.options.toWhizardDotIn("whizard.in")
    elif not template:  
      res = prepareWhizardFile(self.SteeringFile, outputfilename, self.energy,
                               self.RandomSeed, self.NumberOfEvents, self.Lumi, 
                               "whizard.in")
    else:
      res = prepareWhizardFileTemplate(self.SteeringFile, outputfilename,
                                       self.parameters, "whizard.in")
    if not res['OK']:
      LOG.error('Something went wrong with input file generation')
      self.setApplicationStatus('Whizard: something went wrong with input file generation')
      return S_ERROR('Something went wrong with whizard.in file generation')
    foundproceesinwhizardin = res['Value']
    
    scriptName = 'Whizard_%s_Run_%s.sh' % (self.applicationVersion, self.STEP_NUMBER)
    if os.path.exists(scriptName): 
      os.remove(scriptName)
    script = open(scriptName, 'w')
    script.write('#!/bin/sh \n')
    script.write('#####################################################################\n')
    script.write('# Dynamically generated script to run a production or analysis job. #\n')
    script.write('#####################################################################\n')
    script.write('declare -x PATH=%s:$PATH\n' % mySoftDir)
    script.write('declare -x LD_LIBRARY_PATH=%s\n' % new_ld_lib_path)
    script.write('env | sort >> localEnv.log\n')      
    script.write('echo =============================\n')
    script.write('echo Printing content of whizard.in \n')
    script.write('cat whizard.in\n')
    script.write('echo =============================\n')
    script.write('cp  %s/whizard.mdl ./\n' % mySoftDir)
    if leshouchesfiles:
      if not leshouchesfiles == 'LesHouches.msugra_1.in':
        script.write('cp %s ./LesHouches.msugra_1.in\n' % (leshouchesfiles))
      script.write('ln -s LesHouches.msugra_1.in fort.71\n')
    if len(list_of_gridfiles):
      for gridfile in list_of_gridfiles:
        script.write('cp %s ./\n' % (gridfile))
    script.write('cp %s/whizard.prc ./\n' % mySoftDir)
    if self.genlevelcuts:
      res = self.makeWhizardDotCut1()
      if not res['OK']:
        script.close()
        LOG.error("Could not create the cut1 file")
        return S_ERROR("Could not create the cut1 file")
    script.write('echo =============================\n')
    script.write('echo Printing content of whizard.prc \n')
    script.write('cat whizard.prc\n')
    script.write('echo =============================\n')
    extracmd = ""
    if not self.debug:
      extracmd = "2>/dev/null" 
      
    comm = ""
    if foundproceesinwhizardin:
      comm = 'whizard --simulation_input \'write_events_file = \"%s\"\'' % (outputfilename)
    else:
      comm = 'whizard --process_input \'process_id =\"%s\"\' --simulation_input \'write_events_file = \"%s\"\' ' % (self.evttype, 
                                                                                                                    outputfilename)
    comm = "%s %s %s\n" % (comm, self.extraCLIarguments, extracmd)
    LOG.info("Will run %s" % comm)
    script.write(comm)
    script.write('declare -x appstatus=$?\n')    
    script.write('exit $appstatus\n')
    
    script.close()
    if os.path.exists(self.applicationLog): 
      os.remove(self.applicationLog)
    os.chmod(scriptName, 0o755)
    comm = 'sh -c "./%s"' % (scriptName)    
    self.setApplicationStatus('Whizard %s step %s' %(self.applicationVersion, self.STEP_NUMBER))
    self.stdError = ''
    self.result = shellCall(0, comm, callbackFunction = self.redirectLogOutput, bufferLimit=209715200)
    #self.result = {'OK':True,'Value':(0,'Disabled Execution','')}
    if not self.result['OK']:
      LOG.error("Failed with error %s" % self.result['Message'])
    if not os.path.exists(self.applicationLog):
      LOG.error("Something went terribly wrong, the log file is not present")
      self.setApplicationStatus('%s failed terribly, you are doomed!' % (self.applicationName))
      if not self.ignoreapperrors:
        return S_ERROR('%s did not produce the expected log' % (self.applicationName))
    lumi = ''
    message = ""
    success = False
    ###Analyse log file
    with open(self.applicationLog) as logfile:
      for line in logfile:
        if line.count('! Event sample corresponds to luminosity'):
          elems = line.split()
          lumi = elems[-1]
        if line.count("*** Fatal error:"):
          status = 1
          message = line
          break
        elif line.count("PYSTOP"):
          status = 1
          message = line
          break
        elif line.count("No matrix element available"):
          status = 1
          message = line
          break
        elif line.count("Floating point exception"):
          status = 1
          message = line
          break
        elif line.count("Event generation finished."):
          success = True
        else:
          status = 0
    if success:
      status = 0
    else:
      status = 1
    LOG.info('The sample generated has an equivalent luminosity of %s' % lumi)
    if lumi:
      self.workflow_commons['Luminosity'] = float(lumi)
    else:
      status = 1  
    
    ##Now care for the cross sections
    info = {}
    res = self.options.getAsDict()
    if os.path.exists("whizard.out") and res['OK']:
      full_opts_dict = res['Value']
      processes = full_opts_dict['process_input']['process_id'].split()
      info = {}
      info['xsection'] = {}
      processes.append('sum')
      with open("whizard.out", "r") as inf:
        for line in inf:
          line = line.rstrip()
          for process in processes:
            if not process:
              continue
            if line.count("   %s            " % process):
              info['xsection'][process] = {}
              line = line.lstrip()
              crosssection = line.split()[1]
              err_crosssection = line.split()[2]
              frac = line.split()[4]
              info['xsection'][process]['xsection'] = float(crosssection)
              info['xsection'][process]['err_xsection'] = float(err_crosssection)
              info['xsection'][process]['fraction'] = float(frac)

    if info:
      if 'Info' not in self.workflow_commons:
        self.workflow_commons['Info'] = info
      else:
        self.workflow_commons['Info'].update(info)

    LOG.info("Status after the application execution is %s" % str(status))

    messageout = 'Whizard %s Successful' % (self.applicationVersion)
    failed = False
    if status != 0:
      LOG.error("Whizard execution completed with errors:")
      failed = True
    else:
      LOG.info("Whizard execution completed successfully")
      ###Deal with output file
      if len(self.OutputFile):
        if os.path.exists(outputfilename + ".001.stdhep"):
          LOG.notice("Looking for output files")
          ofnames = glob.glob(outputfilename+'*.stdhep')
          if len(ofnames) > 1:
            basename = self.OutputFile.split(".stdhep")[0]
            i = 0
            for of in ofnames:
              i += 1
              name = basename + "_" + str(i) + ".stdhep"
              os.rename(of, name)
          else:
            os.rename(outputfilename + ".001.stdhep", self.OutputFile)    
        else:
          LOG.error("Whizard execution did not produce a stdhep file")
          self.setApplicationStatus('Whizard %s Failed to produce STDHEP file' % (self.applicationVersion))
          messageout = 'Whizard Failed to produce STDHEP file'
          if not self.ignoreapperrors:
            return S_ERROR(messageout)

    if failed is True:
      LOG.error("==================================\n StdError:\n")
      LOG.error(message)
      self.setApplicationStatus('%s Exited With Status %s' % (self.applicationName, status))
      LOG.error('Whizard Exited With Status %s' % (status))
      messageout = 'Whizard Exited With Status %s' % (status)
      if not self.ignoreapperrors:
        return S_ERROR(messageout)
    else:
      self.setApplicationStatus(messageout)
    return S_OK( { "OutputFile": self.OutputFile } )

  def makeWhizardDotCut1(self):
    """ When users need whizard cuts, this is called to prepare the file

    :return: S_OK()
    """
    cutf = open("whizard.cut1","w")
    for key, values in self.genlevelcuts.items():
      cutf.write("process %s\n" % key)
      for val in values:
        cutf.write("  %s\n" % val)
    cutf.close()
    return S_OK()
Пример #2
0
class WhizardAnalysis(ModuleBase):
    """
  Specific Module to run a Whizard job.
  """
    def __init__(self):
        super(WhizardAnalysis, self).__init__()
        self.enable = True
        self.STEP_NUMBER = ''
        self.debug = True
        self.log = gLogger.getSubLogger("WhizardAnalysis")
        self.SteeringFile = ''
        self.OutputFile = ''
        self.NumberOfEvents = 1
        self.Lumi = 0
        self.applicationName = 'whizard'
        self.evttype = ""
        self.RandomSeed = 0
        self.getProcessInFile = False
        self.datMan = DataManager()
        self.processlist = None
        self.parameters = {}
        self.susymodel = 0
        self.Model = ''
        self.genmodel = GeneratorModels()
        self.eventstring = [
            '! ', 'Fatal error:', 'PYSTOP', 'No matrix element available',
            'Floating point exception', 'Event generation finished.',
            " n_events", "luminosity", "  sum            "
        ]
        self.excludeAllButEventString = False
        self.steeringparameters = ''
        self.options = None
        self.optionsdict = {}
        self.OptionsDictStr = ''
        self.GenLevelCutDictStr = ''
        self.genlevelcuts = {}
        self.willCut = False
        self.useGridFiles = False

    def obtainProcessList(self):
        """Internal function
    
    Get the process list from storage if whizard.in was not provided

    :return: S_OK(), S_ERROR()
    """

        res = self.ops.getValue("/ProcessList/Location", "")
        if not res:
            return S_ERROR("No process list found")
        processlistloc = res
        if not os.path.exists(os.path.basename(processlistloc)):
            res = self.datMan.getFile(processlistloc)
            if not res['OK']:
                self.log.error('Could not get processlist: %s' %
                               res['Message'])
                return res
        self.processlist = ProcessList(os.path.basename(processlistloc))
        return S_OK()

    def applicationSpecificInputs(self):
        """Resolve module input

    :return: S_OK()
    """
        self.parameters['ENERGY'] = self.energy

        if not self.RandomSeed and self.jobID:
            self.RandomSeed = self.jobID
        if 'IS_PROD' in self.workflow_commons or 'IS_DBD_GEN_PROD' in self.workflow_commons:
            self.RandomSeed = int(
                str(int(self.workflow_commons["PRODUCTION_ID"])) +
                str(int(self.workflow_commons["JOB_ID"])))

        self.parameters['SEED'] = self.RandomSeed
        self.parameters['NBEVTS'] = self.NumberOfEvents
        self.parameters['LUMI'] = self.Lumi

        ##EVER USED???
        if 'SusyModel' in self.step_commons:
            self.susymodel = self.step_commons['SusyModel']

        self.SteeringFile = os.path.basename(
            self.step_commons.get("InputFile", self.SteeringFile))
        if self.SteeringFile == "whizard.in":
            os.rename(self.SteeringFile, "whizardnew.in")
            self.SteeringFile = "whizardnew.in"

        self.parameters['PROCESS'] = self.evttype

        listofparams = self.steeringparameters.split(";")
        for param in listofparams:
            if param.count("="):
                self.parameters[param.split("=")[0]] = param.split("=")[1]

        if self.OptionsDictStr:
            self.log.info(
                "Will use whizard.in definition from WhizardOptions.")
            try:
                self.optionsdict = eval(self.OptionsDictStr)
                if 'integration_input' not in self.optionsdict:
                    self.optionsdict['integration_input'] = {}
                if 'seed' not in self.optionsdict['integration_input']:
                    self.optionsdict['integration_input']['seed'] = int(
                        self.RandomSeed)
                if 'process_input' in self.optionsdict:
                    if 'sqrts' in self.optionsdict['process_input']:
                        self.energy = self.optionsdict['process_input'][
                            'sqrts']
            except:
                return S_ERROR(
                    "Could not convert string to dictionary for optionsdict")

        if self.GenLevelCutDictStr:
            self.log.info("Found generator level cuts")
            try:
                self.genlevelcuts = eval(self.GenLevelCutDictStr)
            except:
                return S_ERROR(
                    "Could not convert the generator level cuts back to dictionary"
                )

        if not len(self.SteeringFile) and not self.optionsdict:
            self.getProcessInFile = True

        if "IS_PROD" in self.workflow_commons:
            if self.workflow_commons["IS_PROD"] and not self.willCut:
                #self.OutputFile = getProdFilename(self.OutputFile,int(self.workflow_commons["PRODUCTION_ID"]),
                #                                  int(self.workflow_commons["JOB_ID"]))
                if 'ProductionOutputData' in self.workflow_commons:
                    outputlist = self.workflow_commons[
                        'ProductionOutputData'].split(";")
                    for obj in outputlist:
                        if obj.lower().count("_gen_"):
                            self.OutputFile = os.path.basename(obj)
                            break
                else:
                    #This is because most likely there is stdhepcut running after
                    self.OutputFile = "willcut.stdhep"

                    #getProdFilename(self.OutputFile,int(self.workflow_commons["PRODUCTION_ID"]),
                    #                                  int(self.workflow_commons["JOB_ID"]))

        if "IS_DBD_GEN_PROD" in self.workflow_commons and self.workflow_commons[
                "IS_DBD_GEN_PROD"]:
            #self.OutputFile = getProdFilename(self.OutputFile,int(self.workflow_commons["PRODUCTION_ID"]),
            #                                  int(self.workflow_commons["JOB_ID"]))
            if 'ProductionOutputData' in self.workflow_commons:
                outputlist = self.workflow_commons[
                    'ProductionOutputData'].split(";")
                for obj in outputlist:
                    self.OutputFile = os.path.basename(obj)
                    break
            else:
                self.OutputFile = getProdFilename(
                    self.OutputFile,
                    int(self.workflow_commons["PRODUCTION_ID"]),
                    int(self.workflow_commons["JOB_ID"]))
        return S_OK()

    def runIt(self):
        """ Called by Agent
    
    Executes the following
      - resolve input variables
      - resolve installation location
      - resolve dependencies location (beam_spectra)
      - get processlist if needed
      - define output file name
      - prepare whizard.in
      - make magic
      
    :return: S_OK(), S_ERROR()
    """
        self.result = S_OK()
        if not self.platform:
            self.result = S_ERROR('No ILC platform selected')
        elif not self.applicationLog:
            self.result = S_ERROR('No Log file provided')
        if not self.result['OK']:
            self.log.error("Failed to resolve input parameters:",
                           self.result["Message"])
            return self.result

        if not self.workflowStatus['OK'] or not self.stepStatus['OK']:
            self.log.verbose(
                'Workflow status = %s, step status = %s' %
                (self.workflowStatus['OK'], self.stepStatus['OK']))
            return S_OK(
                'Whizard should not proceed as previous step did not end properly'
            )

        #if self.debug:
        #  self.excludeAllButEventString = False

        res = getSoftwareFolder(self.platform, self.applicationName,
                                self.applicationVersion)
        if not res['OK']:
            self.log.error("Failed getting software folder", res['Message'])
            self.setApplicationStatus('Failed finding software')
            return res
        mySoftDir = res['Value']

        ###Remove libc
        removeLibc(mySoftDir + "/lib")

        ##Need to fetch the new LD_LIBRARY_PATH
        new_ld_lib_path = getNewLDLibs(self.platform, self.applicationName,
                                       self.applicationVersion)
        #Don't forget to prepend the application's libs
        new_ld_lib_path = mySoftDir + "/lib:" + new_ld_lib_path
        ### Resolve dependencies (look for beam_spectra)
        deps = resolveDeps(self.platform, self.applicationName,
                           self.applicationVersion)
        path_to_beam_spectra = ""
        path_to_gridfiles = ""
        for dep in deps:
            res = getSoftwareFolder(self.platform, dep["app"], dep['version'])
            if not res['OK']:
                self.log.error("Failed getting software folder",
                               res['Message'])
                self.setApplicationStatus('Failed finding software')
                return res
            depfolder = res['Value']
            if dep["app"] == "beam_spectra":
                path_to_beam_spectra = depfolder
            elif dep["app"] == "gridfiles":
                path_to_gridfiles = depfolder

        ##Env variables needed to run whizard: avoids hard coded locations
        os.environ['LUMI_LINKER'] = path_to_beam_spectra + "/lumi_linker_000"
        os.environ[
            'PHOTONS_B1'] = path_to_beam_spectra + "/photons_beam1_linker_000"
        os.environ[
            'PHOTONS_B2'] = path_to_beam_spectra + "/photons_beam2_linker_000"
        os.environ['EBEAM'] = path_to_beam_spectra + "/ebeam_in_linker_000"
        os.environ['PBEAM'] = path_to_beam_spectra + "/pbeam_in_linker_000"

        os.environ[
            'LUMI_EE_LINKER'] = path_to_beam_spectra + "/lumi_ee_linker_000"
        os.environ[
            'LUMI_EG_LINKER'] = path_to_beam_spectra + "/lumi_eg_linker_000"
        os.environ[
            'LUMI_GE_LINKER'] = path_to_beam_spectra + "/lumi_ge_linker_000"
        os.environ[
            'LUMI_GG_LINKER'] = path_to_beam_spectra + "/lumi_gg_linker_000"

        list_of_gridfiles = []
        if path_to_gridfiles and self.useGridFiles:
            tmp_list_of_gridfiles = [
                os.path.join(path_to_gridfiles, item)
                for item in os.listdir(path_to_gridfiles)
            ]
            gridfilesfound = False
            for path in tmp_list_of_gridfiles:
                if os.path.isdir(path) and path.count(str(self.energy)):
                    #Here look for a sub directory for the energy related grid files
                    list_of_gridfiles = [
                        os.path.join(path, item) for item in os.listdir(path)
                    ]
                    gridfilesfound = True
                    self.log.info('Found grid files specific for energy %s' %
                                  self.energy)
                    break
            if not gridfilesfound:
                self.log.info(
                    "Will use generic grid files found, hope the energy is set right"
                )
                list_of_gridfiles = [
                    item for item in
                    glob.glob(os.path.join(path_to_gridfiles, "*.grb")) +
                    glob.glob(os.path.join(path_to_gridfiles, "*.grc"))
                ]

        template = False
        if self.SteeringFile.count("template"):
            template = True
        ## Get from process file the proper whizard.in file
        if self.getProcessInFile:
            whizardin = ""
            res = self.obtainProcessList()
            if not res['OK']:
                self.log.error("Could not obtain process list")
                self.setApplicationStatus('Failed getting processlist')
                return res
            whizardin = self.processlist.getInFile(self.evttype)
            if not whizardin:
                self.log.error(
                    "Whizard input file was not found in process list, cannot proceed"
                )
                self.setApplicationStatus('Whizard input file was not found')
                return S_ERROR("Error while resolving whizard input file")
            if whizardin.count("template"):
                template = True
            try:
                shutil.copy("%s/%s" % (mySoftDir, whizardin),
                            "./whizardnew.in")
                self.SteeringFile = "whizardnew.in"
            except EnvironmentError:
                self.log.error("Could not copy %s from %s" %
                               (whizardin, mySoftDir))
                self.setApplicationStatus('Failed getting whizard.in file')
                return S_ERROR("Failed to obtain %s" % whizardin)

        ##Check existence of Les Houches input file
        leshouchesfiles = ''
        if not os.path.exists("LesHouches.msugra_1.in"):
            if self.susymodel:
                if self.susymodel == 1:
                    if os.path.exists("%s/LesHouches_slsqhh.msugra_1.in" %
                                      (mySoftDir)):
                        leshouchesfiles = "%s/LesHouches_slsqhh.msugra_1.in" % (
                            mySoftDir)
                if self.susymodel == 2:
                    if os.path.exists("%s/LesHouches_chne.msugra_1.in" %
                                      (mySoftDir)):
                        leshouchesfiles = "%s/LesHouches_chne.msugra_1.in" % (
                            mySoftDir)
            if self.Model:
                if self.genmodel.hasModel(self.Model)['OK']:
                    if self.genmodel.getFile(self.Model)['OK']:
                        if os.path.exists(
                                "%s/%s" %
                            (mySoftDir, self.genmodel.getFile(
                                self.Model)['Value'])):
                            leshouchesfiles = "%s/%s" % (
                                mySoftDir, self.genmodel.getFile(
                                    self.Model)['Value'])
                        else:
                            self.log.error(
                                "Request LesHouches file is missing, cannot proceed"
                            )
                            self.setApplicationStatus(
                                "LesHouches file missing")
                            return S_ERROR(
                                "The LesHouches file was not found. Probably you are using a wrong version of whizard."
                            )
                    else:
                        self.log.warn("No file found attached to model %s" %
                                      self.Model)
                else:
                    self.log.error("Model undefined:", self.Model)
                    self.setApplicationStatus("Model undefined")
                    return S_ERROR("No Model %s defined" % self.Model)
        else:
            leshouchesfiles = "LesHouches.msugra_1.in"

        outputfilename = self.evttype

        if self.optionsdict:
            self.log.info("Using: %s" % self.optionsdict)
            self.options = WhizardOptions(self.Model)
            res = self.options.changeAndReturn(self.optionsdict)
            if not res['OK']:
                return res
            res = self.options.toWhizardDotIn("whizard.in")
        elif not template:
            res = prepareWhizardFile(self.SteeringFile, outputfilename,
                                     self.energy, self.RandomSeed,
                                     self.NumberOfEvents, self.Lumi,
                                     "whizard.in")
        else:
            res = prepareWhizardFileTemplate(self.SteeringFile, outputfilename,
                                             self.parameters, "whizard.in")
        if not res['OK']:
            self.log.error('Something went wrong with input file generation')
            self.setApplicationStatus(
                'Whizard: something went wrong with input file generation')
            return S_ERROR(
                'Something went wrong with whizard.in file generation')
        foundproceesinwhizardin = res['Value']

        scriptName = 'Whizard_%s_Run_%s.sh' % (self.applicationVersion,
                                               self.STEP_NUMBER)
        if os.path.exists(scriptName):
            os.remove(scriptName)
        script = open(scriptName, 'w')
        script.write('#!/bin/sh \n')
        script.write(
            '#####################################################################\n'
        )
        script.write(
            '# Dynamically generated script to run a production or analysis job. #\n'
        )
        script.write(
            '#####################################################################\n'
        )
        script.write('declare -x PATH=%s:$PATH\n' % mySoftDir)
        script.write('declare -x LD_LIBRARY_PATH=%s\n' % new_ld_lib_path)
        script.write('env | sort >> localEnv.log\n')
        script.write('echo =============================\n')
        script.write('echo Printing content of whizard.in \n')
        script.write('cat whizard.in\n')
        script.write('echo =============================\n')
        script.write('cp  %s/whizard.mdl ./\n' % mySoftDir)
        if leshouchesfiles:
            if not leshouchesfiles == 'LesHouches.msugra_1.in':
                script.write('cp %s ./LesHouches.msugra_1.in\n' %
                             (leshouchesfiles))
            script.write('ln -s LesHouches.msugra_1.in fort.71\n')
        if len(list_of_gridfiles):
            for gridfile in list_of_gridfiles:
                script.write('cp %s ./\n' % (gridfile))
        script.write('cp %s/whizard.prc ./\n' % mySoftDir)
        if self.genlevelcuts:
            res = self.makeWhizardDotCut1()
            if not res['OK']:
                script.close()
                self.log.error("Could not create the cut1 file")
                return S_ERROR("Could not create the cut1 file")
        script.write('echo =============================\n')
        script.write('echo Printing content of whizard.prc \n')
        script.write('cat whizard.prc\n')
        script.write('echo =============================\n')
        extracmd = ""
        if not self.debug:
            extracmd = "2>/dev/null"

        comm = ""
        if foundproceesinwhizardin:
            comm = 'whizard --simulation_input \'write_events_file = \"%s\"\'' % (
                outputfilename)
        else:
            comm = 'whizard --process_input \'process_id =\"%s\"\' --simulation_input \'write_events_file = \"%s\"\' ' % (
                self.evttype, outputfilename)
        comm = "%s %s %s\n" % (comm, self.extraCLIarguments, extracmd)
        self.log.info("Will run %s" % comm)
        script.write(comm)
        script.write('declare -x appstatus=$?\n')
        script.write('exit $appstatus\n')

        script.close()
        if os.path.exists(self.applicationLog):
            os.remove(self.applicationLog)
        os.chmod(scriptName, 0755)
        comm = 'sh -c "./%s"' % (scriptName)
        self.setApplicationStatus('Whizard %s step %s' %
                                  (self.applicationVersion, self.STEP_NUMBER))
        self.stdError = ''
        self.result = shellCall(0,
                                comm,
                                callbackFunction=self.redirectLogOutput,
                                bufferLimit=209715200)
        #self.result = {'OK':True,'Value':(0,'Disabled Execution','')}
        if not self.result['OK']:
            self.log.error("Failed with error %s" % self.result['Message'])
        if not os.path.exists(self.applicationLog):
            self.log.error(
                "Something went terribly wrong, the log file is not present")
            self.setApplicationStatus('%s failed terribly, you are doomed!' %
                                      (self.applicationName))
            if not self.ignoreapperrors:
                return S_ERROR('%s did not produce the expected log' %
                               (self.applicationName))
        lumi = ''
        message = ""
        success = False
        ###Analyse log file
        with open(self.applicationLog) as logfile:
            for line in logfile:
                if line.count('! Event sample corresponds to luminosity'):
                    elems = line.split()
                    lumi = elems[-1]
                if line.count("*** Fatal error:"):
                    status = 1
                    message = line
                    break
                elif line.count("PYSTOP"):
                    status = 1
                    message = line
                    break
                elif line.count("No matrix element available"):
                    status = 1
                    message = line
                    break
                elif line.count("Floating point exception"):
                    status = 1
                    message = line
                    break
                elif line.count("Event generation finished."):
                    success = True
                else:
                    status = 0
        if success:
            status = 0
        else:
            status = 1
        self.log.info(
            'The sample generated has an equivalent luminosity of %s' % lumi)
        if lumi:
            self.workflow_commons['Luminosity'] = float(lumi)
        else:
            status = 1

        ##Now care for the cross sections
        info = {}
        res = self.options.getAsDict()
        if os.path.exists("whizard.out") and res['OK']:
            full_opts_dict = res['Value']
            processes = full_opts_dict['process_input']['process_id'].split()
            info = {}
            info['xsection'] = {}
            processes.append('sum')
            with open("whizard.out", "r") as inf:
                for line in inf:
                    line = line.rstrip()
                    for process in processes:
                        if not process:
                            continue
                        if line.count("   %s            " % process):
                            info['xsection'][process] = {}
                            line = line.lstrip()
                            crosssection = line.split()[1]
                            err_crosssection = line.split()[2]
                            frac = line.split()[4]
                            info['xsection'][process]['xsection'] = float(
                                crosssection)
                            info['xsection'][process]['err_xsection'] = float(
                                err_crosssection)
                            info['xsection'][process]['fraction'] = float(frac)

        if info:
            if 'Info' not in self.workflow_commons:
                self.workflow_commons['Info'] = info
            else:
                self.workflow_commons['Info'].update(info)

        self.log.info("Status after the application execution is %s" %
                      str(status))

        messageout = 'Whizard %s Successful' % (self.applicationVersion)
        failed = False
        if status != 0:
            self.log.error("Whizard execution completed with errors:")
            failed = True
        else:
            self.log.info("Whizard execution completed successfully")
            ###Deal with output file
            if len(self.OutputFile):
                if os.path.exists(outputfilename + ".001.stdhep"):
                    self.log.notice("Looking for output files")
                    ofnames = glob.glob(outputfilename + '*.stdhep')
                    if len(ofnames) > 1:
                        basename = self.OutputFile.split(".stdhep")[0]
                        i = 0
                        for of in ofnames:
                            i += 1
                            name = basename + "_" + str(i) + ".stdhep"
                            os.rename(of, name)
                    else:
                        os.rename(outputfilename + ".001.stdhep",
                                  self.OutputFile)
                else:
                    self.log.error(
                        "Whizard execution did not produce a stdhep file")
                    self.setApplicationStatus(
                        'Whizard %s Failed to produce STDHEP file' %
                        (self.applicationVersion))
                    messageout = 'Whizard Failed to produce STDHEP file'
                    if not self.ignoreapperrors:
                        return S_ERROR(messageout)

        if failed is True:
            self.log.error("==================================\n StdError:\n")
            self.log.error(message)
            self.setApplicationStatus('%s Exited With Status %s' %
                                      (self.applicationName, status))
            self.log.error('Whizard Exited With Status %s' % (status))
            messageout = 'Whizard Exited With Status %s' % (status)
            if not self.ignoreapperrors:
                return S_ERROR(messageout)
        else:
            self.setApplicationStatus(messageout)
        return S_OK({"OutputFile": self.OutputFile})

    def makeWhizardDotCut1(self):
        """ When users need whizard cuts, this is called to prepare the file

    :return: S_OK()
    """
        cutf = open("whizard.cut1", "w")
        for key, values in self.genlevelcuts.items():
            cutf.write("process %s\n" % key)
            for val in values:
                cutf.write("  %s\n" % val)
        cutf.close()
        return S_OK()
Пример #3
0
class WhizardOptions(object):
  """ Class that provides an interface to the xml representation of the whizard options.
  """
  def __init__(self, model = "sm"):
    """
    :param string model: physics model to be used by whizard, default "sm"
    """

    self.genmodel = GeneratorModels()
    self.paramdict = {}
    modelparams = self.modelParams(model)
    self.whizardxml = fromstring("""<whizard>
<process_input>
<process_id type="string" value="">
<!-- Process tag(s) as defined in whizard.prc. It should contain the list of processes to activate, separated by commas or blanks, enclosed in quotes. -->
</process_id>
<cm_frame type="T/F" value="T">
<!-- if true, the c.m. frame is the lab frame, the beams are in +/- z directions, and the total c.m. energy is given by sqrts. If false, the beam energies and directions must be specified below in the blocks beam_input. -->
</cm_frame>
<sqrts type="float" value="3000">
<!-- If this number is greater than the sum of the incoming particle masses, it specifies the c.m. energy of the initial state in GeV. Applies only if cm_frame is true, and is ignored for decay processes. -->
</sqrts>
<luminosity type="float" value="0">
<!-- Integrated luminosity in fb-1 -->
</luminosity>
<polarized_beams type="T/F" value="T">
<!-- If true, the helicity content of the beams must be specified below in the blocks beam_input. -->
</polarized_beams>
<structured_beams type="T/F" value="T">
<!-- If true, the nature of the incoming beams must be specified below in the blocks beam_input. -->
</structured_beams>
<beam_recoil type="T/F" value="F">
<!-- If true, and if structure functions (e.g., ISR) are selected, the recoil of the partons against the beam remnant (e.g., the emitted photons) is taken into account. The pT distribution is computed within the approximation valid for the emission, hence it will be accurate at low pT. -->
</beam_recoil>
<recoil_conserve_momentum type="T/F" value="F">
<!-- Applies only if beam_recoil is set: if true, keep momentum balance between parton and recoil momenta at the expense of energy balance. If false, keep energy balance at the expense of momentum balance. -->
</recoil_conserve_momentum>
<filename type="string" value="whizard">
<!-- Base filename (w/o extension) to be used for all input/output files instead of the string "whizard". -->
</filename>
<directory type="string" value="">
<!-- Working directory for all further reading/writing of files. -->
</directory>
<input_file type="string" value="">
<!-- If nonempty, read the specified input file after the current one. The extension .in will be appended to the filename. -->
</input_file>
<input_slha_format type="T/F" value="F">
<!-- If true, assume that the next input file is in SUSY Les Houches Accord format (see Sec. 4.4.7). If false, determine the format from the first line. -->
</input_slha_format>
</process_input>
<integration_input>
<calls type="floatarray" value="1 50000 10 50000 1 1500000">
<!-- Array describing the number of iterations and number of calls per integration pass. Default values depend on the selected process. See below in subsection 4.6 for details. -->
</calls>
<seed type="integer" value="">
<!-- Random number generator seed (integer). When omitted, the time counter will be used, resulting in a different value each run. -->
</seed>
<reset_seed_each_process type="T/F" value="F">
<!-- Reset the random number generator seed to seed not just once, but each time a process is integrated. This is useful for comparing matrix elements which should be identical, but, e.g., have been generated by different programs. -->
</reset_seed_each_process>
<accuracy_goal type="float" value="0">
<!-- Goal for the accuracy estimate (6th column in the output). When this goal is reached and the efficiency goal is either also reached or unset, further grid adaptation iterations will be skipped (Sec. 4.9). -->
</accuracy_goal>
<efficiency_goal type="float" value="100">
<!-- Goal for the reweighting efficiency estimate (7th column in the output). When this goal is reached and the accuracy goal is either also reached or unset, further grid adaptation iterations will be skipped (Sec. 4.9). -->
</efficiency_goal>
<time_limit_adaptation type="integer" value="0">
<!-- If nonzero, grid adaptation for the current process will be stopped after the specified number of minutes, and the final integration pass started (Sec. 4.9). -->
</time_limit_adaptation>
<stratified type="T/F" value="T">
<!-- Use stratified (T) / importance (F) sampling. -->
</stratified>
<use_efficiency type="T/F" value="F">
<!-- Use efficiency (T) / accuracy (F) as the criterion for adapting the channel weights. -->
</use_efficiency>
<weights_power type="float" value="0.25">
<!-- Power used for adapting the channel weights. Lower value means slower adaptation (to suppress fluctuations). -->
</weights_power>
<min_bins type="integer" value="3">
<!-- Minimal number of bins per integration dimension. -->
</min_bins>
<max_bins type="integer" value="20">
<!-- Maximal number of bins per integration dimension. This number will be used as long as there are enough sampling points, otherwise the number of bins will be decreased. -->
</max_bins>
<min_calls_per_bin type="integer" value="10">
<!-- Minimal number of points per bin, integration dimension, and integration channel. If this limit cannot be satisfied, the total number of points will be increased. -->
</min_calls_per_bin>
<min_calls_per_channel type="integer" value="0">
<!-- All integration channel will get at least (approximately) this number of points. Prevents channels from being dropped during adaptation. -->
</min_calls_per_channel>
<write_grids type="T/F" value="T">
<!-- Write grids to files whizard.grb (best grid) and whizard.grc (current grid), to be reused later. -->
</write_grids>
<write_grids_raw type="T/F" value="F">
<!-- Use binary format for writing grids. Saves memory at the expense of portability. -->
</write_grids_raw>
<write_grids_file type="string" value="">
<!-- If nonempty, use the specified filename for writing grids instead of the default. The file extensions are appended to string. -->
</write_grids_file>
<write_all_grids type="T/F" value="F">
<!-- Write, in addition, after each iteration the current grid to file whizard.grXX, where XX is the iteration number. -->
</write_all_grids>
<write_all_grids_file type="string" value="">
<!-- If nonempty, use the specified filename for writing the extra grids instead of the default. The file extensions are appended to string. -->
</write_all_grids_file>
<read_grids type="T/F" value="F">
<!-- Read existing grids whizard.grb and whizard.grc if they have been written by a previous run. This avoids the time-consuming adaptation step. Makes sense only if no physical parameters have been changed. -->
</read_grids>
<read_grids_raw type="T/F" value="F">
<!-- If true, search first for binary grid files, then for ASCII grids. If false, do search first for ASCII.. -->
</read_grids_raw>
<read_grids_force type="T/F" value="T">
<!-- Set this to T if you want to read the grids from file even if some parameters have changed. Use with care! This may result in a program crash if the grid structures are incompatible. -->
</read_grids_force>
<read_grids_file type="string" value="">
<!-- If nonempty, use the specified filename for reading grids instead of the default. The file extensions are appended to string. -->
</read_grids_file>
<generate_phase_space type="T/F" value="T">
<!-- Generate a phase space configuration appropriate for the current process and write it to whizard.phx. -->
</generate_phase_space>
<read_model_file type="string" value="">
<!-- If nonempty, read vertex definitions for phase space setup from string.mdl instead of the default whizard.mdl. -->
</read_model_file>
<write_phase_space_file type="string" value="">
<!-- Write phase space configuration to string.phx instead of the default. -->
</write_phase_space_file>
<read_phase_space type="T/F" value="T">
<!-- Read phase space configuration from whizard.phs or a previously generated file whizard.phx if possible. -->
</read_phase_space>
<read_phase_space_file type="string" value="">
<!-- Read phase space configuration from string.phs or string.phx instead of the default. -->
</read_phase_space_file>
<phase_space_only type="T/F" value="F">
<!-- Stop the program after phase space generation. -->
</phase_space_only>
<use_equivalences type="T/F" value="T">
<!-- If true, use permutation symmetry when updating grids to improve the quality of the results. -->
</use_equivalences>
<azimuthal_dependence type="T/F" value="F">
<!-- If false, it is assumed that the scattering does not depend on the overall azimuthal angle. This will be automatically T if general beam polarization is switched on, therefore the user need only access this parameter in the case of azimuthal-dependent cuts. -->
</azimuthal_dependence>
<write_phase_space_channels_file type="string" value="">
<!-- Show phase space channels in string.ps instead of the default file whizard-channels.ps. Note that you need to call CHANNELS= string make -e channels in order to generate string.ps -->
</write_phase_space_channels_file>
<off_shell_lines type="integer" value="1">
<!-- Maximum number of off-shell-lines allowed for Feynman graphs which are initially taken into account for the phase space configuration. Log-enhanced (massless) propagators are not counted as off-shell. -->
</off_shell_lines>
<extra_off_shell_lines type="integer" value="1">
<!-- Use configurations with more off-shell lines, if they happen to be maximally resonant. -->
</extra_off_shell_lines>
<splitting_depth type="integer" value="1">
<!-- Up to this number of branchings, a (massless) propagator will be considered as log-enhanced and mapped like a photon propagator. -->
</splitting_depth>
<exchange_lines type="integer" value="3">
<!-- Up to this number of t-channel propagators, a multiperipheral graph will be taken into account. -->
</exchange_lines>
<show_deleted_channels type="T/F" value="F">
<!-- With extra_off_shell_lines, extra channels will be generated which are deleted if they do not contain enough resonances. With this flag, they are just commented out, so they could be manually activated. -->
</show_deleted_channels>
<single_off_shell_decays type="T/F" value="T">
<!-- Whether single-off-shell decays are relevant for the phase space configuration. -->
</single_off_shell_decays>
<double_off_shell_decays type="T/F" value="F">
<!-- Whether double-off-shell decays are relevant for the phase space configuration. -->
</double_off_shell_decays>
<single_off_shell_branchings type="T/F" value="T">
<!-- Whether single-off-shell branchings are relevant for the phase space configuration. -->
</single_off_shell_branchings>
<double_off_shell_branchings type="T/F" value="T">
<!-- Whether double-off-shell branchings are relevant for the phase space configuration. -->
</double_off_shell_branchings>
<massive_fsr type="T/F" value="T">
<!-- Whether the radiation of a massive particle in the final state is relevant for the phase space configuration. -->
</massive_fsr>
<threshold_mass type="float" value="-10">
<!-- A particle with a mass up to this value will be considered as massless for the purpose of phase-space setup. (But the true mass is taken into account when the particle appears as a resonant intermediate state.) -->
</threshold_mass>
<threshold_mass_t type="float" value="-10">
<!-- A particle with a mass up to this value will be considered as massless for the purpose of phase-space setup, when it appears as a t-channel propagator. -->
</threshold_mass_t>
<!-- <initial_decays_fatal type="T/F" value="T"> -->
<!-- As the phase space maps cannot describe on-shell decays of beam particles properly, WHIZARD normally gives a fatal error when such configurations are encountered. This option changes this to a warning at the price of a potentially screwed phase space setup. -->
<!-- </initial_decays_fatal> -->
<default_jet_cut type="float" value="10">
<!-- The default invariant mass cut in GeV applied to pairs of massless colored particles. -->
</default_jet_cut>
<default_mass_cut type="float" value="4">
<!-- The default invariant mass cut in GeV applied to pair production of massless colorless charged particles and to photon emission. -->
</default_mass_cut>
<default_energy_cut type="float" value="10">
<!-- The default energy cut in GeV applied to photon and gluon emission. -->
</default_energy_cut>
<default_q_cut type="float" value="4">
<!-- The default Q cut in GeV applied to photon and gluon exchange. -->
</default_q_cut>
<write_default_cuts_file type="string" value="">
<!-- If nonempty, write the list of default cuts to this file (augmented by the file extension) instead of the default. Note that the settings in this file are overwritten by a user-defined cut configuration, if present. -->
</write_default_cuts_file>
<read_cuts_file type="string" value="">
<!-- Look for user-defined cut configurations in string.cut1 instead of whizard.cut1. -->
</read_cuts_file>
<user_cut_mode type="integer" value="0">
<!-- Set this nonzero to activate a user-defined cut function (Sec. 5.4). -->
</user_cut_mode>
<user_weight_mode type="integer" value="0">
<!-- Set this nonzero to activate a user-defined weight function (Sec. 5.5). -->
</user_weight_mode>
</integration_input>
<simulation_input>
<n_events type="integer" value="0">
<!-- Number of (unweighted) events to generate at least, irrespective of the luminosity setting. -->
</n_events>
<n_calls type="integer" value="0">
<!-- Number of matrix-element calls (weighted events) to execute at least, irrespective of the luminosity setting. -->
</n_calls>
<n_events_warmup type="integer" value="0">
<!-- Number of extra warmup events (see below, Sec. 4.7). -->
</n_events_warmup>
<unweighted type="T/F" value="T">
<!-- Reweight events to generate an unweighted event sample. -->
</unweighted>
<normalize_weight type="T/F" value="T">
<!-- If true, normalize the event weight to unity. If false, normalize to the total cross section. -->
</normalize_weight>
<write_weights type="T/F" value="F">
<!-- If unweighted=F, write weight distribution data to whizard.wgt. -->
</write_weights>
<write_weights_file type="string" value="">
<!-- Write weight distribution to string.wgt instead. -->
</write_weights_file>
<safety_factor type="float" value="1">
<!-- Multiply the estimate for the highest weight by this factor before starting event generation. -->
</safety_factor>
<write_events type="T/F" value="T">
<!-- Write generated events to file whizard.evt to be used by an external analysis package. -->
</write_events>
<write_events_format type="integer" value="20">
<!-- The format to be used for writing events, where the file extension depends on the format (.evt for format = 1, see Sec. 4.7). -->
</write_events_format>
<write_events_file type="string" value="">
<!-- If nonempty, use string as filename for writing events, where the file extension will be appended. -->
</write_events_file>
<events_per_file type="integer" value="5000000">
<!-- If positive, begin a new event file once the number of entries exceeds this number. The event file counter is appended to each event file name, separated with a dot (before the file extension). This feature applies only to non-binary event formats. -->
</events_per_file>
<bytes_per_file type="integer" value="0">
<!-- If positive, begin a new event file once the number of bytes in the file exceeds this number. The event file counter is appended to each event file name, separated with a dot (before the file extension). This feature applies only to non-binary event formats. See Sec. 4.7.1. -->
</bytes_per_file>
<min_file_count type="integer" value="1">
<!-- If event files are split, use this index for the first event file. Increase the counter by one for each successive event file. -->
</min_file_count>
<max_file_count type="integer" value="999">
<!-- Limit for the event file counter; if this limit is exceeded, event generation is terminated. (For weighted events only, this is an error condition since the event sample must be complete for being usable.) -->
</max_file_count>
<write_events_raw type="T/F" value="F">
<!-- Write events to whizard.evx in condensed binary format, so they can be internally reused in another run. -->
</write_events_raw>
<write_events_raw_file type="string" value="">
<!-- Write raw events to string.evx instead. -->
</write_events_raw_file>
<read_events type="T/F" value="F">
<!-- Read events from file whizard.evx (raw format) instead of generating them. This is equivalent to read_events_raw. -->
</read_events>
<read_events_force type="T/F" value="T">
<!-- This was intended to force WHIZARD to read in events from file even if some parameters have changed. However, the MD5 checksum implemented to check for parameter changes has some deficiencies. Hence, we always enforce to read in events, because this feature could otherwise not be used at all. Use with great care! (Note that this problem has been solved in WHIZARD 2.) -->
</read_events_force>
<read_events_raw_file type="string" value="">
<!-- Read raw events from string.evx instead. -->
</read_events_raw_file>
<keep_beam_remnants type="T/F" value="T">
<!-- Keep the beam remnants in the event record when applying structure functions. See Sec. 4.4.8. -->
</keep_beam_remnants>
<keep_initials type="T/F" value="T">
<!-- Keep the beam particles and the partons which initiate the hard scattering in the event record. See Sec. 4.4.8. -->
</keep_initials>
<guess_color_flow type="T/F" value="F">
<!-- Infer the color flow for hadronization from the particle ordering, if it is nontrivial and not available directly. -->
</guess_color_flow>
<recalculate type="T/F" value="F">
<!-- Recalculate the matrix element value for each event of a previously generated sample. Setting this flag automatically turns on reading grids and events from file. -->
</recalculate>
<fragment type="T/F" value="T">
<!-- Fragment the events depending on the value of fragmentation_method (see Sec. 4.8). -->
</fragment>
<fragmentation_method type="integer" value="3">
<!-- Method used for fragmentation if fragment is true: 0=no fragmentation; 1=JETSET; 2=PYTHIA; 3=user. -->
</fragmentation_method>
<user_fragmentation_mode type="integer" value="0">
<!-- When user-defined fragmentation routines are called, this parameter may select different modes. -->
</user_fragmentation_mode>
<pythia_parameters type="string" value="PMAS(25,1)=120.; PMAS(25,2)=0.3605E-02; MSTU(22)=20 ;MSTJ(28)=2 ;PARJ(21)=0.40000;PARJ(41)=0.11000; PARJ(42)=0.52000; PARJ(81)=0.25000; PARJ(82)=1.90000; MSTJ(11)=3; PARJ(54)=-0.03100; PARJ(55)=-0.00200;PARJ(1)=0.08500; PARJ(3)=0.45000; PARJ(4)=0.02500; PARJ(2)=0.31000; PARJ(11)=0.60000; PARJ(12)=0.40000; PARJ(13)=0.72000;PARJ(14)=0.43000; PARJ(15)=0.08000; PARJ(16)=0.08000; PARJ(17)=0.17000; MSTP(3)=1;">
<!-- String to be given to PYTHIA's pygive call before starting event generation. This allows to modify PYTHIA/JETSET properties, set particle masses, etc. The string is also available within user-defined fragmentation routines and can there be abused for different purposes. -->
</pythia_parameters>
<pythia_processes type="string" value="">
<!-- PYTHIA background processes to be simulated in addition to the WHIZARD processes: A list of integers separated by blanks, enclosed in quotation marks. Refer to the PYTHIA manual for the list of processes. -->
</pythia_processes>
<shower type="T/F" value="F">
<!-- Switches the internal shower on or off. As a default it is off. Note that the shower only works with LHEF event format (foramt type 6). This shower is highly experimental. Mainly intended for testing purposes. -->
</shower>
<shower_nf type="integer" value="5">
<!-- Number of light flavors in the shower. -->
</shower_nf>
<shower_running_alpha_s type="T/F" value="F">
<!-- Whether to use a running strong coupling alpha_s or not in the shower. As a default it is fixed. -->
</shower_running_alpha_s>
<shower_alpha_s type="float" value="0.2">
<!-- The value of the strong coupling constant alpha_s as used by the internal shower. The default is 0.2. -->
</shower_alpha_s>
<shower_lambda type="float" value="0.29">
<!-- The value of the QCD scale Lambda_QCD as used by the internal shower. The default is 0.29 GeV. -->
</shower_lambda>
<shower_t_min type="float" value="1.0">
<!-- The infrared cutoff for the evolution parameter tmin as used by the internal shower. The default is 1 GeV. -->
</shower_t_min>
<shower_md type="float" value="0.330">
<!-- The constituent d quark mass md as used by the internal shower. The default is 0.330 GeV. -->
</shower_md>
<shower_mu type="float" value="0.330">
<!-- The constituent u quark mass mu as used by the internal shower. The default is 0.330 GeV. -->
</shower_mu>
<shower_ms type="float" value="0.500">
<!-- The constituent s quark mass ms as used by the internal shower. The default is 0.5 GeV. -->
</shower_ms>
<shower_mc type="float" value="1.5">
<!-- The constituent c quark mass mc as used by the internal shower. The default is 1.5 GeV. -->
</shower_mc>
<shower_mb type="float" value="4.8">
<!-- The constituent b quark mass mb as used by the internal shower. The default is 4.8 GeV.diagnostics_input -->
</shower_mb>
</simulation_input>
<diagnostics_input>
<chattiness type="integer" value="4">
<!-- How much information to show on screen: (0) only fatal errors, (1) and non-fatal errors, (2) and warnings, (3) and messages, (4) and results, (5) and debugging messages (if any). -->
</chattiness>
<catch_signals type="T/F" value="T">
<!-- If the compiler supports it, try to catch external signals such as SIGINT and SIGXCPU and exit gracefully, closing files first. -->
</catch_signals>
<time_limit type="integer" value="0"> -->
<!-- If nonzero, exit gracefully after the given number of minutes has passed. This is useful to prevent an external kill within a batch environment. -->
</time_limit>
<warn_empty_channel type="T/F" value="F">
<!-- Issue a warning whenever the integral within a phase space channel is zero. -->
</warn_empty_channel>
<screen_events type="T/F" value="F">
<!-- Whether to show generated events on screen. -->
</screen_events>
<screen_histograms type="T/F" value="F">
<!-- Whether to show histograms on screen. -->
</screen_histograms>
<screen_diagnostics type="T/F" value="F">
<!-- Whether to repeat the input parameters on screen. -->
</screen_diagnostics>
<show_pythia_banner type="T/F" value="T">
<!-- Whether to display the PYTHIA banner page if fragmentation is enabled. -->
</show_pythia_banner>
<show_pythia_initialization type="T/F" value="T">
<!-- Whether to display the PYTHIA initialization messages if fragmentation is enabled. -->
</show_pythia_initialization>
<show_pythia_statistics type="T/F" value="T">
<!-- Whether to display the PYTHIA statistics summary after event generation is completed. -->
</show_pythia_statistics>
<write_logfile type="T/F" value="T">
<!-- Whether to write the (process-specific) output file(s) whizard.XX.out. -->
</write_logfile>
<write_logfile_file type="string" value="">
<!-- Use this as the filename for the logfile. -->
</write_logfile_file>
<show_input type="T/F" value="T">
<!-- Whether to repeat the input parameters in the logfile. -->
</show_input>
<show_results type="T/F" value="T">
<!-- Whether to show the integration results in namelist format in the logfile. -->
</show_results>
<show_phase_space type="T/F" value="F">
<!-- Whether to show the phase space configuration in the logfile. -->
</show_phase_space>
<show_cuts type="T/F" value="T">
<!-- Whether to show the cut configuration in the logfile. -->
</show_cuts>
<show_histories type="T/F" value="F">
<!-- Whether to show the individual VAMP channel histories in the logfile. -->
</show_histories>
<show_history type="T/F" value="T">
<!-- Whether to show the overall VAMP history in the logfile. -->
</show_history>
<show_weights type="T/F" value="T">
<!-- Whether to show the weight adaptation in the logfile. -->
</show_weights>
<show_event type="T/F" value="F">
<!-- Whether to show the last event in the logfile. -->
</show_event>
<show_histograms type="T/F" value="F">
<!-- Whether to show histograms in the logfile. -->
</show_histograms>
<show_overflow type="T/F" value="F">
<!-- Whether to show events beyond the first or last bin in histogram listings. -->
</show_overflow>
<show_excess type="T/F" value="T">
<!-- Whether to show a summary of events with weight exceeding one. -->
</show_excess>
<read_analysis_file type="string" value="">
<!-- Use this (string.cut5) as the filename for the analysis setup instead of whizard.cut5 -->
</read_analysis_file>
<plot_width type="float" value="130">
<!-- The width in mm of the plots if online analysis is enabled. -->
</plot_width>
<plot_height type="float" value="90">
<!-- The height in mm of the plots if online analysis is enabled. -->
</plot_height>
<plot_excess type="T/F" value="T">
<!-- In the plots, display excess events in red. -->
</plot_excess>
<plot_history type="T/F" value="T">
<!-- If this is enabled, write a graphics driver file for displaying the integration history, i.e., the integral with error bars for each iteration. Use make history to generate the graphics file whizard-history.ps. -->
</plot_history>
<plot_grids_channels type="string" value="">
<!-- The string is a list of phase-space channels (integers) for which the bin distribution will be histogrammed. Use make grids to generate the graphics file whizard-grids.ps. -->
</plot_grids_channels>
<plot_grids_logscale type="float" value="10">
<!-- Use logarithmic scale for the grid plots if the bin width varies over more than this ratio. -->
</plot_grids_logscale>
<slha_rewrite_input type="T/F" value="T">
<!-- If SUSY Les Houches Accord data have been used, whether to repeat this input in the process-specific logfiles (including comments) or to rewrite it there using the data which have actually been used. -->
</slha_rewrite_input>
<slha_ignore_errors type="T/F" value="F">
<!-- If this is false, an error signaled in the SLHA input file (in the SPINFO or DCINFO block) will cause WHIZARD to stop before calculating anything. If true, such errors will be displayed, but the run continues. -->
</slha_ignore_errors>
</diagnostics_input>
%s
<beam_input_1>
<energy type="float" value="0">
<!-- If greater than the beam particle mass, this specifies the beam energy in the lab frame. Otherwise, the beam energy is set equal to the particle mass (fixed target). -->
</energy>
<angle type="float" value="0">
<!-- If direction is not set, this specifies a rotation of the beam axis in the lab frame around the positive y axis. (By default, the beam directions are along the positive/negative z axis, so a rotation by the angle pi/2 turns them into the positive/negative x axis.) If direction is set, this parameter is ignored. -->
</angle>
<direction type="floatarray" value="0 0 0">
<!-- If any component is nonzero, this vector explicitly specifies the direction of the given beam in the lab frame. -->
</direction>
<vector_polarization type="T/F" value="F">
<!-- If false (default), use the standard helicity basis (left-/right-handed). Set this flag if you need another basis, in particular transversal polarization. -->
</vector_polarization>
<polarization type="floatarray" value="0.0 0.0">
<!-- Fraction of left/right polarization (fermions, photons, gluons), resp. left/longitudinal/right polarization (massive vector bosons). If the vector polarization model is selected, the three numbers denote the polarization vector. -->
</polarization>
<particle_code type="integer" value="0">
<!-- PDG code of the incoming beam particle. -->
</particle_code>
<particle_name type="string" value="e1">
<!-- Name of the incoming beam particle. -->
</particle_name>
<USER_spectrum_on type="T/F" value="T">
<!-- Apply or not the user spectrum -->
</USER_spectrum_on>
<USER_spectrum_mode type="integer" value="11">
<!-- User spectrum -->
</USER_spectrum_mode>
<ISR_on type="T/F" value="T">
<!-- Whether to apply ISR (electron or positron beam). -->
</ISR_on>
<ISR_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</ISR_alpha>
<ISR_m_in type="float" value="0.000511">
<!-- The mass of the incoming particle. -->
</ISR_m_in>
<ISR_Q_max type="float" value="sqrts">
<!-- The hard scale which cuts off photon radiation. -->
</ISR_Q_max>
<ISR_LLA_order type="0/1/2/3" value="3">
<!-- The order of the leading-logarithmic approximation. -->
</ISR_LLA_order>
<ISR_map type="T/F" value="T">
<!-- Whether to use a mapping of the singularity at x=1 when evaluating the structure function (recommended; note that switching this off might even lead to an uncaught arithmetic exception). -->
</ISR_map>
<EPA_on type="T/F" value="F">
<!-- Whether to use the EPA spectrum (photon beam). -->
</EPA_on>
<EPA_map type="T/F" value="T">
<!-- Whether to apply a mapping to improve convergence. -->
</EPA_map>
<EPA_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</EPA_alpha>
<EPA_m_in type="float" value="0.000511">
<!-- The mass of the incoming beam particle. -->
</EPA_m_in>
<EPA_mX type="float" value="4">
<!-- The lower cutoff for the produced invariant mass. -->
</EPA_mX>
<EPA_Q_max type="float" value="4">
<!-- The upper cutoff on the virtuality of the photon (Qmax&gt;0). -->
</EPA_Q_max>
<EPA_x0 type="float" value="0">
<!-- The lower cutoff on the energy fraction of the incoming photon -->
</EPA_x0>
<EPA_x1 type="float" value="0">
<!-- The upper cutoff on the energy fraction of the incoming photon -->
</EPA_x1>
</beam_input_1>
<beam_input_2>
<energy type="float" value="0">
<!-- If greater than the beam particle mass, this specifies the beam energy in the lab frame. Otherwise, the beam energy is set equal to the particle mass (fixed target). -->
</energy>
<angle type="float" value="0">
<!-- If direction is not set, this specifies a rotation of the beam axis in the lab frame around the positive y axis. (By default, the beam directions are along the positive/negative z axis, so a rotation by the angle pi/2 turns them into the positive/negative x axis.) If direction is set, this parameter is ignored. -->
</angle>
<direction type="floatarray" value="0 0 0">
<!-- If any component is nonzero, this vector explicitly specifies the direction of the given beam in the lab frame. -->
</direction>
<vector_polarization type="T/F" value="F">
<!-- If false (default), use the standard helicity basis (left-/right-handed). Set this flag if you need another basis, in particular transversal polarization. -->
</vector_polarization>
<polarization type="floatarray" value="0.0 0.0">
<!-- Fraction of left/right polarization (fermions, photons, gluons), resp. left/longitudinal/right polarization (massive vector bosons). If the vector polarization model is selected, the three numbers denote the polarization vector. -->
</polarization>
<particle_code type="integer" value="0">
<!-- PDG code of the incoming beam particle. -->
</particle_code>
<particle_name type="string" value="E1">
<!-- Name of the incoming beam particle. -->
</particle_name>
<USER_spectrum_on type="T/F" value="T">
<!-- Apply or not the user spectrum -->
</USER_spectrum_on>
<USER_spectrum_mode type="integer" value="-11">
<!-- User spectrum -->
</USER_spectrum_mode>
<ISR_on type="T/F" value="T">
<!-- Whether to apply ISR (electron or positron beam). -->
</ISR_on>
<ISR_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</ISR_alpha>
<ISR_m_in type="float" value="0.000511">
<!-- The mass of the incoming particle. -->
</ISR_m_in>
<ISR_Q_max type="float" value="sqrts">
<!-- The hard scale which cuts off photon radiation. -->
</ISR_Q_max>
<ISR_LLA_order type="0/1/2/3" value="3">
<!-- The order of the leading-logarithmic approximation. -->
</ISR_LLA_order>
<ISR_map type="T/F" value="T">
<!-- Whether to use a mapping of the singularity at x=1 when evaluating the structure function (recommended; note that switching this off might even lead to an uncaught arithmetic exception). -->
</ISR_map>
<EPA_on type="T/F" value="F">
<!-- Whether to use the EPA spectrum (photon beam). -->
</EPA_on>
<EPA_map type="T/F" value="T">
<!-- Whether to apply a mapping to improve convergence. -->
</EPA_map>
<EPA_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</EPA_alpha>
<EPA_m_in type="float" value="0.000511">
<!-- The mass of the incoming beam particle. -->
</EPA_m_in>
<EPA_mX type="float" value="4">
<!-- The lower cutoff for the produced invariant mass. -->
</EPA_mX>
<EPA_Q_max type="float" value="4">
<!-- The upper cutoff on the virtuality of the photon (Qmax&gt;0). -->
</EPA_Q_max>
<EPA_x0 type="float" value="0">
<!-- The lower cutoff on the energy fraction of the incoming photon -->
</EPA_x0>
<EPA_x1 type="float" value="0">
<!-- The upper cutoff on the energy fraction of the incoming photon -->
</EPA_x1>
</beam_input_2>
</whizard>
"""%modelparams)
    self.getInputFiles(model)
  
  def getInputFiles(self, model):
    """ Get the proper input parameter file, usually LesHouches
    """
    if not self.paramdict.has_key('process_input'):
      self.paramdict['process_input'] = {}
    if not self.paramdict['process_input'].has_key('input_file'):
      res = self.genmodel.getFile(model) 
      if not res['OK']:
        self.paramdict['process_input']['input_file'] = ''
        self.paramdict['process_input']['input_slha_format'] = 'F'
      else:
        self.paramdict['process_input']['input_file'] = res['Value']
        self.paramdict['process_input']['input_slha_format'] = 'T'
    
    
  def modelParams(self, model):
    """ Get the model parameters
    """
    modelparams = []
    res = self.genmodel.getParamsForWhizard(model)
    if not res['OK']:
      return ""
    modelparams.append("<parameter_input>")

    modelparams.append(res['Value'])
    
    modelparams.append("</parameter_input>")
    
    return "\n".join(modelparams)
    
  def toXML(self, fname = 'whizard.xml'):
    """ Write to XML
    """
    tree = ElementTree(self.whizardxml)
    tree.write(fname)
    return S_OK()
  
  def getMainFields(self):
    """ Get the main fields
    """
    listoffields = []
    for elem in self.whizardxml.getchildren():
      listoffields.append(elem.tag)
    return S_OK(listoffields)
  
  def getOptionsForField(self, field):
    """ Get the options of a given field
    """
    options = []
    element = self.whizardxml.find(field)
    if element == None:
      return S_ERROR("Field %s does not exist" % field)
    for subelements in element.getchildren():
      options.append(subelements.tag)
    return S_OK(options)
  
  def getValue(self, field):
    """ Get the value for a given field/option
    """
    element = self.whizardxml.find(field)
    return S_OK(element.attrib['value'])  

  def changeAndReturn(self, paramdict):
    """ Update the options, and returns the modified XML object
    """
    self.paramdict.update(paramdict)
    res = self.checkFields(self.paramdict)
    if not res['OK']:
      return res
    for key, val in self.paramdict.items():
      for subkey in val.keys():
        subelement = self.whizardxml.find(key + "/" + subkey)
        subelement.attrib['value'] = val[subkey]
    return S_OK(self.whizardxml)
  
  def getAsDict(self):
    """ Get the content as dict, like the one used for setting the options
    """
    whiz_opt = {}
    for element in self.whizardxml.getchildren():
      whiz_opt[element.tag] = {}
      for item in element.getchildren():
        val = item.attrib['value']
        if type(val) == type(""):
          val = val.rstrip()
        whiz_opt[element.tag][item.tag] = val
    return S_OK(whiz_opt)
  
  def checkFields(self, paramdict):
    """ Make sure all supplied fields are exisiting somewhere
    """
    for key, val in paramdict.items():
      element = self.whizardxml.find(key)
      if element == None:
        return S_ERROR("Element %s is not in the allowed parameters" % key)
      for subkey, value in val.items():
        subelement = self.whizardxml.find(key + "/" + subkey)
        if subelement == None:
          return S_ERROR("Key %s/%s is not in the allowed parameters" % (key, subkey))
        etype = subelement.attrib['type']
        if etype == 'float':
          if not type(value) == types.FloatType and not type(value) == types.IntType:
            return S_ERROR("%s should be a float" % (key + "/" + subkey))
        elif etype == 'T/F':
          if value != 'T' and value != 'F':
            return S_ERROR("%s should be either 'T' or 'F'" % (key + "/" + subkey))
        elif etype == 'integer' or type == '0/1/2/3':
          if not type(value) == types.IntType:
            return S_ERROR("%s should be an integer" % (key + "/" + subkey))
        elif etype == 'string':
          if not type(value) in types.StringTypes:
            return S_ERROR("%s should be a string" % (key + "/" + subkey))
        elif etype == 'floatarray':
          error = False
          if not type(value) in types.StringTypes:
            error = True
          else:
            valelem = value.split()
            if len(valelem) < 2:
              error = True
          if error: 
            return S_ERROR("%s should be a string with spaces, e.g. '0 1 2 3'" % (key + "/" + subkey))
    return S_OK()
  
  def toWhizardDotIn(self, fname):
    """ Write the options to the whizard.in
    """
    lines = []
    for elem in self.whizardxml.getchildren():
      tag = elem.tag
      if tag.count("beam_input"):
        tag = "beam_input"
      lines.append("&%s" % tag)
      for subelem in elem.getchildren():
        val = subelem.get('value')
        if val == 'sqrts':
          continue
        if subelem.get('type') == 'string' :
          val = '"%s"' % val
        if val == '000':
          val = '0 0 0'
        if val == '0.0.0':
          val = '0.0 0.0'
        if val == '0..0..0':
          val = '\n 1 20000\n 10 20000\n 1 20000'
        lines.append(' %s = %s' % (subelem.tag, val))
      lines.append('/')
    of = file(fname, "w")
    of.write("\n".join(lines))
    of.write("\n")
    return S_OK(True)
  
  def fromWhizardDotIn(self, filename):
    """ Given a whizard.in, create the parameter dict used for the production definition
    """
    pdict = {}
    whizin = file(filename,"r")
    beam_input_idx = 0
    curkey = ""
    for line in whizin:
      line = line.rstrip().lstrip()
      if not line or line[0] in ["!","/"]:
        continue
      
      if line[0]=="&":
        key = line.split("&")[1].rstrip().lstrip()
        if key.count("beam_input"):
          if not beam_input_idx:
            curkey = key+"_1"
            beam_input_idx += 1
          else:
            curkey = key+"_2"
        else:
          curkey = key
        pdict[curkey] = {}
      elif line.count("="):
        elems = line.split("=")
        key = elems[0].lstrip().rstrip()
        val = str("=".join(elems[1:])).lstrip().rstrip().lstrip('"').rstrip('"')
        if not val.count("T") and not val.count("F"):
          if val.count("."):
            try:
              val = float(val)
            except:
              pass
          else:
            try:
              val = int(val)
            except:
              pass
        pdict[curkey][key] = val
    return self.changeAndReturn(pdict)
Пример #4
0
class WhizardOptions(object):
    """ Class that provides an interface to the xml representation of the whizard options.
  """
    def __init__(self, model="sm"):
        """
    :param string model: physics model to be used by whizard, default "sm"
    """

        self.genmodel = GeneratorModels()
        self.paramdict = {}
        modelparams = self.modelParams(model)
        self.whizardxml = fromstring("""<whizard>
<process_input>
<process_id type="string" value="">
<!-- Process tag(s) as defined in whizard.prc. It should contain the list of processes to activate, separated by commas or blanks, enclosed in quotes. -->
</process_id>
<cm_frame type="T/F" value="T">
<!-- if true, the c.m. frame is the lab frame, the beams are in +/- z directions, and the total c.m. energy is given by sqrts. If false, the beam energies and directions must be specified below in the blocks beam_input. -->
</cm_frame>
<sqrts type="float" value="3000">
<!-- If this number is greater than the sum of the incoming particle masses, it specifies the c.m. energy of the initial state in GeV. Applies only if cm_frame is true, and is ignored for decay processes. -->
</sqrts>
<luminosity type="float" value="0">
<!-- Integrated luminosity in fb-1 -->
</luminosity>
<polarized_beams type="T/F" value="T">
<!-- If true, the helicity content of the beams must be specified below in the blocks beam_input. -->
</polarized_beams>
<structured_beams type="T/F" value="T">
<!-- If true, the nature of the incoming beams must be specified below in the blocks beam_input. -->
</structured_beams>
<beam_recoil type="T/F" value="F">
<!-- If true, and if structure functions (e.g., ISR) are selected, the recoil of the partons against the beam remnant (e.g., the emitted photons) is taken into account. The pT distribution is computed within the approximation valid for the emission, hence it will be accurate at low pT. -->
</beam_recoil>
<recoil_conserve_momentum type="T/F" value="F">
<!-- Applies only if beam_recoil is set: if true, keep momentum balance between parton and recoil momenta at the expense of energy balance. If false, keep energy balance at the expense of momentum balance. -->
</recoil_conserve_momentum>
<filename type="string" value="whizard">
<!-- Base filename (w/o extension) to be used for all input/output files instead of the string "whizard". -->
</filename>
<directory type="string" value="">
<!-- Working directory for all further reading/writing of files. -->
</directory>
<input_file type="string" value="">
<!-- If nonempty, read the specified input file after the current one. The extension .in will be appended to the filename. -->
</input_file>
<input_slha_format type="T/F" value="F">
<!-- If true, assume that the next input file is in SUSY Les Houches Accord format (see Sec. 4.4.7). If false, determine the format from the first line. -->
</input_slha_format>
</process_input>
<integration_input>
<calls type="floatarray" value="1 50000 10 50000 1 1500000">
<!-- Array describing the number of iterations and number of calls per integration pass. Default values depend on the selected process. See below in subsection 4.6 for details. -->
</calls>
<seed type="integer" value="">
<!-- Random number generator seed (integer). When omitted, the time counter will be used, resulting in a different value each run. -->
</seed>
<reset_seed_each_process type="T/F" value="F">
<!-- Reset the random number generator seed to seed not just once, but each time a process is integrated. This is useful for comparing matrix elements which should be identical, but, e.g., have been generated by different programs. -->
</reset_seed_each_process>
<accuracy_goal type="float" value="0">
<!-- Goal for the accuracy estimate (6th column in the output). When this goal is reached and the efficiency goal is either also reached or unset, further grid adaptation iterations will be skipped (Sec. 4.9). -->
</accuracy_goal>
<efficiency_goal type="float" value="100">
<!-- Goal for the reweighting efficiency estimate (7th column in the output). When this goal is reached and the accuracy goal is either also reached or unset, further grid adaptation iterations will be skipped (Sec. 4.9). -->
</efficiency_goal>
<time_limit_adaptation type="integer" value="0">
<!-- If nonzero, grid adaptation for the current process will be stopped after the specified number of minutes, and the final integration pass started (Sec. 4.9). -->
</time_limit_adaptation>
<stratified type="T/F" value="T">
<!-- Use stratified (T) / importance (F) sampling. -->
</stratified>
<use_efficiency type="T/F" value="F">
<!-- Use efficiency (T) / accuracy (F) as the criterion for adapting the channel weights. -->
</use_efficiency>
<weights_power type="float" value="0.25">
<!-- Power used for adapting the channel weights. Lower value means slower adaptation (to suppress fluctuations). -->
</weights_power>
<min_bins type="integer" value="3">
<!-- Minimal number of bins per integration dimension. -->
</min_bins>
<max_bins type="integer" value="20">
<!-- Maximal number of bins per integration dimension. This number will be used as long as there are enough sampling points, otherwise the number of bins will be decreased. -->
</max_bins>
<min_calls_per_bin type="integer" value="10">
<!-- Minimal number of points per bin, integration dimension, and integration channel. If this limit cannot be satisfied, the total number of points will be increased. -->
</min_calls_per_bin>
<min_calls_per_channel type="integer" value="0">
<!-- All integration channel will get at least (approximately) this number of points. Prevents channels from being dropped during adaptation. -->
</min_calls_per_channel>
<write_grids type="T/F" value="T">
<!-- Write grids to files whizard.grb (best grid) and whizard.grc (current grid), to be reused later. -->
</write_grids>
<write_grids_raw type="T/F" value="F">
<!-- Use binary format for writing grids. Saves memory at the expense of portability. -->
</write_grids_raw>
<write_grids_file type="string" value="">
<!-- If nonempty, use the specified filename for writing grids instead of the default. The file extensions are appended to string. -->
</write_grids_file>
<write_all_grids type="T/F" value="F">
<!-- Write, in addition, after each iteration the current grid to file whizard.grXX, where XX is the iteration number. -->
</write_all_grids>
<write_all_grids_file type="string" value="">
<!-- If nonempty, use the specified filename for writing the extra grids instead of the default. The file extensions are appended to string. -->
</write_all_grids_file>
<read_grids type="T/F" value="F">
<!-- Read existing grids whizard.grb and whizard.grc if they have been written by a previous run. This avoids the time-consuming adaptation step. Makes sense only if no physical parameters have been changed. -->
</read_grids>
<read_grids_raw type="T/F" value="F">
<!-- If true, search first for binary grid files, then for ASCII grids. If false, do search first for ASCII.. -->
</read_grids_raw>
<read_grids_force type="T/F" value="T">
<!-- Set this to T if you want to read the grids from file even if some parameters have changed. Use with care! This may result in a program crash if the grid structures are incompatible. -->
</read_grids_force>
<read_grids_file type="string" value="">
<!-- If nonempty, use the specified filename for reading grids instead of the default. The file extensions are appended to string. -->
</read_grids_file>
<generate_phase_space type="T/F" value="T">
<!-- Generate a phase space configuration appropriate for the current process and write it to whizard.phx. -->
</generate_phase_space>
<read_model_file type="string" value="">
<!-- If nonempty, read vertex definitions for phase space setup from string.mdl instead of the default whizard.mdl. -->
</read_model_file>
<write_phase_space_file type="string" value="">
<!-- Write phase space configuration to string.phx instead of the default. -->
</write_phase_space_file>
<read_phase_space type="T/F" value="T">
<!-- Read phase space configuration from whizard.phs or a previously generated file whizard.phx if possible. -->
</read_phase_space>
<read_phase_space_file type="string" value="">
<!-- Read phase space configuration from string.phs or string.phx instead of the default. -->
</read_phase_space_file>
<phase_space_only type="T/F" value="F">
<!-- Stop the program after phase space generation. -->
</phase_space_only>
<use_equivalences type="T/F" value="T">
<!-- If true, use permutation symmetry when updating grids to improve the quality of the results. -->
</use_equivalences>
<azimuthal_dependence type="T/F" value="F">
<!-- If false, it is assumed that the scattering does not depend on the overall azimuthal angle. This will be automatically T if general beam polarization is switched on, therefore the user need only access this parameter in the case of azimuthal-dependent cuts. -->
</azimuthal_dependence>
<write_phase_space_channels_file type="string" value="">
<!-- Show phase space channels in string.ps instead of the default file whizard-channels.ps. Note that you need to call CHANNELS= string make -e channels in order to generate string.ps -->
</write_phase_space_channels_file>
<off_shell_lines type="integer" value="1">
<!-- Maximum number of off-shell-lines allowed for Feynman graphs which are initially taken into account for the phase space configuration. Log-enhanced (massless) propagators are not counted as off-shell. -->
</off_shell_lines>
<extra_off_shell_lines type="integer" value="1">
<!-- Use configurations with more off-shell lines, if they happen to be maximally resonant. -->
</extra_off_shell_lines>
<splitting_depth type="integer" value="1">
<!-- Up to this number of branchings, a (massless) propagator will be considered as log-enhanced and mapped like a photon propagator. -->
</splitting_depth>
<exchange_lines type="integer" value="3">
<!-- Up to this number of t-channel propagators, a multiperipheral graph will be taken into account. -->
</exchange_lines>
<show_deleted_channels type="T/F" value="F">
<!-- With extra_off_shell_lines, extra channels will be generated which are deleted if they do not contain enough resonances. With this flag, they are just commented out, so they could be manually activated. -->
</show_deleted_channels>
<single_off_shell_decays type="T/F" value="T">
<!-- Whether single-off-shell decays are relevant for the phase space configuration. -->
</single_off_shell_decays>
<double_off_shell_decays type="T/F" value="F">
<!-- Whether double-off-shell decays are relevant for the phase space configuration. -->
</double_off_shell_decays>
<single_off_shell_branchings type="T/F" value="T">
<!-- Whether single-off-shell branchings are relevant for the phase space configuration. -->
</single_off_shell_branchings>
<double_off_shell_branchings type="T/F" value="T">
<!-- Whether double-off-shell branchings are relevant for the phase space configuration. -->
</double_off_shell_branchings>
<massive_fsr type="T/F" value="T">
<!-- Whether the radiation of a massive particle in the final state is relevant for the phase space configuration. -->
</massive_fsr>
<threshold_mass type="float" value="-10">
<!-- A particle with a mass up to this value will be considered as massless for the purpose of phase-space setup. (But the true mass is taken into account when the particle appears as a resonant intermediate state.) -->
</threshold_mass>
<threshold_mass_t type="float" value="-10">
<!-- A particle with a mass up to this value will be considered as massless for the purpose of phase-space setup, when it appears as a t-channel propagator. -->
</threshold_mass_t>
<!-- <initial_decays_fatal type="T/F" value="T"> -->
<!-- As the phase space maps cannot describe on-shell decays of beam particles properly, WHIZARD normally gives a fatal error when such configurations are encountered. This option changes this to a warning at the price of a potentially screwed phase space setup. -->
<!-- </initial_decays_fatal> -->
<default_jet_cut type="float" value="10">
<!-- The default invariant mass cut in GeV applied to pairs of massless colored particles. -->
</default_jet_cut>
<default_mass_cut type="float" value="4">
<!-- The default invariant mass cut in GeV applied to pair production of massless colorless charged particles and to photon emission. -->
</default_mass_cut>
<default_energy_cut type="float" value="10">
<!-- The default energy cut in GeV applied to photon and gluon emission. -->
</default_energy_cut>
<default_q_cut type="float" value="4">
<!-- The default Q cut in GeV applied to photon and gluon exchange. -->
</default_q_cut>
<write_default_cuts_file type="string" value="">
<!-- If nonempty, write the list of default cuts to this file (augmented by the file extension) instead of the default. Note that the settings in this file are overwritten by a user-defined cut configuration, if present. -->
</write_default_cuts_file>
<read_cuts_file type="string" value="">
<!-- Look for user-defined cut configurations in string.cut1 instead of whizard.cut1. -->
</read_cuts_file>
<user_cut_mode type="integer" value="0">
<!-- Set this nonzero to activate a user-defined cut function (Sec. 5.4). -->
</user_cut_mode>
<user_weight_mode type="integer" value="0">
<!-- Set this nonzero to activate a user-defined weight function (Sec. 5.5). -->
</user_weight_mode>
</integration_input>
<simulation_input>
<n_events type="integer" value="0">
<!-- Number of (unweighted) events to generate at least, irrespective of the luminosity setting. -->
</n_events>
<n_calls type="integer" value="0">
<!-- Number of matrix-element calls (weighted events) to execute at least, irrespective of the luminosity setting. -->
</n_calls>
<n_events_warmup type="integer" value="0">
<!-- Number of extra warmup events (see below, Sec. 4.7). -->
</n_events_warmup>
<unweighted type="T/F" value="T">
<!-- Reweight events to generate an unweighted event sample. -->
</unweighted>
<normalize_weight type="T/F" value="T">
<!-- If true, normalize the event weight to unity. If false, normalize to the total cross section. -->
</normalize_weight>
<write_weights type="T/F" value="F">
<!-- If unweighted=F, write weight distribution data to whizard.wgt. -->
</write_weights>
<write_weights_file type="string" value="">
<!-- Write weight distribution to string.wgt instead. -->
</write_weights_file>
<safety_factor type="float" value="1">
<!-- Multiply the estimate for the highest weight by this factor before starting event generation. -->
</safety_factor>
<write_events type="T/F" value="T">
<!-- Write generated events to file whizard.evt to be used by an external analysis package. -->
</write_events>
<write_events_format type="integer" value="20">
<!-- The format to be used for writing events, where the file extension depends on the format (.evt for format = 1, see Sec. 4.7). -->
</write_events_format>
<write_events_file type="string" value="">
<!-- If nonempty, use string as filename for writing events, where the file extension will be appended. -->
</write_events_file>
<events_per_file type="integer" value="5000000">
<!-- If positive, begin a new event file once the number of entries exceeds this number. The event file counter is appended to each event file name, separated with a dot (before the file extension). This feature applies only to non-binary event formats. -->
</events_per_file>
<bytes_per_file type="integer" value="0">
<!-- If positive, begin a new event file once the number of bytes in the file exceeds this number. The event file counter is appended to each event file name, separated with a dot (before the file extension). This feature applies only to non-binary event formats. See Sec. 4.7.1. -->
</bytes_per_file>
<min_file_count type="integer" value="1">
<!-- If event files are split, use this index for the first event file. Increase the counter by one for each successive event file. -->
</min_file_count>
<max_file_count type="integer" value="999">
<!-- Limit for the event file counter; if this limit is exceeded, event generation is terminated. (For weighted events only, this is an error condition since the event sample must be complete for being usable.) -->
</max_file_count>
<write_events_raw type="T/F" value="F">
<!-- Write events to whizard.evx in condensed binary format, so they can be internally reused in another run. -->
</write_events_raw>
<write_events_raw_file type="string" value="">
<!-- Write raw events to string.evx instead. -->
</write_events_raw_file>
<read_events type="T/F" value="F">
<!-- Read events from file whizard.evx (raw format) instead of generating them. This is equivalent to read_events_raw. -->
</read_events>
<read_events_force type="T/F" value="T">
<!-- This was intended to force WHIZARD to read in events from file even if some parameters have changed. However, the MD5 checksum implemented to check for parameter changes has some deficiencies. Hence, we always enforce to read in events, because this feature could otherwise not be used at all. Use with great care! (Note that this problem has been solved in WHIZARD 2.) -->
</read_events_force>
<read_events_raw_file type="string" value="">
<!-- Read raw events from string.evx instead. -->
</read_events_raw_file>
<keep_beam_remnants type="T/F" value="T">
<!-- Keep the beam remnants in the event record when applying structure functions. See Sec. 4.4.8. -->
</keep_beam_remnants>
<keep_initials type="T/F" value="T">
<!-- Keep the beam particles and the partons which initiate the hard scattering in the event record. See Sec. 4.4.8. -->
</keep_initials>
<guess_color_flow type="T/F" value="F">
<!-- Infer the color flow for hadronization from the particle ordering, if it is nontrivial and not available directly. -->
</guess_color_flow>
<recalculate type="T/F" value="F">
<!-- Recalculate the matrix element value for each event of a previously generated sample. Setting this flag automatically turns on reading grids and events from file. -->
</recalculate>
<fragment type="T/F" value="T">
<!-- Fragment the events depending on the value of fragmentation_method (see Sec. 4.8). -->
</fragment>
<fragmentation_method type="integer" value="3">
<!-- Method used for fragmentation if fragment is true: 0=no fragmentation; 1=JETSET; 2=PYTHIA; 3=user. -->
</fragmentation_method>
<user_fragmentation_mode type="integer" value="0">
<!-- When user-defined fragmentation routines are called, this parameter may select different modes. -->
</user_fragmentation_mode>
<pythia_parameters type="string" value="PMAS(25,1)=120.; PMAS(25,2)=0.3605E-02; MSTU(22)=20 ;MSTJ(28)=2 ;PARJ(21)=0.40000;PARJ(41)=0.11000; PARJ(42)=0.52000; PARJ(81)=0.25000; PARJ(82)=1.90000; MSTJ(11)=3; PARJ(54)=-0.03100; PARJ(55)=-0.00200;PARJ(1)=0.08500; PARJ(3)=0.45000; PARJ(4)=0.02500; PARJ(2)=0.31000; PARJ(11)=0.60000; PARJ(12)=0.40000; PARJ(13)=0.72000;PARJ(14)=0.43000; PARJ(15)=0.08000; PARJ(16)=0.08000; PARJ(17)=0.17000; MSTP(3)=1;">
<!-- String to be given to PYTHIA's pygive call before starting event generation. This allows to modify PYTHIA/JETSET properties, set particle masses, etc. The string is also available within user-defined fragmentation routines and can there be abused for different purposes. -->
</pythia_parameters>
<pythia_processes type="string" value="">
<!-- PYTHIA background processes to be simulated in addition to the WHIZARD processes: A list of integers separated by blanks, enclosed in quotation marks. Refer to the PYTHIA manual for the list of processes. -->
</pythia_processes>
<shower type="T/F" value="F">
<!-- Switches the internal shower on or off. As a default it is off. Note that the shower only works with LHEF event format (foramt type 6). This shower is highly experimental. Mainly intended for testing purposes. -->
</shower>
<shower_nf type="integer" value="5">
<!-- Number of light flavors in the shower. -->
</shower_nf>
<shower_running_alpha_s type="T/F" value="F">
<!-- Whether to use a running strong coupling alpha_s or not in the shower. As a default it is fixed. -->
</shower_running_alpha_s>
<shower_alpha_s type="float" value="0.2">
<!-- The value of the strong coupling constant alpha_s as used by the internal shower. The default is 0.2. -->
</shower_alpha_s>
<shower_lambda type="float" value="0.29">
<!-- The value of the QCD scale Lambda_QCD as used by the internal shower. The default is 0.29 GeV. -->
</shower_lambda>
<shower_t_min type="float" value="1.0">
<!-- The infrared cutoff for the evolution parameter tmin as used by the internal shower. The default is 1 GeV. -->
</shower_t_min>
<shower_md type="float" value="0.330">
<!-- The constituent d quark mass md as used by the internal shower. The default is 0.330 GeV. -->
</shower_md>
<shower_mu type="float" value="0.330">
<!-- The constituent u quark mass mu as used by the internal shower. The default is 0.330 GeV. -->
</shower_mu>
<shower_ms type="float" value="0.500">
<!-- The constituent s quark mass ms as used by the internal shower. The default is 0.5 GeV. -->
</shower_ms>
<shower_mc type="float" value="1.5">
<!-- The constituent c quark mass mc as used by the internal shower. The default is 1.5 GeV. -->
</shower_mc>
<shower_mb type="float" value="4.8">
<!-- The constituent b quark mass mb as used by the internal shower. The default is 4.8 GeV.diagnostics_input -->
</shower_mb>
</simulation_input>
<diagnostics_input>
<chattiness type="integer" value="4">
<!-- How much information to show on screen: (0) only fatal errors, (1) and non-fatal errors, (2) and warnings, (3) and messages, (4) and results, (5) and debugging messages (if any). -->
</chattiness>
<catch_signals type="T/F" value="T">
<!-- If the compiler supports it, try to catch external signals such as SIGINT and SIGXCPU and exit gracefully, closing files first. -->
</catch_signals>
<time_limit type="integer" value="0"> -->
<!-- If nonzero, exit gracefully after the given number of minutes has passed. This is useful to prevent an external kill within a batch environment. -->
</time_limit>
<warn_empty_channel type="T/F" value="F">
<!-- Issue a warning whenever the integral within a phase space channel is zero. -->
</warn_empty_channel>
<screen_events type="T/F" value="F">
<!-- Whether to show generated events on screen. -->
</screen_events>
<screen_histograms type="T/F" value="F">
<!-- Whether to show histograms on screen. -->
</screen_histograms>
<screen_diagnostics type="T/F" value="F">
<!-- Whether to repeat the input parameters on screen. -->
</screen_diagnostics>
<show_pythia_banner type="T/F" value="T">
<!-- Whether to display the PYTHIA banner page if fragmentation is enabled. -->
</show_pythia_banner>
<show_pythia_initialization type="T/F" value="T">
<!-- Whether to display the PYTHIA initialization messages if fragmentation is enabled. -->
</show_pythia_initialization>
<show_pythia_statistics type="T/F" value="T">
<!-- Whether to display the PYTHIA statistics summary after event generation is completed. -->
</show_pythia_statistics>
<write_logfile type="T/F" value="T">
<!-- Whether to write the (process-specific) output file(s) whizard.XX.out. -->
</write_logfile>
<write_logfile_file type="string" value="">
<!-- Use this as the filename for the logfile. -->
</write_logfile_file>
<show_input type="T/F" value="T">
<!-- Whether to repeat the input parameters in the logfile. -->
</show_input>
<show_results type="T/F" value="T">
<!-- Whether to show the integration results in namelist format in the logfile. -->
</show_results>
<show_phase_space type="T/F" value="F">
<!-- Whether to show the phase space configuration in the logfile. -->
</show_phase_space>
<show_cuts type="T/F" value="T">
<!-- Whether to show the cut configuration in the logfile. -->
</show_cuts>
<show_histories type="T/F" value="F">
<!-- Whether to show the individual VAMP channel histories in the logfile. -->
</show_histories>
<show_history type="T/F" value="T">
<!-- Whether to show the overall VAMP history in the logfile. -->
</show_history>
<show_weights type="T/F" value="T">
<!-- Whether to show the weight adaptation in the logfile. -->
</show_weights>
<show_event type="T/F" value="F">
<!-- Whether to show the last event in the logfile. -->
</show_event>
<show_histograms type="T/F" value="F">
<!-- Whether to show histograms in the logfile. -->
</show_histograms>
<show_overflow type="T/F" value="F">
<!-- Whether to show events beyond the first or last bin in histogram listings. -->
</show_overflow>
<show_excess type="T/F" value="T">
<!-- Whether to show a summary of events with weight exceeding one. -->
</show_excess>
<read_analysis_file type="string" value="">
<!-- Use this (string.cut5) as the filename for the analysis setup instead of whizard.cut5 -->
</read_analysis_file>
<plot_width type="float" value="130">
<!-- The width in mm of the plots if online analysis is enabled. -->
</plot_width>
<plot_height type="float" value="90">
<!-- The height in mm of the plots if online analysis is enabled. -->
</plot_height>
<plot_excess type="T/F" value="T">
<!-- In the plots, display excess events in red. -->
</plot_excess>
<plot_history type="T/F" value="T">
<!-- If this is enabled, write a graphics driver file for displaying the integration history, i.e., the integral with error bars for each iteration. Use make history to generate the graphics file whizard-history.ps. -->
</plot_history>
<plot_grids_channels type="string" value="">
<!-- The string is a list of phase-space channels (integers) for which the bin distribution will be histogrammed. Use make grids to generate the graphics file whizard-grids.ps. -->
</plot_grids_channels>
<plot_grids_logscale type="float" value="10">
<!-- Use logarithmic scale for the grid plots if the bin width varies over more than this ratio. -->
</plot_grids_logscale>
<slha_rewrite_input type="T/F" value="T">
<!-- If SUSY Les Houches Accord data have been used, whether to repeat this input in the process-specific logfiles (including comments) or to rewrite it there using the data which have actually been used. -->
</slha_rewrite_input>
<slha_ignore_errors type="T/F" value="F">
<!-- If this is false, an error signaled in the SLHA input file (in the SPINFO or DCINFO block) will cause WHIZARD to stop before calculating anything. If true, such errors will be displayed, but the run continues. -->
</slha_ignore_errors>
</diagnostics_input>
%s
<beam_input_1>
<energy type="float" value="0">
<!-- If greater than the beam particle mass, this specifies the beam energy in the lab frame. Otherwise, the beam energy is set equal to the particle mass (fixed target). -->
</energy>
<angle type="float" value="0">
<!-- If direction is not set, this specifies a rotation of the beam axis in the lab frame around the positive y axis. (By default, the beam directions are along the positive/negative z axis, so a rotation by the angle pi/2 turns them into the positive/negative x axis.) If direction is set, this parameter is ignored. -->
</angle>
<direction type="floatarray" value="0 0 0">
<!-- If any component is nonzero, this vector explicitly specifies the direction of the given beam in the lab frame. -->
</direction>
<vector_polarization type="T/F" value="F">
<!-- If false (default), use the standard helicity basis (left-/right-handed). Set this flag if you need another basis, in particular transversal polarization. -->
</vector_polarization>
<polarization type="floatarray" value="0.0 0.0">
<!-- Fraction of left/right polarization (fermions, photons, gluons), resp. left/longitudinal/right polarization (massive vector bosons). If the vector polarization model is selected, the three numbers denote the polarization vector. -->
</polarization>
<particle_code type="integer" value="0">
<!-- PDG code of the incoming beam particle. -->
</particle_code>
<particle_name type="string" value="e1">
<!-- Name of the incoming beam particle. -->
</particle_name>
<USER_spectrum_on type="T/F" value="T">
<!-- Apply or not the user spectrum -->
</USER_spectrum_on>
<USER_spectrum_mode type="integer" value="11">
<!-- User spectrum -->
</USER_spectrum_mode>
<ISR_on type="T/F" value="T">
<!-- Whether to apply ISR (electron or positron beam). -->
</ISR_on>
<ISR_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</ISR_alpha>
<ISR_m_in type="float" value="0.000511">
<!-- The mass of the incoming particle. -->
</ISR_m_in>
<ISR_Q_max type="float" value="sqrts">
<!-- The hard scale which cuts off photon radiation. -->
</ISR_Q_max>
<ISR_LLA_order type="0/1/2/3" value="3">
<!-- The order of the leading-logarithmic approximation. -->
</ISR_LLA_order>
<ISR_map type="T/F" value="T">
<!-- Whether to use a mapping of the singularity at x=1 when evaluating the structure function (recommended; note that switching this off might even lead to an uncaught arithmetic exception). -->
</ISR_map>
<EPA_on type="T/F" value="F">
<!-- Whether to use the EPA spectrum (photon beam). -->
</EPA_on>
<EPA_map type="T/F" value="T">
<!-- Whether to apply a mapping to improve convergence. -->
</EPA_map>
<EPA_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</EPA_alpha>
<EPA_m_in type="float" value="0.000511">
<!-- The mass of the incoming beam particle. -->
</EPA_m_in>
<EPA_mX type="float" value="4">
<!-- The lower cutoff for the produced invariant mass. -->
</EPA_mX>
<EPA_Q_max type="float" value="4">
<!-- The upper cutoff on the virtuality of the photon (Qmax&gt;0). -->
</EPA_Q_max>
<EPA_x0 type="float" value="0">
<!-- The lower cutoff on the energy fraction of the incoming photon -->
</EPA_x0>
<EPA_x1 type="float" value="0">
<!-- The upper cutoff on the energy fraction of the incoming photon -->
</EPA_x1>
</beam_input_1>
<beam_input_2>
<energy type="float" value="0">
<!-- If greater than the beam particle mass, this specifies the beam energy in the lab frame. Otherwise, the beam energy is set equal to the particle mass (fixed target). -->
</energy>
<angle type="float" value="0">
<!-- If direction is not set, this specifies a rotation of the beam axis in the lab frame around the positive y axis. (By default, the beam directions are along the positive/negative z axis, so a rotation by the angle pi/2 turns them into the positive/negative x axis.) If direction is set, this parameter is ignored. -->
</angle>
<direction type="floatarray" value="0 0 0">
<!-- If any component is nonzero, this vector explicitly specifies the direction of the given beam in the lab frame. -->
</direction>
<vector_polarization type="T/F" value="F">
<!-- If false (default), use the standard helicity basis (left-/right-handed). Set this flag if you need another basis, in particular transversal polarization. -->
</vector_polarization>
<polarization type="floatarray" value="0.0 0.0">
<!-- Fraction of left/right polarization (fermions, photons, gluons), resp. left/longitudinal/right polarization (massive vector bosons). If the vector polarization model is selected, the three numbers denote the polarization vector. -->
</polarization>
<particle_code type="integer" value="0">
<!-- PDG code of the incoming beam particle. -->
</particle_code>
<particle_name type="string" value="E1">
<!-- Name of the incoming beam particle. -->
</particle_name>
<USER_spectrum_on type="T/F" value="T">
<!-- Apply or not the user spectrum -->
</USER_spectrum_on>
<USER_spectrum_mode type="integer" value="-11">
<!-- User spectrum -->
</USER_spectrum_mode>
<ISR_on type="T/F" value="T">
<!-- Whether to apply ISR (electron or positron beam). -->
</ISR_on>
<ISR_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</ISR_alpha>
<ISR_m_in type="float" value="0.000511">
<!-- The mass of the incoming particle. -->
</ISR_m_in>
<ISR_Q_max type="float" value="sqrts">
<!-- The hard scale which cuts off photon radiation. -->
</ISR_Q_max>
<ISR_LLA_order type="0/1/2/3" value="3">
<!-- The order of the leading-logarithmic approximation. -->
</ISR_LLA_order>
<ISR_map type="T/F" value="T">
<!-- Whether to use a mapping of the singularity at x=1 when evaluating the structure function (recommended; note that switching this off might even lead to an uncaught arithmetic exception). -->
</ISR_map>
<EPA_on type="T/F" value="F">
<!-- Whether to use the EPA spectrum (photon beam). -->
</EPA_on>
<EPA_map type="T/F" value="T">
<!-- Whether to apply a mapping to improve convergence. -->
</EPA_map>
<EPA_alpha type="float" value="0.0072993">
<!-- The value of alpha_QED to be used for the spectrum. -->
</EPA_alpha>
<EPA_m_in type="float" value="0.000511">
<!-- The mass of the incoming beam particle. -->
</EPA_m_in>
<EPA_mX type="float" value="4">
<!-- The lower cutoff for the produced invariant mass. -->
</EPA_mX>
<EPA_Q_max type="float" value="4">
<!-- The upper cutoff on the virtuality of the photon (Qmax&gt;0). -->
</EPA_Q_max>
<EPA_x0 type="float" value="0">
<!-- The lower cutoff on the energy fraction of the incoming photon -->
</EPA_x0>
<EPA_x1 type="float" value="0">
<!-- The upper cutoff on the energy fraction of the incoming photon -->
</EPA_x1>
</beam_input_2>
</whizard>
""" % modelparams)
        self.getInputFiles(model)

    def getInputFiles(self, model):
        """ Get the proper input parameter file, usually LesHouches
    """
        if 'process_input' not in self.paramdict:
            self.paramdict['process_input'] = {}
        if 'input_file' not in self.paramdict['process_input']:
            res = self.genmodel.getFile(model)
            if not res['OK']:
                self.paramdict['process_input']['input_file'] = ''
                self.paramdict['process_input']['input_slha_format'] = 'F'
            else:
                self.paramdict['process_input']['input_file'] = res['Value']
                self.paramdict['process_input']['input_slha_format'] = 'T'

    def modelParams(self, model):
        """ Get the model parameters
    """
        modelparams = []
        res = self.genmodel.getParamsForWhizard(model)
        if not res['OK']:
            return ""
        modelparams.append("<parameter_input>")

        modelparams.append(res['Value'])

        modelparams.append("</parameter_input>")

        return "\n".join(modelparams)

    def toXML(self, fname='whizard.xml'):
        """ Write to XML
    """
        tree = ElementTree(self.whizardxml)
        tree.write(fname)
        return S_OK()

    def getMainFields(self):
        """ Get the main fields
    """
        listoffields = []
        for elem in list(self.whizardxml):
            listoffields.append(elem.tag)
        return S_OK(listoffields)

    def getOptionsForField(self, field):
        """ Get the options of a given field
    """
        options = []
        element = self.whizardxml.find(field)
        if element is None:
            return S_ERROR("Field %s does not exist" % field)
        for subelements in list(element):
            options.append(subelements.tag)
        return S_OK(options)

    def getValue(self, field):
        """ Get the value for a given field/option
    """
        element = self.whizardxml.find(field)
        return S_OK(element.attrib['value'])

    def changeAndReturn(self, paramdict):
        """ Update the options, and returns the modified XML object
    """
        self.paramdict.update(paramdict)
        res = self.checkFields(self.paramdict)
        if not res['OK']:
            return res
        for key, val in self.paramdict.items():
            for subkey in val.keys():
                subelement = self.whizardxml.find(key + "/" + subkey)
                subelement.attrib['value'] = val[subkey]
        return S_OK(self.whizardxml)

    def getAsDict(self):
        """ Get the content as dict, like the one used for setting the options
    """
        whiz_opt = {}
        for element in list(self.whizardxml):
            whiz_opt[element.tag] = {}
            for item in list(element):
                val = item.attrib['value']
                if isinstance(val, basestring):
                    val = val.rstrip()
                whiz_opt[element.tag][item.tag] = val
        return S_OK(whiz_opt)

    def checkFields(self, paramdict):
        """ Make sure all supplied fields are exisiting somewhere
    """
        for key, val in paramdict.items():
            element = self.whizardxml.find(key)
            if element is None:
                return S_ERROR("Element %s is not in the allowed parameters" %
                               key)
            for subkey, value in val.items():
                subelement = self.whizardxml.find(key + "/" + subkey)
                if subelement is None:
                    return S_ERROR(
                        "Key %s/%s is not in the allowed parameters" %
                        (key, subkey))
                etype = subelement.attrib['type']
                if etype == 'float':
                    if not isinstance(value, (float, int, long)) or isinstance(
                            value, bool):
                        return S_ERROR("%s should be a float" %
                                       (key + "/" + subkey))
                elif etype == 'T/F':
                    if value != 'T' and value != 'F':
                        return S_ERROR("%s should be either 'T' or 'F'" %
                                       (key + "/" + subkey))
                elif etype == 'integer' or etype == '0/1/2/3':
                    if not isinstance(value,
                                      (int, long)) or (etype == '0/1/2/3' and
                                                       value not in range(4)):
                        return S_ERROR("%s should be an integer" %
                                       (key + "/" + subkey))
                elif etype == 'string':
                    if not isinstance(value, basestring):
                        return S_ERROR("%s should be a string" %
                                       (key + "/" + subkey))
                elif etype == 'floatarray':
                    error = False
                    if not isinstance(value, basestring):
                        error = True
                    else:
                        valelem = value.split()
                        if len(valelem) < 2:
                            error = True
                    if error:
                        return S_ERROR(
                            "%s should be a string with spaces, e.g. '0 1 2 3'"
                            % (key + "/" + subkey))
        return S_OK()

    def toWhizardDotIn(self, fname):
        """ Write the options to the whizard.in
    """
        lines = []
        for elem in list(self.whizardxml):
            tag = elem.tag
            if tag.count("beam_input"):
                tag = "beam_input"
            lines.append("&%s" % tag)
            for subelem in list(elem):
                val = subelem.get('value')
                if val == 'sqrts':
                    continue
                if subelem.get('type') == 'string':
                    val = '"%s"' % val
                if val == '000':
                    val = '0 0 0'
                if val == '0.0.0':
                    val = '0.0 0.0'
                if val == '0..0..0':
                    val = '\n 1 20000\n 10 20000\n 1 20000'
                lines.append(' %s = %s' % (subelem.tag, val))
            lines.append('/')
        with open(fname, "w") as of:
            of.write("\n".join(lines))
            of.write("\n")
        return S_OK(True)

    def fromWhizardDotIn(self, filename):
        """ Given a whizard.in, create the parameter dict used for the production definition
    """
        pdict = {}
        beam_input_idx = 0
        curkey = ""
        with open(filename, "r") as whizin:
            for line in whizin:
                line = line.rstrip().lstrip()
                if not line or line[0] in ["!", "/"]:
                    continue

                if line[0] == "&":
                    key = line.split("&")[1].rstrip().lstrip()
                    if key.count("beam_input"):
                        if not beam_input_idx:
                            curkey = key + "_1"
                            beam_input_idx += 1
                        else:
                            curkey = key + "_2"
                    else:
                        curkey = key
                    pdict[curkey] = {}
                elif line.count("="):
                    elems = line.split("=")
                    key = elems[0].lstrip().rstrip()
                    val = str("=".join(
                        elems[1:])).lstrip().rstrip().lstrip('"').rstrip('"')
                    if not val.count("T") and not val.count("F"):
                        if val.count("."):
                            try:
                                val = float(val)
                            except ValueError:
                                pass
                        else:
                            try:
                                val = int(val)
                            except ValueError:
                                pass
                    pdict[curkey][key] = val
        return self.changeAndReturn(pdict)