Warning, /epic/bin/generate_prim_file is written in an unsupported language. File is not indexed.
0001 #!/usr/bin/env python3
0002
0003 # same as make_dawn_views but stops at generating the prim file.
0004 # W. Armstrong (ANL), original bash script
0005 # C. Peng (ANL), translate to python and add flexible run time for simulation
0006
0007 import os
0008 import signal
0009 import subprocess
0010 import argparse
0011 import atexit
0012 import time
0013 from datetime import datetime
0014 import fcntl
0015
0016
0017 def readline_nonblocking(output):
0018 fd = output.fileno()
0019 fl = fcntl.fcntl(fd, fcntl.F_GETFL)
0020 fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
0021 try:
0022 return output.readline()
0023 except:
0024 return ''
0025
0026
0027 # arguments
0028 parser = argparse.ArgumentParser()
0029
0030 parser.add_argument('-c', '--compact-file', type=str, dest='compact',
0031 default=os.path.join(os.environ.get('DETECTOR_PATH', '.'), 'epic.xml'),
0032 help='Top level compact file for detectors')
0033
0034 parser.add_argument('-s', '--skip', type=int,
0035 default=0,
0036 help='Number of events number to skip in the input')
0037
0038 parser.add_argument('-i', '--input', type=str,
0039 default='scripts/input_data/few_events.hepmc',
0040 help='Input hepmc file')
0041
0042 parser.add_argument('-o', '--output-dir', type=str, dest='out_dir',
0043 default='sim_output',
0044 help='output directory')
0045
0046 parser.add_argument('-D', '--detector-only', action='store_true', dest='detector_only',
0047 help='only generate the prim files for the detector geometry')
0048
0049 parser.add_argument('-t', '--tag', type=str,dest='file_tag',
0050 default='view',
0051 help='Output file tag')
0052
0053 parser.add_argument('--timeout', type=int,
0054 default=3600,
0055 help='Timeout in seconds')
0056
0057 parser.add_argument('passthrough', nargs='*')
0058
0059 args = parser.parse_args()
0060
0061 macro = 'macro/dawn_picture.mac' if args.detector_only else 'macro/dawn_picture2.mac'
0062
0063 # raise error if cannot create a temporary working dir
0064 # os.makedirs('dawn_view_tmp', exist_ok=False)
0065 os.makedirs(args.out_dir, exist_ok=True)
0066
0067 # use absolute path so the chdir does not affect them
0068 args.input = os.path.abspath(args.input)
0069 args.out_dir = os.path.abspath(args.out_dir)
0070 args.compact = os.path.abspath(args.compact)
0071 macro = os.path.abspath(macro)
0072
0073 # adjust fiber radius to reduce the number of fibers
0074 #compact_dir = os.path.dirname(os.path.realpath(args.compact))
0075 #ci_ecal = os.path.join(compact_dir, 'compact', 'ci_ecal_scfi.xml')
0076 #os.system('sed -i \'s/radius=\"EcalEndcapP_FiberRadius\"/radius=\"EcalEndcapP_FiberRadius*10\"/\' {}'.format(ci_ecal))
0077
0078 prim_file = 'g4_0000.prim'
0079 dawn_env = os.environ.copy()
0080 dawn_env['DAWN_BATCH'] = 'a'
0081 # sdir = os.path.dirname(os.path.realpath(__file__))
0082
0083 # Using a python warpper such as npsim introduces some problem in managing the subprocess.
0084 # The process1 managed by subprocess will generate another process with proc2_pid = proc1_pid + 1, which will not
0085 # be terminated by terminating or killing the process1.
0086 # In addition, running Geant4 with vis mode will never exit automatically (it waits for input).
0087 # Thus the created process 2 will occupy the system resources.
0088 sim_cmd = ['npsim', '--runType', 'vis',
0089 '--compact', args.compact,
0090 '--inputFiles', args.input,
0091 '--outputFile', 'derp.root',
0092 '--numberOfEvents', '1',
0093 '--skipNEvents', str(args.skip),
0094 '--macroFile', macro]
0095
0096 start = datetime.now()
0097 elapse = datetime.now() - start
0098 last_update = datetime.now()
0099 finished = False
0100
0101 # run simulation
0102 print(' '.join(sim_cmd))
0103 p = subprocess.Popen(args=sim_cmd, env=dawn_env,
0104 stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE,
0105 preexec_fn=os.setsid)
0106 __child_pid = p.pid
0107 while elapse.seconds < args.timeout:
0108 line = readline_nonblocking(p.stdout)
0109 elapse = datetime.now() - start
0110 time_left = args.timeout - elapse.seconds
0111 time_str = '[{:02d}:{:02d}]'.format(elapse.seconds // 60, elapse.seconds % 60)
0112
0113 if time_left < 10:
0114 print('{} === TIMEOUT ===: Terminating in {:d} seconds'.format(time_str, time_left))
0115
0116 if line:
0117 decoded_line = line.decode('utf-8').strip()
0118 print('{} {}'.format(time_str, decoded_line))
0119 # what we are looking for
0120 if decoded_line == 'File {} is generated.'.format(prim_file):
0121 print('{} === FINISHED ===: Got the prim file, terminating.'.format(time_str))
0122 finished = True
0123 break
0124 if decoded_line == 'Idle>':
0125 p.stdin.write(b'exit')
0126 break
0127 # do not sleep
0128 continue
0129
0130 # ended early before file
0131 if p.poll() is not None:
0132 print(p.poll())
0133 break
0134
0135 time.sleep(1)
0136
0137 try:
0138 os.killpg(os.getpgid(p.pid), signal.SIGTERM)
0139 except ProcessLookupError:
0140 pass # assume process is dead
0141
0142 # revert the change
0143 #os.system('sed -i \'s/radius=\"EcalEndcapP_FiberRadius*10\"/radius=\"EcalEndcapP_FiberRadius\"/\' {}'.format(ci_ecal))
0144
0145 line = b'stderr outputs:\n'
0146 while line:
0147 print(line.decode('utf-8'), end='')
0148 line = readline_nonblocking(p.stderr)
0149
0150 if finished:
0151 print('Simulation finished')
0152 else:
0153 print('Simulation failed')
0154 exit(1)
0155
0156 # move the prim files (which can be quite large)
0157 # to the local pipeline storage path
0158 os.system('mv g4_0000.prim {}/{}.prim'.format(args.out_dir,args.file_tag))