From d515184f1fae69191803acf864263bc1c4d86d37 Mon Sep 17 00:00:00 2001
From: Chao Peng <cpeng@anl.gov>
Date: Tue, 27 Jul 2021 19:40:03 +0000
Subject: [PATCH] change the make_dawn_view script to flexibly run the
 simulation

---
 .gitlab-ci.yml                      |  13 +-
 bin/make_dawn_views                 | 347 +++++++++++++---------------
 compact/ecal_barrel_interlayers.xml |   6 +-
 scripts/view1/generate_eps          |   2 +-
 4 files changed, 177 insertions(+), 191 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2e14a658..4ddfe731 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -82,13 +82,14 @@ compile:
   stage: docs
   before_script:
     - source .local/bin/env.sh
-    - sed -i 's?<support inside?<\!--support inside?' compact/ecal_barrel_hybrid.xml 
-    - sed -i 's?</support>?</support-->?' compact/ecal_barrel_hybrid.xml
-    - sed -i 's?<fiber material?<\!--fiber material?' compact/ecal_barrel_hybrid.xml 
-    - sed -i 's?</fiber>?</fiber-->?' compact/ecal_barrel_hybrid.xml
-    - echo $DETECTOR_PATH
-    - cp compact/ecal_barrel_hybrid.xml ${DETECTOR_PATH}/compact/ecal_barrel_hybrid.xml
+      #    - sed -i 's?<support inside?<\!--support inside?' compact/ecal_barrel_hybrid.xml 
+      #    - sed -i 's?</support>?</support-->?' compact/ecal_barrel_hybrid.xml
+      #    - sed -i 's?<fiber material?<\!--fiber material?' compact/ecal_barrel_interlayers.xml 
+      #    - sed -i 's?</fiber>?</fiber-->?' compact/ecal_barrel_interlayers.xml
+      #    - echo $DETECTOR_PATH
+      #    - cp compact/ecal_barrel_interlayers.xml ${DETECTOR_PATH}/compact/ecal_barrel_interlayers.xml
     - env
+    - pip3 install psutil
   needs:
     - ["common:detector"]
 
diff --git a/bin/make_dawn_views b/bin/make_dawn_views
index ea438d27..26f6f074 100755
--- a/bin/make_dawn_views
+++ b/bin/make_dawn_views
@@ -1,183 +1,166 @@
-#!/bin/bash
-
-#git clone --depth 1 https://eicweb.phy.anl.gov/EIC/datasets.git
-export DAWN_PS_PREVIEWER="ls "
-export G4DAWNFILE_VIEWER="ls -lrth "
-export G4DAWNFILE_PS_VIEWER="ls "
-
-function print_the_help {
-  echo "USAGE: ${0} [-s <skip_events>] -d <dawn_run_dir> "
-  echo "  OPTIONS: "
-  echo "            -D,--detector-only            Only generate the prim files for the detector geometry."
-  echo "            -s,--skip <skip_events>       Required run number"
-  echo "            -i,--input <input_file>       Input hepmc file"
-  echo "            -d,--dawn-dir <dawn_run_dir>  Directory with the .DAWN files and a generate script "
-  echo "            -t,--tag <file_tag>           Output file tag"
-  exit 
-}
-
-function yes_or_no {
-  while true; do
-    read -p "$* [y/n]: " yn
-    case $yn in
-      [Yy]*) return 0 ;;
-      [Nn]*) echo "No entered" ; return 1 ;;
-    esac
-  done
-}
-
-if [[ $# -eq 0 ]] ; then
-  print_the_help
-  exit 
-fi
-
-SKIP_EVENTS=0
-DETECTOR_ONLY=0
-FILE_TAG="view"
-DAWN_RUN_DIR="scripts/view1"
-DETECTOR_FILE="${DETECTOR_PATH}/athena.xml"
-
-POSITIONAL=()
-while [[ $# -gt 0 ]]
-do
-  key="$1"
-
-  case $key in
-    -h|--help)
-      shift # past argument
-      print_the_help
-      ;;
-    -c|--compact-file)
-      DETECTOR_FILE="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    -s|--skip)
-      SKIP_EVENTS="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    -i|--input)
-      INPUT_FILE="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    -o|--ouput-dir)
-      OUTPUT_DIR="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    -D|--detector-only)
-      DETECTOR_ONLY=1
-      shift # past argument
-      #shift # past value
-      ;;
-    -d|--dawn-dir)
-      DAWN_RUN_DIR=$2
-      shift # past argument
-      shift # past value
-      ;;
-    -t|--tag)
-      FILE_TAG=$2
-      shift # past argument
-      shift # past value
-      ;;
-    *)    # unknown option
-      #POSITIONAL+=("$1") # save it in an array for later
-      echo "unknown option $1"
-      print_the_help
-      shift # past argument
-      ;;
-  esac
-done
-set -- "${POSITIONAL[@]}" # restore positional parameters
-
-
-rm -f *.prim
-
-if [  "${DETECTOR_ONLY}" -eq "1" ] ; then
-
-  # timeout --preserve-status --signal=SIGTERM 120s \
-  ./scripts/run_detector_simulation.py  \
-    --compact ${DETECTOR_PATH}/athena.xml \
-  -i scripts/input_data/few_events.hepmc \
-  -o derp.root -n 1 \
-  --ui csh --vis -b -m macro/dawn_picture.mac &
-
-timeout=200
-while [ $timeout -ge 0 ] && [ ! -f "g4_0000.prim" ]
-do
-  echo "terminating in $timeout secs ..."
-  sleep 5
-  ((timeout=timeout-5))
-done
-kill %1
-
-else 
-
-  echo " Running simulation for tracks"
-  # timeout --preserve-status --signal=SIGTERM 120s \
-  ./scripts/run_detector_simulation.py \
-    --compact ${DETECTOR_PATH}/athena.xml \
-  -i scripts/input_data/few_events.hepmc \
-  -o derp.root -s ${SKIP_EVENTS} -n 1 \
-  --ui csh --vis -b -m macro/dawn_picture2.mac & 
-
-sleep 40 
-kill %1
-
-fi
-
-#./scripts/run_detector_simulation.py -i scripts/input_data/few_events.hepmc \
-#  -o derp.root -s 2 -n 1 \
-#  --ui csh --vis -b -m macro/dawn_picture2.mac & 
-#
-#sleep 20 
-#kill %1
-
-#./scripts/run_detector_simulation.py -i scripts/input_data/few_events.hepmc \
-#  -o derp.root -s 5 -n 1 \
-#  --ui csh --vis -b -m macro/dawn_picture2.mac & 
-#
-#sleep 20 
-#kill %1
-#
-#./scripts/run_detector_simulation.py -i scripts/input_data/few_events.hepmc \
-#  -o derp.root -s 6 -n 1 \
-#  --ui csh --vis -b -m macro/dawn_picture2.mac & 
-#
-#sleep 20 
-#kill %1
-
-[[ -f "g4_0000.prim" ]]  ||  exit -1
-
-echo "simulating done" 
-#npsim --runType vis \
-#      -v WARNING \
-#      --macroFile macro/dawn_picture.mac \
-#      --numberOfEvents 1 \
-#      --compactFile topside.xml \
-#      --inputFiles scripts/input_data/few_events.hepmc \
-#      --outputFile  derp.root \
-#      --dumpSteeringFile >> derp.out
-
-
-ls -lrth
-mkdir -p images
-#mkdir -p images/prim
-
-pushd ${DAWN_RUN_DIR}
-
-if [  "${DETECTOR_ONLY}" -eq "1" ] ; then
-  ./generate_eps -t ${FILE_TAG} -i ../../g4_0000.prim
-else 
-  ./generate_eps -t ${FILE_TAG} -i ../../g4_0000.prim
-fi
-ls -lrth
-
-cp *.pdf ../../images/.
-cp *.png ../../images/.
-#cp *.prim ../../images/prim/.
-popd
-
+#!/usr/local/bin/python
+
+# get dawn view of detectors
+# W. Armstrong (ANL), original bash script
+# C. Peng (ANL), translate to python and add flexible run time for simulation
+
+import os
+import signal
+import subprocess
+import argparse
+import atexit
+import time
+from datetime import datetime
+import fcntl
+import psutil
+
+
+def readline_nonblocking(output):
+    fd = output.fileno()
+    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+    try:
+        return output.readline()
+    except:
+        return ''
+
+
+# arguments
+parser = argparse.ArgumentParser()
+
+parser.add_argument('-c', '--compact-file', type=str, dest='compact',
+        default=os.path.join(os.environ.get('DETECTOR_PATH', '.'), 'athena.xml'),
+        help='Top level compact file for detectors')
+
+parser.add_argument('-s', '--skip', type=int,
+        default=0,
+        help='Number of events number to skip in the input')
+
+parser.add_argument('-i', '--input', type=str,
+        default='scripts/input_data/few_events.hepmc',
+        help='Input hepmc file')
+
+parser.add_argument('-o', '--output-dir', type=str, dest='out_dir',
+        default='images',
+        help='output directory')
+
+parser.add_argument('-D', '--detector-only', action='store_true', dest='detector_only',
+        help='only generate the prim files for the detector geometry')
+
+parser.add_argument('-d', '--dawn-dir', type=str, dest='dawn_dir',
+        default='scripts/view1',
+        help='Directory to dawn script dir (with .DAWN files and a generate_eps script)')
+
+parser.add_argument('-t', '--tag', type=str,
+        default='view',
+        help='Output file tag')
+
+parser.add_argument('--timeout', type=int,
+        default=60,
+        help='Timeout in seconds')
+
+args = parser.parse_args()
+
+macro = 'macro/dawn_picture.mac' if args.detector_only else 'macro/dawn_picture2.mac'
+
+# raise error if cannot create a temporary working dir
+# os.makedirs('dawn_view_tmp', exist_ok=False)
+os.makedirs(args.out_dir, exist_ok=True)
+
+# use absolute path so the chdir does not affect them
+args.input = os.path.abspath(args.input)
+args.out_dir = os.path.abspath(args.out_dir)
+args.compact = os.path.abspath(args.compact)
+macro = os.path.abspath(macro)
+
+prim_file = 'g4_0000.prim'
+dawn_env = os.environ.copy()
+dawn_env['DAWN_BATCH'] = 'a'
+# sdir = os.path.dirname(os.path.realpath(__file__))
+
+# Using a python warpper such as npsim introduces some problem in managing the subprocess.
+# The process1 managed by subprocess will generate another process with proc2_pid = proc1_pid + 1, which will not
+# be terminated by terminating or killing the process1.
+# In addition, running Geant4 with vis mode will never exit automatically (it waits for input).
+# Thus the created process 2 will occupy the system resources.
+sim_cmd = ['npsim', '--runType', 'vis',
+        '--compact', args.compact,
+        '--inputFiles', args.input,
+        '--outputFile', 'derp.root',
+        '--numberOfEvents', '1',
+        '--skipNEvents', str(args.skip),
+        '--macroFile', macro]
+
+start = datetime.now()
+elapse = datetime.now() - start
+last_update = datetime.now()
+finished = False
+
+# run simulation
+print(' '.join(sim_cmd))
+p = subprocess.Popen(args=sim_cmd, env=dawn_env,
+                     stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+__child_pid = p.pid
+while elapse.seconds < args.timeout:
+    line = readline_nonblocking(p.stdout)
+    elapse = datetime.now() - start
+    time_left = args.timeout - elapse.seconds
+    time_str = '[{:02d}:{:02d}]'.format(elapse.seconds // 60, elapse.seconds % 60)
+
+    if time_left < 10:
+        print('{} === TIMEOUT ===: Terminating in {:d} seconds'.format(time_str, time_left))
+
+    if line:
+        decoded_line = line.decode('utf-8').strip()
+        print('{} {}'.format(time_str, decoded_line))
+        # what we are looking for
+        if decoded_line == 'File  {}  is generated.'.format(prim_file):
+            print('{} === FINISHED ===: Got the prim file, terminating.'.format(time_str))
+            finished = True
+            break
+        if decoded_line == 'Idle>':
+            p.stdin.write(b'exit')
+            break
+        # do not sleep
+        continue
+
+    # ended early before file
+    if p.poll() is not None:
+        print(p.poll())
+        break
+
+    time.sleep(1)
+
+p.kill()
+# use to kill the subprocess generated from the python wrapper
+# this is unsafe so maybe more checks required
+for proc in psutil.process_iter():
+    pinfo = proc.as_dict(attrs=['pid', 'name', 'create_time'])
+    if pinfo['pid'] == p.pid + 1 and pinfo['name'] == 'python':
+        print('kill {}, generated from {}'.format(pinfo, p.pid))
+        os.kill(pinfo['pid'], signal.SIGTERM)
+
+line = b'stderr outputs:\n'
+while line:
+    print(line.decode('utf-8'), end='')
+    line = readline_nonblocking(p.stderr)
+
+if finished:
+    print('Simulation finished')
+else:
+    print('Simulation failed')
+    exit(1)
+
+
+# generate DAWN images
+prim_file = os.path.abspath(prim_file)
+owd = os.getcwd()
+os.chdir(args.dawn_dir)
+subprocess.run(['./generate_eps', '-t', args.tag, '-i', prim_file])
+subprocess.run(['ls', '-lrth'])
+
+# upload the results
+os.system('cp *.pdf {}'.format(args.out_dir))
+os.system('cp *.png {}'.format(args.out_dir))
+os.chdir(owd)
 
diff --git a/compact/ecal_barrel_interlayers.xml b/compact/ecal_barrel_interlayers.xml
index fbdf6ebe..3963cb71 100644
--- a/compact/ecal_barrel_interlayers.xml
+++ b/compact/ecal_barrel_interlayers.xml
@@ -127,7 +127,8 @@
             sensitive="yes"
             radius="EcalBarrel_FiberRadius"
             spacing_x="EcalBarrel_FiberXSpacing"
-            spacing_z="EcalBarrel_FiberZSpacing"/>
+            spacing_z="EcalBarrel_FiberZSpacing">
+          </fiber>
         </slice>
         <slice material="CarbonFiber" thickness="EcalBarrel_CarbonThickness" vis="AnlGold"/>
         <slice material="Air" thickness="EcalBarrel_LayerSpacing " vis="AnlGold"/>
@@ -141,7 +142,8 @@
             sensitive="yes"
             radius="EcalBarrel_FiberRadius"
             spacing_x="EcalBarrel_FiberXSpacing"
-            spacing_z="EcalBarrel_FiberZSpacing"/>
+            spacing_z="EcalBarrel_FiberZSpacing">
+          </fiber>
         </slice>
       </layer>
     </detector>
diff --git a/scripts/view1/generate_eps b/scripts/view1/generate_eps
index aae587cb..bb206495 100755
--- a/scripts/view1/generate_eps
+++ b/scripts/view1/generate_eps
@@ -60,7 +60,7 @@ pdftoppm ${FILE_TAG}.pdf ${FILE_TAG} -png -singlefile -cropbox
 # Top view
 dawncut 0 1 0 1 ${INPUT_FILE} ${FILE_TAG}_temp0.prim 
 dawncut 0 -1 0 1 ${FILE_TAG}_temp0.prim  ${FILE_TAG}.prim
-../../bin/dawn_tweak --theta 270 --mag 20
+../../bin/dawn_tweak --theta 270 --mag 10
 dawn -d ${FILE_TAG}.prim 
 ps2pdf ${FILE_TAG}.eps ${FILE_TAG}_top_full.pdf
 gs -o ${FILE_TAG}_top.pdf -sDEVICE=pdfwrite \
-- 
GitLab