Example #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()
Example #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()
Example #3
0
class Whizard(LCApplication):
  """ Runs whizard to generate a given event type

  Usage:

  >>> wh = Whizard(dirac.getProcessList())
  >>> wh.setEvtType("ee_h_mumu")
  >>> wh.setEnergy(500)
  >>> wh.setNumberOfEvents(1000)
  >>> wh.setModel("sm")

  use :func:`setExtraArguments` to overwrite the content of the whizard.in
  in case you use something not standard (parameter scan for exmple)
  """
  def __init__(self, processlist = None, paramdict = None):

    self.parameterDict = {}
    self.model = 'sm'
    self.randomSeed = 0
    self.luminosity = 0
    self.jobIndex = ''
    self._optionsdictstr = ''
    self.fullParameterDict = {}
    self.generatorLevelCuts = {}
    self._genlevelcutsstr = ''
    self._leshouchesfiles = None
    self._generatormodels = GeneratorModels()
    self.eventType = ''
    self.globalEventType = ''
    self.useGridFiles = False
    self._allowedparams = ['PNAME1', 'PNAME2', 'POLAB1', 'POLAB2', 'USERB1', 'USERB2',
                           'ISRB1', 'ISRB2', 'EPAB1', 'EPAB2', 'RECOIL', 'INITIALS', 'USERSPECTRUM']
    self._wo = None
    self.parameters = []
    self._processlist = None
    if processlist:
      self._processlist = processlist
    super(Whizard, self).__init__( paramdict )
    ##Those 4 need to come after default constructor
    self._modulename = 'WhizardAnalysis'
    self._moduledescription = 'Module to run WHIZARD'
    self.appname = 'whizard'
    self.datatype = 'gen'
    self._paramsToExclude.extend( [ '_optionsdictstr', '_genlevelcutsstr', '_leshouchesfiles', '_generatormodels',
                                    '_allowedparams', '_wo','_processlist' ] )

  def getPDict(self):
    """ Provide predefined parameter dictionary
    """
    return getDict()

  def setEvtType(self, evttype):
    """ Define process. If the process given is not found, when calling :func:`UserJob.append() <ILCDIRAC.Interfaces.API.NewInterface.UserJob.UserJob.append>` a full list is printed.

    :param string evttype: Process to generate
    """
    self._checkArgs( { 'evttype' : types.StringTypes } )
    if self.addedtojob:
      self._log.error("Cannot modify this attribute once application has been added to Job")
      return S_ERROR("Cannot modify")
    self.eventType = evttype

  def setGlobalEvtType(self, globalname):
    """ When producing multiple process in one job, it is needed to define this for the output file name.
    It's mandatory to use the :any:`setFullParameterDict` method when using this.
    """
    self._checkArgs( { 'globalname' : types.StringTypes } )
    self.globalEventType = globalname

  def setLuminosity(self, lumi):
    """ Optional: Define luminosity to generate

    :param float lumi: Luminosity to generate. Not available if cross section is not known a priori. Use with care.
    """
    self._checkArgs( { 'lumi' : types.FloatType } )
    self.luminosity = lumi

  def setRandomSeed(self, randomSeed):
    """ Optional: Define random seed to use. Default is Job ID.

    :param int randomSeed: Seed to use during integration and generation.
    """
    self._checkArgs( { 'randomSeed' : types.IntType } )

    self.randomSeed = randomSeed

  def setParameterDict(self, paramdict):
    """ Parameters for Whizard steering files

    :param dict paramdict: Dictionary of parameters for the whizard templates. Most parameters are set on the fly.
    """
    self._checkArgs( { 'paramdict' : types.DictType } )
    self.parameterDict = paramdict

  def setGeneratorLevelCuts(self, cutsdict):
    """ Define generator level cuts (to be put in whizard.cut1)

    Refer to http://whizard.hepforge.org/manual_w1/manual005.html#toc12 for details about how to set cuts.

    >>> wh.setGeneratorLevelCuts({'e1e1_o':["cut M of  3 within 10 99999","cut E of  3 within  5 99999"]})

    :param dict cutsdict: Dictionary of cuts
    """
    self._checkArgs( { 'cutsdict' : types.DictType } )
    self.generatorLevelCuts = cutsdict

  def setFullParameterDict(self, pdict):
    """ Parameters for Whizard steering files, better than above as much more complete (cannot be more complete)

    >>> pdict = {}
    >>> pdict['process_input'] = {}
    >>> #processes below are not those of the templates, but those of the whizard.prc
    >>> pdict['process_input']['process_id']='h_n1n1'
    >>> pdict['process_input']['sqrts'] = 3000.
    >>> pdict['simulation_input'] = {}
    >>> pdict['simulation_input']['n_events'] = 100
    >>> pdict['beam_input_1'] = {}
    >>> pdict['beam_input_1']['polarization']='1.0 0.0'
    >>> pdict['beam_input_1']['USER_spectrum_mode'] = 11
    >>> pdict['beam_input_2'] = {}
    >>> pdict['beam_input_2']['polarization']='0.0 1.0'
    >>> pdict['beam_input_2']['USER_spectrum_mode'] = -11
    >>> wh.setFullParameterDict(pdict)

    The first key corresponds to the sections of the whizard.in, while the second corresponds to the possible parameters.
    All keys/values can be found in the WHIZARD documentation: http://whizard.hepforge.org/manual_w1/manual005.html#toc11

    :param dict pdict: Dictionnary of parameters
    """
    self._checkArgs( { 'pdict' : types.DictType } )

    self.fullParameterDict = pdict
    #self._wo.changeAndReturn(dict)

  def setModel(self, model):
    """ Optional: Define Model

    :param string model: Model to use for generation. Predefined list available in the :mod:`GeneratorModels<ILCDIRAC.Core.Utilities.GeneratorModels.GeneratorModels>` class.
    """
    self._checkArgs( { 'model' : types.StringTypes } )

    self.model = model

  def willCut(self):
    """ You need this if you plan on cutting using :mod:`StdhepCut <ILCDIRAC.Interfaces.API.NewInterface.Applications.StdhepCut.StdhepCut>`
    """
    self.willBeCut = True

  def usingGridFiles(self):
    """ Call this if you want to use the grid files that come with the Whizard version used.

    Beware: Depends on the energy and generator cuts, use it if you know what you are doing.
    """
    self.useGridFiles = True

  def setJobIndex(self, index):
    """ Optional: Define Job Index. Added in the file name between the event type and the extension.

    :param string index: Index to use for generation
    """
    self._checkArgs( { 'index' : types.StringTypes } )

    self.jobIndex = index

  def dumpWhizardDotIn(self, fname = 'whizard.in'):
    """ Dump the content of the whizard.in file requested for this application

    :param string fname: filename in which whizard.in is written
    """
    if self.addedtojob:
      self._wo.toWhizardDotIn(fname)
    else:
      self._reportError("Can't dump the whizard.in as there can be further changes")

  def _checkConsistency(self):
    """ Check the consistency, called from Application
    """
    self._wo = WhizardOptions(self.model)

    if not self.fullParameterDict:
      if not self.energy :
        return S_ERROR('Energy not set')

      if not self.numberOfEvents :
        return S_ERROR('Number of events not set!')

      if not self.eventType:
        return S_ERROR("Process not defined")
    else:
      res = self._wo.checkFields(self.fullParameterDict)
      if not res['OK']:
        return res
      self._wo.changeAndReturn(self.fullParameterDict)
      res = self._wo.getValue("process_input/process_id")
      if not len(res['Value']):
        if self.eventType:
          if not 'process_input' in self.fullParameterDict:
            self.fullParameterDict['process_input'] = {}
          self.fullParameterDict['process_input']['process_id'] = self.eventType
        else:
          return S_ERROR("Event type not specified")
      self.eventType = res['Value']

      res = self._wo.getValue("process_input/sqrts")
      if type(res['Value']) == type(3) or type(res['Value']) == type(3.):
        energy = res['Value']
      else:
        energy = eval(res['Value'])
      if not energy:
        if self.energy:
          if not 'process_input' in self.fullParameterDict:
            self.fullParameterDict['process_input'] = {}
          self.fullParameterDict['process_input']['sqrts'] = self.energy
          energy = self.energy
        else:
          return S_ERROR("Energy set to 0")
      self.energy = energy

      res = self._wo.getValue("simulation_input/n_events")
      if type(res['Value']) == type(3) or type(res['Value']) == type(3.):
        numberOfEvents = res['Value']
      else:
        numberOfEvents = eval(res['Value'])
      if not numberOfEvents:
        if self.numberOfEvents:
          if not 'simulation_input' in self.fullParameterDict:
            self.fullParameterDict['simulation_input'] = {}
          self.fullParameterDict['simulation_input']['n_events'] = self.numberOfEvents
          numberOfEvents = self.numberOfEvents
        else:
          return S_ERROR("Number of events set to 0")
      self.numberOfEvents = numberOfEvents

    if not self._processlist:
      return S_ERROR("Process list was not given")

    if self.generatorLevelCuts:
      for process in self.generatorLevelCuts.keys():
        if not process in self.eventType.split():
          self._log.info("You want to cut on %s but that process is not to be generated" % process)
      for values in self.generatorLevelCuts.values():
        if not type(values) == types.ListType:
          return S_ERROR('Type of %s is not a list, cannot proceed' % values)
      self._genlevelcutsstr = str(self.generatorLevelCuts)

    if self.eventType:
      processes = self.eventType.split()
      if len(processes) > 1 and not self.globalEventType:
        return S_ERROR("Global name MUST be defined when producing multiple processes in one job")
      elif self.globalEventType:
        self.eventType = self.globalEventType
      for process in processes:
        if not self._processlist.existsProcess(process)['Value']:
          self._log.notice("Available processes are:")
          self._processlist.printProcesses()
          return S_ERROR('Process %s does not exists'%process)
        else:
          cspath = self._processlist.getCSPath(process)
          whiz_file = os.path.basename(cspath)
          version = whiz_file.replace(".tar.gz","").replace(".tgz","").replace("whizard","")
          if self.version:
            if self.version != version:
              return S_ERROR("All processes to consider are not available in the same WHIZARD version")
          else:
            self.version = version
          self._log.info("Found the process %s in whizard %s"%(process, self.version))

    if not self.version:
      return S_ERROR('No version found')

    if self.model:
      if not self._generatormodels.hasModel(self.model)['OK']:
        return S_ERROR("Unknown model %s" % self.model)

    if self.outputFile:
      if self.outputFile.count("/"):
        return S_ERROR("The OutputFile name is a file name, not a path. Remove any / in there")

    if not self.outputFile and self._jobtype == 'User':
      self.outputFile = self.eventType
      if self.jobIndex :
        self.outputFile += "_" + self.jobIndex
      self.outputFile += "_gen.stdhep"

    if not self._jobtype == 'User':
      if not self.willBeCut:
        self._listofoutput.append({"outputFile":"@{OutputFile}", "outputPath":"@{OutputPath}",
                                   "outputDataSE":'@{OutputSE}'})
      self.prodparameters['nbevts'] = self.numberOfEvents
      self.prodparameters['Process'] = self.eventType
      self.prodparameters['model'] = self.model
      self.prodparameters['Energy'] = self.energy
      self.prodparameters['whizardparams'] = self.fullParameterDict
      self.prodparameters['gencuts'] = self.generatorLevelCuts
      self.prodparameters['gridfiles'] = self.useGridFiles

    if not self.fullParameterDict and self.parameterDict:
      for key in self.parameterDict.keys():
        if not key in self._allowedparams:
          return S_ERROR("Unknown parameter %s"%key)

      self.setParameter( 'PNAME1', 'e1', "Assuming incoming beam 1 to be electrons" )
      self.setParameter( 'PNAME2', 'E1', "Assuming incoming beam 2 to be positrons" )
      self.setParameter( 'POLAB1', '0.0 0.0', "Assuming no polarization for beam 1" )
      self.setParameter( 'POLAB2', '0.0 0.0', "Assuming no polarization for beam 2" )
      self.setParameter( 'USERB1', 'T', "Will put beam spectrum to True for beam 1" )
      self.setParameter( 'USERB2', 'T', "Will put beam spectrum to True for beam 2" )
      self.setParameter( 'ISRB1', 'T', "Will put ISR to True for beam 1" )
      self.setParameter( 'ISRB2', 'T', "Will put ISR to True for beam 2" )

      self.setParameter( 'EPAB1', 'F', "Will put EPA to False for beam 1" )
      self.setParameter( 'EPAB2', 'F', "Will put EPA to False for beam 2" )

      self.setParameter( 'RECOIL', 'F', "Will set Beam_recoil to False" )
      self.setParameter( 'INITIALS', 'F', "Will set keep_initials to False" )
      self.setParameter( 'USERSPECTRUM', '11', "Will set USER_spectrum_on to +-11" )

      self.parameters = ";".join( self.parameters )
    elif self.fullParameterDict:
      self._optionsdictstr = str(self.fullParameterDict)


    return S_OK()

  def _applicationModule(self):
    md1 = self._createModuleDefinition()
    md1.addParameter(Parameter("evttype",      "", "string", "", "", False, False, "Process to generate"))
    md1.addParameter(Parameter("RandomSeed",    0,    "int", "", "", False, False, "Random seed for the generator"))
    md1.addParameter(Parameter("Lumi",          0,  "float", "", "", False, False, "Luminosity of beam"))
    md1.addParameter(Parameter("Model",        "", "string", "", "", False, False, "Model for generation"))
    md1.addParameter(Parameter("SteeringFile", "", "string", "", "", False, False, "Steering file"))
    md1.addParameter(Parameter("steeringparameters",  "", "string", "", "", False, False,
                               "Specific steering parameters"))
    md1.addParameter(Parameter("OptionsDictStr",      "", "string", "", "", False, False,
                               "Options dict to create full whizard.in on the fly"))
    md1.addParameter(Parameter("GenLevelCutDictStr",  "", "string", "", "", False, False,
                               "Generator level cuts to put in whizard.cut1"))
    md1.addParameter(Parameter("willCut",  False,   "bool", "", "", False, False, "Will cut after"))
    md1.addParameter(Parameter("useGridFiles",  True,   "bool", "", "", False, False, "Will use grid files"))
    md1.addParameter(Parameter("debug",    False,   "bool", "", "", False, False, "debug mode"))
    return md1


  def _applicationModuleValues(self, moduleinstance):
    moduleinstance.setValue("evttype",            self.eventType)
    moduleinstance.setValue("RandomSeed",         self.randomSeed)
    moduleinstance.setValue("Lumi",               self.luminosity)
    moduleinstance.setValue("Model",              self.model)
    moduleinstance.setValue("SteeringFile",       self.steeringFile)
    moduleinstance.setValue("steeringparameters", self.parameters)
    moduleinstance.setValue("OptionsDictStr",     self._optionsdictstr)
    moduleinstance.setValue("GenLevelCutDictStr", self._genlevelcutsstr)
    moduleinstance.setValue("willCut",            self.willBeCut)
    moduleinstance.setValue("useGridFiles",       self.useGridFiles)
    moduleinstance.setValue("debug",              self.debug)

  def _userjobmodules(self, stepdefinition):
    res1 = self._setApplicationModuleAndParameters(stepdefinition)
    res2 = self._setUserJobFinalization(stepdefinition)
    if not res1["OK"] or not res2["OK"] :
      return S_ERROR('userjobmodules failed')
    return S_OK()

  def _prodjobmodules(self, stepdefinition):
    res1 = self._setApplicationModuleAndParameters(stepdefinition)
    res2 = self._setOutputComputeDataList(stepdefinition)
    if not res1["OK"] or not res2["OK"] :
      return S_ERROR('prodjobmodules failed')
    return S_OK()

  def setParameter(self, parameter, defaultValue, docString):
    if not parameter in self.parameterDict:
      self._log.info(docString)
      self.parameters.append( "%s=%s" % (parameter, defaultValue) )
    else:
      self.parameters.append( "%s=%s" % (parameter, self.parameterDict[parameter]) )
Example #4
0
class Whizard(LCApplication):
    """ Runs whizard to generate a given event type

  Usage:

  >>> wh = Whizard(dirac.getProcessList())
  >>> wh.setEvtType("ee_h_mumu")
  >>> wh.setEnergy(500)
  >>> wh.setNumberOfEvents(1000)
  >>> wh.setModel("sm")

  use :func:`setExtraArguments` to overwrite the content of the whizard.in
  in case you use something not standard (parameter scan for exmple)
  """
    def __init__(self, processlist=None, paramdict=None):

        self.parameterDict = {}
        self.model = 'sm'
        self.randomSeed = 0
        self.luminosity = 0
        self.jobIndex = ''
        self._optionsdictstr = ''
        self.fullParameterDict = {}
        self.generatorLevelCuts = {}
        self._genlevelcutsstr = ''
        self._leshouchesfiles = None
        self._generatormodels = GeneratorModels()
        self.eventType = ''
        self.globalEventType = ''
        self.useGridFiles = False
        self._allowedparams = [
            'PNAME1', 'PNAME2', 'POLAB1', 'POLAB2', 'USERB1', 'USERB2',
            'ISRB1', 'ISRB2', 'EPAB1', 'EPAB2', 'RECOIL', 'INITIALS',
            'USERSPECTRUM'
        ]
        self._wo = None
        self.parameters = []
        self._processlist = None
        if processlist:
            self._processlist = processlist
        super(Whizard, self).__init__(paramdict)
        ##Those 4 need to come after default constructor
        self._modulename = 'WhizardAnalysis'
        self._moduledescription = 'Module to run WHIZARD'
        self.appname = 'whizard'
        self.datatype = 'gen'
        self._paramsToExclude.extend([
            '_optionsdictstr', '_genlevelcutsstr', '_leshouchesfiles',
            '_generatormodels', '_allowedparams', '_wo', '_processlist'
        ])

    def getPDict(self):
        """ Provide predefined parameter dictionary
    """
        return getDict()

    def setEvtType(self, evttype):
        """ Define process. If the process given is not found, when calling :func:`UserJob.append() <ILCDIRAC.Interfaces.API.NewInterface.UserJob.UserJob.append>` a full list is printed.

    :param string evttype: Process to generate
    """
        self._checkArgs({'evttype': types.StringTypes})
        if self.addedtojob:
            self._log.error(
                "Cannot modify this attribute once application has been added to Job"
            )
            return S_ERROR("Cannot modify")
        self.eventType = evttype

    def setGlobalEvtType(self, globalname):
        """ When producing multiple process in one job, it is needed to define this for the output file name.
    It's mandatory to use the :any:`setFullParameterDict` method when using this.
    """
        self._checkArgs({'globalname': types.StringTypes})
        self.globalEventType = globalname

    def setLuminosity(self, lumi):
        """ Optional: Define luminosity to generate

    :param float lumi: Luminosity to generate. Not available if cross section is not known a priori. Use with care.
    """
        self._checkArgs({'lumi': types.FloatType})
        self.luminosity = lumi

    def setRandomSeed(self, randomSeed):
        """ Optional: Define random seed to use. Default is Job ID.

    :param int randomSeed: Seed to use during integration and generation.
    """
        self._checkArgs({'randomSeed': types.IntType})

        self.randomSeed = randomSeed

    def setParameterDict(self, paramdict):
        """ Parameters for Whizard steering files

    :param dict paramdict: Dictionary of parameters for the whizard templates. Most parameters are set on the fly.
    """
        self._checkArgs({'paramdict': types.DictType})
        self.parameterDict = paramdict

    def setGeneratorLevelCuts(self, cutsdict):
        """ Define generator level cuts (to be put in whizard.cut1)

    Refer to http://whizard.hepforge.org/manual_w1/manual005.html#toc12 for details about how to set cuts.

    >>> wh.setGeneratorLevelCuts({'e1e1_o':["cut M of  3 within 10 99999","cut E of  3 within  5 99999"]})

    :param dict cutsdict: Dictionary of cuts
    """
        self._checkArgs({'cutsdict': types.DictType})
        self.generatorLevelCuts = cutsdict

    def setFullParameterDict(self, pdict):
        """ Parameters for Whizard steering files, better than above as much more complete (cannot be more complete)

    >>> pdict = {}
    >>> pdict['process_input'] = {}
    >>> #processes below are not those of the templates, but those of the whizard.prc
    >>> pdict['process_input']['process_id']='h_n1n1'
    >>> pdict['process_input']['sqrts'] = 3000.
    >>> pdict['simulation_input'] = {}
    >>> pdict['simulation_input']['n_events'] = 100
    >>> pdict['beam_input_1'] = {}
    >>> pdict['beam_input_1']['polarization']='1.0 0.0'
    >>> pdict['beam_input_1']['USER_spectrum_mode'] = 11
    >>> pdict['beam_input_2'] = {}
    >>> pdict['beam_input_2']['polarization']='0.0 1.0'
    >>> pdict['beam_input_2']['USER_spectrum_mode'] = -11
    >>> wh.setFullParameterDict(pdict)

    The first key corresponds to the sections of the whizard.in, while the second corresponds to the possible parameters.
    All keys/values can be found in the WHIZARD documentation: http://whizard.hepforge.org/manual_w1/manual005.html#toc11

    :param dict pdict: Dictionnary of parameters
    """
        self._checkArgs({'pdict': types.DictType})

        self.fullParameterDict = pdict
        #self._wo.changeAndReturn(dict)

    def setModel(self, model):
        """ Optional: Define Model

    :param string model: Model to use for generation. Predefined list available in the :mod:`GeneratorModels<ILCDIRAC.Core.Utilities.GeneratorModels.GeneratorModels>` class.
    """
        self._checkArgs({'model': types.StringTypes})

        self.model = model

    def willCut(self):
        """ You need this if you plan on cutting using :mod:`StdhepCut <ILCDIRAC.Interfaces.API.NewInterface.Applications.StdhepCut.StdhepCut>`
    """
        self.willBeCut = True

    def usingGridFiles(self):
        """ Call this if you want to use the grid files that come with the Whizard version used.

    Beware: Depends on the energy and generator cuts, use it if you know what you are doing.
    """
        self.useGridFiles = True

    def setJobIndex(self, index):
        """ Optional: Define Job Index. Added in the file name between the event type and the extension.

    :param string index: Index to use for generation
    """
        self._checkArgs({'index': types.StringTypes})

        self.jobIndex = index

    def dumpWhizardDotIn(self, fname='whizard.in'):
        """ Dump the content of the whizard.in file requested for this application

    :param string fname: filename in which whizard.in is written
    """
        if self.addedtojob:
            self._wo.toWhizardDotIn(fname)
        else:
            self._reportError(
                "Can't dump the whizard.in as there can be further changes")

    def _checkConsistency(self, job=None):
        """ Check the consistency, called from Application
    """
        self._wo = WhizardOptions(self.model)

        if not self.fullParameterDict:
            if not self.energy:
                return S_ERROR('Energy not set')

            if not self.numberOfEvents:
                return S_ERROR('Number of events not set!')

            if not self.eventType:
                return S_ERROR("Process not defined")
        else:
            res = self._wo.checkFields(self.fullParameterDict)
            if not res['OK']:
                return res
            self._wo.changeAndReturn(self.fullParameterDict)
            res = self._wo.getValue("process_input/process_id")
            if not len(res['Value']):
                if self.eventType:
                    if 'process_input' not in self.fullParameterDict:
                        self.fullParameterDict['process_input'] = {}
                    self.fullParameterDict['process_input'][
                        'process_id'] = self.eventType
                else:
                    return S_ERROR("Event type not specified")
            self.eventType = res['Value']

            res = self._wo.getValue("process_input/sqrts")
            if isinstance(res['Value'], (int, long, float)):
                energy = res['Value']
            else:
                energy = eval(res['Value'])
            if not energy:
                if self.energy:
                    if 'process_input' not in self.fullParameterDict:
                        self.fullParameterDict['process_input'] = {}
                    self.fullParameterDict['process_input'][
                        'sqrts'] = self.energy
                    energy = self.energy
                else:
                    return S_ERROR("Energy set to 0")
            self.energy = energy

            res = self._wo.getValue("simulation_input/n_events")
            if isinstance(res['Value'], (int, long, float)):
                numberOfEvents = res['Value']
            else:
                numberOfEvents = eval(res['Value'])
            if not numberOfEvents:
                if self.numberOfEvents:
                    if 'simulation_input' not in self.fullParameterDict:
                        self.fullParameterDict['simulation_input'] = {}
                    self.fullParameterDict['simulation_input'][
                        'n_events'] = self.numberOfEvents
                    numberOfEvents = self.numberOfEvents
                else:
                    return S_ERROR("Number of events set to 0")
            self.numberOfEvents = numberOfEvents

        if not self._processlist:
            return S_ERROR("Process list was not given")

        if self.generatorLevelCuts:
            for process in self.generatorLevelCuts.keys():
                if process not in self.eventType.split():
                    self._log.info(
                        "You want to cut on %s but that process is not to be generated"
                        % process)
            for values in self.generatorLevelCuts.values():
                if not isinstance(values, list):
                    return S_ERROR('Type of %s is not a list, cannot proceed' %
                                   values)
            self._genlevelcutsstr = str(self.generatorLevelCuts)

        if self.eventType:
            processes = self.eventType.split()
            if len(processes) > 1 and not self.globalEventType:
                return S_ERROR(
                    "Global name MUST be defined when producing multiple processes in one job"
                )
            elif self.globalEventType:
                self.eventType = self.globalEventType
            for process in processes:
                if not self._processlist.existsProcess(process)['Value']:
                    self._log.notice("Available processes are:")
                    self._processlist.printProcesses()
                    return S_ERROR('Process %s does not exists' % process)
                else:
                    cspath = self._processlist.getCSPath(process)
                    whiz_file = os.path.basename(cspath)
                    version = whiz_file.replace(".tar.gz", "").replace(
                        ".tgz", "").replace("whizard", "")
                    if self.version:
                        if self.version != version:
                            return S_ERROR(
                                "All processes to consider are not available in the same WHIZARD version"
                            )
                    else:
                        self.version = version
                    self._log.info("Found the process %s in whizard %s" %
                                   (process, self.version))

        if not self.version:
            return S_ERROR('No version found')

        if self.model:
            if not self._generatormodels.hasModel(self.model)['OK']:
                return S_ERROR("Unknown model %s" % self.model)

        if self.outputFile:
            if self.outputFile.count("/"):
                return S_ERROR(
                    "The OutputFile name is a file name, not a path. Remove any / in there"
                )

        if not self.outputFile and self._jobtype == 'User':
            self.outputFile = self.eventType
            if self.jobIndex:
                self.outputFile += "_" + self.jobIndex
            self.outputFile += "_gen.stdhep"

        if self._jobtype != 'User':
            if not self.willBeCut:
                self._listofoutput.append({
                    "outputFile": "@{OutputFile}",
                    "outputPath": "@{OutputPath}",
                    "outputDataSE": '@{OutputSE}'
                })
            self.prodparameters['nbevts'] = self.numberOfEvents
            self.prodparameters['Process'] = self.eventType
            self.prodparameters['model'] = self.model
            self.prodparameters['Energy'] = self.energy
            self.prodparameters['whizardparams'] = self.fullParameterDict
            self.prodparameters['gencuts'] = self.generatorLevelCuts
            self.prodparameters['gridfiles'] = self.useGridFiles

        if not self.fullParameterDict and self.parameterDict:
            for key in self.parameterDict.keys():
                if key not in self._allowedparams:
                    return S_ERROR("Unknown parameter %s" % key)

            self.setParameter('PNAME1', 'e1',
                              "Assuming incoming beam 1 to be electrons")
            self.setParameter('PNAME2', 'E1',
                              "Assuming incoming beam 2 to be positrons")
            self.setParameter('POLAB1', '0.0 0.0',
                              "Assuming no polarization for beam 1")
            self.setParameter('POLAB2', '0.0 0.0',
                              "Assuming no polarization for beam 2")
            self.setParameter('USERB1', 'T',
                              "Will put beam spectrum to True for beam 1")
            self.setParameter('USERB2', 'T',
                              "Will put beam spectrum to True for beam 2")
            self.setParameter('ISRB1', 'T', "Will put ISR to True for beam 1")
            self.setParameter('ISRB2', 'T', "Will put ISR to True for beam 2")

            self.setParameter('EPAB1', 'F', "Will put EPA to False for beam 1")
            self.setParameter('EPAB2', 'F', "Will put EPA to False for beam 2")

            self.setParameter('RECOIL', 'F', "Will set Beam_recoil to False")
            self.setParameter('INITIALS', 'F',
                              "Will set keep_initials to False")
            self.setParameter('USERSPECTRUM', '11',
                              "Will set USER_spectrum_on to +-11")

            self.parameters = ";".join(self.parameters)
        elif self.fullParameterDict:
            self._optionsdictstr = str(self.fullParameterDict)

        return S_OK()

    def _applicationModule(self):
        md1 = self._createModuleDefinition()
        md1.addParameter(
            Parameter("evttype", "", "string", "", "", False, False,
                      "Process to generate"))
        md1.addParameter(
            Parameter("RandomSeed", 0, "int", "", "", False, False,
                      "Random seed for the generator"))
        md1.addParameter(
            Parameter("Lumi", 0, "float", "", "", False, False,
                      "Luminosity of beam"))
        md1.addParameter(
            Parameter("Model", "", "string", "", "", False, False,
                      "Model for generation"))
        md1.addParameter(
            Parameter("SteeringFile", "", "string", "", "", False, False,
                      "Steering file"))
        md1.addParameter(
            Parameter("steeringparameters", "", "string", "", "", False, False,
                      "Specific steering parameters"))
        md1.addParameter(
            Parameter("OptionsDictStr", "", "string", "", "", False, False,
                      "Options dict to create full whizard.in on the fly"))
        md1.addParameter(
            Parameter("GenLevelCutDictStr", "", "string", "", "", False, False,
                      "Generator level cuts to put in whizard.cut1"))
        md1.addParameter(
            Parameter("willCut", False, "bool", "", "", False, False,
                      "Will cut after"))
        md1.addParameter(
            Parameter("useGridFiles", True, "bool", "", "", False, False,
                      "Will use grid files"))
        md1.addParameter(
            Parameter("debug", False, "bool", "", "", False, False,
                      "debug mode"))
        return md1

    def _applicationModuleValues(self, moduleinstance):
        moduleinstance.setValue("evttype", self.eventType)
        moduleinstance.setValue("RandomSeed", self.randomSeed)
        moduleinstance.setValue("Lumi", self.luminosity)
        moduleinstance.setValue("Model", self.model)
        moduleinstance.setValue("SteeringFile", self.steeringFile)
        moduleinstance.setValue("steeringparameters", self.parameters)
        moduleinstance.setValue("OptionsDictStr", self._optionsdictstr)
        moduleinstance.setValue("GenLevelCutDictStr", self._genlevelcutsstr)
        moduleinstance.setValue("willCut", self.willBeCut)
        moduleinstance.setValue("useGridFiles", self.useGridFiles)
        moduleinstance.setValue("debug", self.debug)

    def _userjobmodules(self, stepdefinition):
        res1 = self._setApplicationModuleAndParameters(stepdefinition)
        res2 = self._setUserJobFinalization(stepdefinition)
        if not res1["OK"] or not res2["OK"]:
            return S_ERROR('userjobmodules failed')
        return S_OK()

    def _prodjobmodules(self, stepdefinition):
        res1 = self._setApplicationModuleAndParameters(stepdefinition)
        res2 = self._setOutputComputeDataList(stepdefinition)
        if not res1["OK"] or not res2["OK"]:
            return S_ERROR('prodjobmodules failed')
        return S_OK()

    def setParameter(self, parameter, defaultValue, docString):
        if parameter not in self.parameterDict:
            self._log.info(docString)
            self.parameters.append("%s=%s" % (parameter, defaultValue))
        else:
            self.parameters.append("%s=%s" %
                                   (parameter, self.parameterDict[parameter]))