Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-05-13 08:03:04

0001 #!/usr/bin/env python3
0002 """
0003 run_all_energies.py - EIC Simulation Runner
0004 
0005 This script runs particle physics simulations for the Electron-Ion Collider (EIC) 
0006 using npsim and eicrecon across multiple beam energy configurations and 
0007 Q² values, generating simulation data files.
0008 
0009 Features:
0010 - Sets up the environment with appropriate library paths
0011 - Runs npsim simulations with specified parameters
0012 - Processes output files with eicrecon for reconstruction
0013 - Supports customization of simulation parameters via command-line arguments
0014 - Runs with sensible defaults when no arguments are provided
0015 
0016 Usage:
0017     ./run_all_energies.py                      # Run with default settings
0018     ./run_all_energies.py [options]            # Run with custom options
0019 
0020 Default behavior:
0021     Without any arguments, the script will:
0022     - Use /mnt/dd4hep-plugin/firebird_steering.py as the steering file
0023     - Run simulations for beam energies: 5x41, 10x100, 18x275
0024     - Use minimum Q² values: 1, 100, 1000
0025     - Process 5 events per configuration
0026     - Use the detector path from DETECTOR_PATH environment variable
0027       or /opt/detector/epic-main/share/epic/epic_full.xml as fallback
0028     - Use /var/project/prefix/lib for plugin libraries
0029     - Save output files to the current directory
0030 
0031 Examples:
0032     ./run_all_energies.py                      # Run with defaults
0033     ./run_all_energies.py --events 10          # Run with 10 events per configuration
0034     ./run_all_energies.py -o /path/to/outputs  # Save outputs to specific directory
0035     ./run_all_energies.py --plugin-path /custom/lib/path  # Use custom plugin path
0036     ./run_all_energies.py --steering /path/to/steering.py --beams 5x41 10x100
0037     ./run_all_energies.py --minq2s 1 100       # Run with only Q² values 1 and 100
0038 """
0039 
0040 import subprocess
0041 import os
0042 import argparse
0043 
0044 
0045 def setup_environment(plugin_path='prefix/lib'):
0046     """
0047     Updates the LD_LIBRARY_PATH environment variable to include custom library paths.
0048     
0049     Parameters:
0050         plugin_path (str): The library path to prepend to LD_LIBRARY_PATH
0051     """
0052     # Get the current LD_LIBRARY_PATH value from the environment
0053     current_ld_library_path = os.environ.get('LD_LIBRARY_PATH', '')
0054 
0055     # Prepend the prefix to the LD_LIBRARY_PATH
0056     new_ld_library_path = (plugin_path + ':' + current_ld_library_path) if current_ld_library_path else plugin_path
0057 
0058     # Set the new LD_LIBRARY_PATH in the environment
0059     os.environ['LD_LIBRARY_PATH'] = new_ld_library_path
0060     print("Updated LD_LIBRARY_PATH:", os.environ['LD_LIBRARY_PATH'])
0061 
0062 
0063 def run_command(command):
0064     """
0065     Executes a given command in the shell and prints the output as it appears.
0066 
0067     Parameters:
0068         command (list): A list containing the command and its arguments.
0069         
0070     Returns:
0071         int: The return code of the executed command.
0072     """
0073     print("Executing:", " ".join(command))
0074     process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
0075 
0076     # Print output as it appears
0077     while True:
0078         output = process.stdout.readline()
0079         if output == '' and process.poll() is not None:
0080             break
0081         if output:
0082             print(output.strip())
0083 
0084     # Handle errors if there are any
0085     err = process.stderr.read()
0086     if err:
0087         print("Error:", err)
0088 
0089     # Check the process return code
0090     return_code = process.wait()
0091     print("Command completed with return code:", return_code)
0092     print("\n" + "-"*50 + "\n")
0093     return return_code
0094 
0095 
0096 def get_hepmc_path(beam, minq2):
0097     """
0098     Generates the path to the HepMC input file based on beam and minQ2 parameters.
0099     
0100     Parameters:
0101         beam (str): The energy configuration for the beam.
0102         minq2 (int): The minimum Q2 value.
0103         
0104     Returns:
0105         str: The path to the HepMC file.
0106     """
0107     return f"root://dtn-eic.jlab.org//volatile/eic/EPIC/EVGEN/DIS/NC/{beam}/minQ2={minq2}/pythia8NCDIS_{beam}_minQ2={minq2}_beamEffects_xAngle=-0.025_hiDiv_1.hepmc3.tree.root"
0108 
0109 
0110 def get_base_name(beam, minq2, event_num, output_dir=None):
0111     """
0112     Generates the base filename for output files.
0113     
0114     Parameters:
0115         beam (str): The energy configuration for the beam.
0116         minq2 (int): The minimum Q2 value.
0117         event_num (int): The number of events to simulate.
0118         output_dir (str, optional): Directory for output files. If provided,
0119                                    the path will be prepended to the filename.
0120         
0121     Returns:
0122         str: The base filename (with path) for output files.
0123     """
0124     filename = f"py8_dis-cc_{beam}_minq2-{minq2}_minp-150mev_vtxcut-5m_nevt-{event_num}"
0125     
0126     if output_dir:
0127         # Ensure output directory exists
0128         os.makedirs(output_dir, exist_ok=True)
0129         return os.path.join(output_dir, filename)
0130     
0131     return filename
0132 
0133 
0134 def run_simulation(beam, minq2, event_num, detector_path, steering_file, output_dir=None):
0135     """
0136     Runs the simulation for a given beam, Q2 value, and event number, then converts the output file.
0137 
0138     Parameters:
0139         beam (str): The energy configuration for the beam.
0140         minq2 (int): The minimum Q2 value.
0141         event_num (int): The number of events to simulate.
0142         detector_path (str): Path to the detector configuration XML file.
0143         steering_file (str): Path to the steering file for npsim.
0144         output_dir (str, optional): Directory to store output files.
0145         
0146     Returns:
0147         bool: True if the simulation completed successfully, False otherwise.
0148     """
0149     # Construct the input file URL
0150     url = get_hepmc_path(beam, minq2)
0151 
0152     # Construct the output file name
0153     output_base = get_base_name(beam, minq2, event_num, output_dir)
0154     output_edm4hep = output_base + ".edm4hep.root"
0155     output_evttxt = output_base + ".evt.txt"
0156     event_prefix = f"CC_{beam}_minq2_{minq2}"
0157 
0158     # Command for npsim
0159     npsim_command = [
0160         "npsim",
0161         "--compactFile", detector_path,
0162         "-N", str(event_num),
0163         "--inputFiles", url,
0164         "--random.seed", "1",
0165         "--outputFile", output_edm4hep,
0166         "--steeringFile", steering_file
0167     ]
0168 
0169     # Run the simulation
0170     if run_command(npsim_command) != 0:
0171         print(f"Error running npsim for beam={beam}, minq2={minq2}")
0172         return False
0173 
0174     # Command for converting the output file
0175     reconstruction_command = [
0176         "eicrecon",
0177         f"-Pjana:debug_plugin_loading=1",
0178         f"-Pjana:nevents={event_num}",
0179         f"-Pjana:timeout=0",
0180         f"-Ppodio:output_file={output_base}.edm4eic.root",
0181         f"-Pdd4hep:xml_files={detector_path}",
0182         f"{output_base}.edm4hep.root"
0183     ]
0184 
0185     # Run the conversion
0186     if run_command(reconstruction_command) != 0:
0187         print(f"Error running eicrecon for beam={beam}, minq2={minq2}")
0188         return False
0189         
0190     return True
0191 
0192 
0193 def main():
0194     """
0195     Main function that parses command-line arguments and runs the simulation.
0196     """
0197     # Define default paths and values
0198     default_detector_base = os.getenv('DETECTOR_PATH', '/opt/detector/epic-main/share/epic/')
0199     default_detector_path = os.path.join(default_detector_base, "epic_full.xml")
0200     default_steering_path = "firebird_steering.py"
0201     default_plugin_path = "prefix/lib"
0202     default_output_path = "tmp"
0203     
0204     parser = argparse.ArgumentParser(
0205         description="EIC Simulation Runner",
0206         formatter_class=argparse.ArgumentDefaultsHelpFormatter
0207     )
0208     
0209     # Add command-line arguments
0210     parser.add_argument(
0211         "--steering", 
0212         default=default_steering_path,
0213         help="Path to the steering file for npsim"
0214     )
0215     parser.add_argument(
0216         "--detector", 
0217         default=default_detector_path,
0218         help="Path to the detector configuration XML file"
0219     )
0220     parser.add_argument(
0221         "--events", 
0222         type=int, 
0223         default=5,
0224         help="Number of events to simulate per configuration"
0225     )
0226     parser.add_argument(
0227         "--beams", 
0228         nargs="+", 
0229         default=['5x41', '10x100', '18x275'],
0230         help="Beam energy configurations to simulate"
0231     )
0232     parser.add_argument(
0233         "--minq2s", 
0234         nargs="+", 
0235         type=int, 
0236         default=[1, 100, 1000],
0237         help="Minimum Q2 values to simulate"
0238     )
0239     parser.add_argument(
0240         "--skip-setup", 
0241         action="store_true",
0242         help="Skip environment setup step"
0243     )
0244     parser.add_argument(
0245         "--plugin-path",
0246         default=default_plugin_path,
0247         help="Path to plugin libraries to be added to LD_LIBRARY_PATH"
0248     )
0249     parser.add_argument(
0250         "-o", "--output",
0251         dest="output_dir",
0252         default=default_output_path,
0253         help="Directory for output files"
0254     )
0255     
0256     args = parser.parse_args()
0257     
0258     # Setup environment if not skipped
0259     if not args.skip_setup:
0260         setup_environment(args.plugin_path)
0261     
0262     # Validate detector path
0263     detector_path = args.detector
0264     if not os.path.exists(detector_path):
0265         print(f"Error: Detector file not found: {detector_path}")
0266         return 1
0267         
0268     # Validate steering file
0269     steering_file = args.steering
0270     if not os.path.exists(steering_file):
0271         print(f"Error: Steering file not found: {steering_file}")
0272         return 1
0273     
0274     # Create output directory if specified
0275     if args.output_dir:
0276         os.makedirs(args.output_dir, exist_ok=True)
0277         print(f"Output files will be saved to: {args.output_dir}")
0278     
0279     # Run simulations for each combination
0280     for beam in args.beams:
0281         for minq2 in args.minq2s:
0282             print("\n" + "-" * 100)
0283             print(f"Running simulation for beam={beam}, minq2={minq2}, events={args.events}")
0284             success = run_simulation(
0285                 beam=beam,
0286                 minq2=minq2, 
0287                 event_num=args.events,
0288                 detector_path=detector_path,
0289                 steering_file=steering_file,
0290                 output_dir=args.output_dir
0291             )
0292             print("\n" + "/" * 100)
0293             if not success:
0294                 print(f"Simulation failed for beam={beam}, minq2={minq2}")
0295     
0296     return 0
0297 
0298 
0299 if __name__ == "__main__":
0300     exit(main())