Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:14:56

0001 #!/bin/bash
0002 
0003 ##############################################################################################################################################################################
0004 # Golden Run List Generation Script
0005 #
0006 # Purpose:
0007 #   This script compiles a final list of "Golden Runs" for sPHENIX analysis. The selection criteria are:
0008 #     • Run contains ≥1M events (and runnumber ≥47289 unless 'noRunNumberLimit' is specified).
0009 #     • Calorimeter QA designates EMCal, IHCal, and OHCal as "Golden."
0010 #     • Runtime exceeds 5 minutes.
0011 #     • MBD (minimum bias) livetime is above 80%.
0012 #     • (Optional) Runs missing bad tower maps can be removed if 'removeRunsWithMissingMaps' is given.
0013 #     • (Optional) Runs without a magnet_on='t' entry in 'magnet_info' can be removed if 'removeNoMagnet' is specified.
0014 #   After constructing this list, the script may also create DST .list files and examine which runs succeeded or failed in generating those lists.
0015 #
0016 # Main Steps:
0017 #   1) FileCatalog extraction:
0018 #       - Retrieve runs with ≥1M events.
0019 #         - If 'noRunNumberLimit' is omitted, an additional runnumber ≥47289 criterion is applied.
0020 #   2) Calo QA filtering:
0021 #       - Intersect these runs with the Production_write database to ensure EMCal, IHCal, and OHCal each classify them as Golden.
0022 #   3) Apply a >5-minute runtime cut.
0023 #   4) Enforce an MBD livetime >80%.
0024 #   5) Optionally remove runs lacking valid bad tower maps.
0025 #   6) Optionally remove runs with no magnet_on='t' if 'removeNoMagnet' is specified.
0026 #   7) Produce a final run list, optionally create DST .list files, and record which runs succeeded or failed to generate those lists.
0027 #   8) If 'noRunNumberLimit' is used, a summary comparison is displayed between no-run-limit and run≥47289 scenarios.
0028 #
0029 # Usage:
0030 #   ./GoldenRunList_ConductorFile.sh [removeRunsWithMissingMaps] [dontGenerateFileLists] [noRunNumberLimit] [removeNoMagnet]
0031 #     - removeRunsWithMissingMaps : Exclude runs missing bad tower maps.
0032 #     - dontGenerateFileLists     : Omit creation of DST .list files.
0033 #     - noRunNumberLimit          : Omit the runnumber≥47289 cutoff.
0034 #     - removeNoMagnet            : Exclude runs lacking magnet_on='t' in magnet_info.
0035 #
0036 # Outputs:
0037 #   - Final run list: ../dst_list/Final_RunNumbers_After_All_Cuts.txt (plus an optional ge47289 variant).
0038 #   - A local Full_ppGoldenRunList_Version1.list for DST creation (unless suppressed).
0039 #   - Console summaries for each step, plus optional no-run-limit comparisons.
0040 ##############################################################################################################################################################################
0041 
0042 ########################################
0043 # GLOBAL STYLES
0044 ########################################
0045 BOLD="\e[1m"
0046 RESET="\e[0m"
0047 GREEN="\e[32m"
0048 CYAN="\e[36m"
0049 MAGENTA="\e[35m"
0050 YELLOW="\e[33m"
0051 
0052 ########################################
0053 # FUNCTIONS
0054 ########################################
0055 
0056 # Prints an error message and exits. If 'dontGenerateFileLists' is set, it
0057 # additionally clarifies that no DST lists would have been generated.
0058 error_exit() {
0059     echo -e "${BOLD}${YELLOW}[ERROR]:${RESET} $1"
0060     if $DONT_GENERATE_FILELISTS; then
0061         echo "Note: 'dontGenerateFileLists' was provided, so no DST lists would have been generated."
0062     fi
0063     exit 1
0064 }
0065 
0066 # Parses command-line arguments to enable/disable specific features:
0067 #   removeRunsWithMissingMaps, dontGenerateFileLists, noRunNumberLimit, removeNoMagnet.
0068 parse_arguments() {
0069     REMOVE_MISSING_MAPS=false
0070     DONT_GENERATE_FILELISTS=false
0071     NO_RUNNUMBER_LIMIT=false
0072     REMOVE_NO_MAGNET=false
0073 
0074     for arg in "$@"; do
0075         case "$arg" in
0076             removeRunsWithMissingMaps)
0077                 REMOVE_MISSING_MAPS=true
0078                 echo -e "${BOLD}${CYAN}Argument detected:${RESET} Removing runs missing bad tower maps."
0079                 ;;
0080             dontGenerateFileLists)
0081                 DONT_GENERATE_FILELISTS=true
0082                 echo -e "${BOLD}${CYAN}Argument detected:${RESET} Will not generate DST lists."
0083                 ;;
0084             noRunNumberLimit)
0085                 NO_RUNNUMBER_LIMIT=true
0086                 echo -e "${BOLD}${CYAN}Argument detected:${RESET} No run number lower limit will be applied."
0087                 ;;
0088             removeNoMagnet)
0089                 REMOVE_NO_MAGNET=true
0090                 echo -e "${BOLD}${CYAN}Argument detected:${RESET} Removing runs with magnet_off (or missing)."
0091                 ;;
0092         esac
0093     done
0094 
0095     if ! $REMOVE_MISSING_MAPS; then
0096         echo "No removal option detected: Missing-map runs will be kept."
0097     fi
0098     if ! $REMOVE_NO_MAGNET; then
0099         echo "No magnet check requested: Runs with magnet_off or missing are kept."
0100     fi
0101     echo "----------------------------------------"
0102 }
0103 
0104 # Removes pre-existing lists, FileLists, and old .list files in ../dst_list to
0105 # ensure a clean start, then reports the cleanup results to the user.
0106 clean_previous_data() {
0107     echo -e "${BOLD}${GREEN}Cleaning old data (dst_list contents, intermediate files)...${RESET}"
0108 
0109     rm -rf list/*
0110     rm -rf FileLists/*
0111     rm -f "${workplace}/../dst_list/"*.list
0112 
0113     rm -f "${workplace}/../dst_list/Final_RunNumbers_After_All_Cuts.txt"
0114     rm -f "${workplace}/../dst_list/Final_RunNumbers_After_All_Cuts_ge47289.txt"
0115     rm -rf "${workplace}/../dst_list_scratch"
0116 
0117     echo "All old data removed. Starting fresh."
0118     echo "----------------------------------------"
0119 }
0120 
0121 # Creates or verifies the necessary directories: FileLists/, list/,
0122 # and ../dst_list. Informs the user of the newly set up directories.
0123 setup_directories() {
0124     echo -e "${BOLD}${GREEN}Setting up directories...${RESET}"
0125     base_path="${workplace}/.."
0126     mkdir -p FileLists/
0127     mkdir -p "${base_path}/dst_list"
0128     mkdir -p list/
0129 
0130     echo "Directories ready under ${base_path}/"
0131     echo "----------------------------------------"
0132 }
0133 
0134 # Captures the current working directory and displays it, storing the
0135 # path in 'workplace' for subsequent reference.
0136 set_workplace() {
0137     workplace=$(pwd)
0138     echo -e "${BOLD}Working directory:${RESET} $workplace"
0139     echo "----------------------------------------"
0140 }
0141 
0142 # (Step 1) Queries FileCatalog for runs with ≥1M events. If 'noRunNumberLimit'
0143 # is disabled, also requires runnumber≥47289. Then intersects these runs with
0144 # Production_write to keep only Golden EMCal/IHCal/OHCal runs, storing results locally.
0145 extract_initial_runs() {
0146     echo -e "${BOLD}${MAGENTA}Step 1:${RESET} Extracting initial runs from databases..."
0147 
0148     python_script=$(cat <<EOF
0149 import pyodbc
0150 import sys
0151 
0152 no_limit = "NO_LIMIT" in sys.argv
0153 
0154 try:
0155     fc_conn = pyodbc.connect("DSN=FileCatalog;UID=phnxrc;READONLY=True")
0156 except:
0157     print("TOTAL_RUNS:0")
0158     sys.exit(1)
0159 
0160 fc_cursor = fc_conn.cursor()
0161 
0162 if no_limit:
0163     query = """
0164     SELECT runnumber
0165     FROM datasets
0166     WHERE dsttype='DST_CALO_run2pp' AND dataset='ana450_2024p009'
0167     GROUP BY runnumber
0168     HAVING SUM(events) >= 1000000;
0169     """
0170 else:
0171     query = """
0172     SELECT runnumber
0173     FROM datasets
0174     WHERE dsttype='DST_CALO_run2pp' AND dataset='ana450_2024p009'
0175     GROUP BY runnumber
0176     HAVING SUM(events) >= 1000000 AND runnumber >= 47289;
0177     """
0178 
0179 fc_cursor.execute(query)
0180 all_runs = [row.runnumber for row in fc_cursor.fetchall()]
0181 all_runs.sort()
0182 
0183 with open('list/list_runnumber_all.txt', 'w') as f:
0184     for r in all_runs:
0185         f.write(f"{r}\\n")
0186 print(f"TOTAL_RUNS:{len(all_runs)}")
0187 
0188 fc_conn.close()
0189 
0190 try:
0191     prod_conn = pyodbc.connect("DSN=Production_write")
0192 except:
0193     print("COMBINED_GOLDEN_RUNS:0")
0194     sys.exit(1)
0195 
0196 prod_cursor = prod_conn.cursor()
0197 detectors = ['emcal', 'ihcal', 'ohcal']
0198 golden_runs = set(all_runs)
0199 
0200 for d in detectors:
0201     prod_cursor.execute(f"SELECT runnumber FROM goodruns WHERE ({d}_auto).runclass='GOLDEN'")
0202     detector_golden = {row.runnumber for row in prod_cursor.fetchall()}
0203     golden_runs = golden_runs.intersection(detector_golden)
0204 
0205 golden_runs = sorted(golden_runs)
0206 
0207 with open('list/Full_ppGoldenRunList.txt', 'w') as f:
0208     for r in golden_runs:
0209         f.write(f"{r}\\n")
0210 print(f"COMBINED_GOLDEN_RUNS:{len(golden_runs)}")
0211 prod_conn.close()
0212 EOF
0213     )
0214 
0215     if $NO_RUNNUMBER_LIMIT; then
0216         python_output=$(python3 <(echo "$python_script") NO_LIMIT)
0217     else
0218         python_output=$(python3 <(echo "$python_script"))
0219     fi
0220 
0221     total_runs=$(echo "$python_output" | grep 'TOTAL_RUNS' | cut -d':' -f2)
0222     combined_golden_runs=$(echo "$python_output" | grep 'COMBINED_GOLDEN_RUNS' | cut -d':' -f2)
0223 
0224     echo "Summary after initial extraction:"
0225     echo "Total initial runs: ${total_runs:-0}"
0226     echo "Runs after Calo QA: ${combined_golden_runs:-0}"
0227     echo "----------------------------------------"
0228 
0229     if [[ "${total_runs:-0}" -eq 0 ]]; then
0230         error_exit "No runs found after initial extraction. No data matches your criteria."
0231     fi
0232 }
0233 
0234 # (Step 2) Ensures that a valid 'Full_ppGoldenRunList.txt' was produced.
0235 # If not found, abort execution since no runs qualified.
0236 validate_golden_list() {
0237     echo -e "${BOLD}${MAGENTA}Step 2:${RESET} Validating golden run list..."
0238     if [[ ! -f "list/Full_ppGoldenRunList.txt" ]]; then
0239         error_exit "list/Full_ppGoldenRunList.txt not found. Possibly no runs qualify."
0240     fi
0241     echo "Golden run list found."
0242     echo "----------------------------------------"
0243 }
0244 
0245 # Summation function for events in .evt files. Given a file of runnumbers,
0246 # this function batches them in groups of 100 for a SQL IN(...) query,
0247 # queries the 'filelist' table, and accumulates the total event count.
0248 get_actual_events_from_evt() {
0249     input_file=$1
0250     total_events=0
0251     batch_size=100
0252     run_numbers=()
0253 
0254     while IFS= read -r runnumber; do
0255         [[ -z "$runnumber" ]] && continue
0256         run_numbers+=("$runnumber")
0257         # Once we hit batch_size, we query in a single shot.
0258         if [[ ${#run_numbers[@]} -ge $batch_size ]]; then
0259             run_list=$(IFS=,; echo "${run_numbers[*]}")
0260             run_numbers=()
0261             query="SELECT SUM(lastevent - firstevent + 1)
0262                    FROM filelist
0263                    WHERE runnumber IN ($run_list)
0264                      AND filename LIKE '%GL1_physics_gl1daq%.evt';"
0265             result=$(psql -h sphnxdaqdbreplica -d daq -t -c "$query")
0266             events=$(echo "$result" | xargs)
0267             if [[ "$events" =~ ^[0-9]+$ ]]; then
0268                 total_events=$(echo "$total_events + $events" | bc)
0269             fi
0270         fi
0271     done < "$input_file"
0272 
0273     # Handle leftover runs if any remain below the batch size.
0274     if [[ ${#run_numbers[@]} -gt 0 ]]; then
0275         run_list=$(IFS=,; echo "${run_numbers[*]}")
0276         query="SELECT SUM(lastevent - firstevent + 1)
0277                FROM filelist
0278                WHERE runnumber IN ($run_list)
0279                  AND filename LIKE '%GL1_physics_gl1daq%.evt';"
0280         result=$(psql -h sphnxdaqdbreplica -d daq -t -c "$query")
0281         events=$(echo "$result" | xargs)
0282         if [[ "$events" =~ ^[0-9]+$ ]]; then
0283             total_events=$(echo "$total_events + $events" | bc)
0284         fi
0285     fi
0286 
0287     echo "$total_events"
0288 }
0289 
0290 # Prints a heading indicating that runtime, livetime, and missing bad tower maps
0291 # will be enforced in the subsequent steps.
0292 apply_incremental_cuts_header() {
0293     echo "----------------------------------------"
0294     echo -e "${BOLD}${MAGENTA}Applying incremental cuts:${RESET} runtime, livetime, and missing bad tower maps"
0295     echo "----------------------------------------"
0296 }
0297 
0298 # (Step 3) Reads 'Full_ppGoldenRunList.txt', queries the 'run' table to calculate
0299 # (ertimestamp - brtimestamp). Retains runs with >300s (5 minutes).
0300 # The result is placed in 'list_runnumber_runtime_v1.txt'.
0301 # -- ADDED PROGRESS PRINTS EVERY 100 RUNS PROCESSED.
0302 runtime_cut() {
0303     input_file="list/Full_ppGoldenRunList.txt"
0304     output_file_duration_v1="list/list_runnumber_runtime_v1.txt"
0305     > "$output_file_duration_v1"
0306 
0307     total_runs_duration_v1=0
0308     runs_dropped_runtime_v1=0
0309 
0310     # Count total for nice progress prints
0311     total_input_runs=$(wc -l < "$input_file")
0312     processed=0
0313 
0314     while IFS= read -r runnumber; do
0315         ((processed++))
0316         [[ -z "$runnumber" ]] && continue
0317 
0318         query="SELECT EXTRACT(EPOCH FROM (ertimestamp - brtimestamp))
0319                FROM run
0320                WHERE runnumber = ${runnumber};"
0321         result=$(psql -h sphnxdaqdbreplica -d daq -t -c "$query" | tr -d '[:space:]')
0322         duration="$result"
0323 
0324         if [[ "$duration" =~ ^[0-9]+(\.[0-9]+)?$ ]] && (( $(echo "$duration > 300" | bc -l) )); then
0325             echo "$runnumber" >> "$output_file_duration_v1"
0326             (( total_runs_duration_v1++ ))
0327         else
0328             (( runs_dropped_runtime_v1++ ))
0329         fi
0330 
0331         # Print progress every 100 runs
0332         if (( processed % 100 == 0 )); then
0333             echo "  [Runtime Cut] Processed $processed / $total_input_runs runs so far..."
0334         fi
0335     done < "$input_file"
0336 
0337     echo "After runtime cut (>5 mins): $total_runs_duration_v1 runs remain."
0338     echo "Dropped due to runtime: $runs_dropped_runtime_v1"
0339     echo "----------------------------------------"
0340 }
0341 
0342 # (Step 4) Reads the runtime-filtered list, queries 'gl1_scalers' for index=10
0343 # (minimum bias), ensuring live/raw≥80%. Passing runs are written to
0344 # 'list_runnumber_livetime_v1.txt'; failing runs go to 'list_runnumber_bad_livetime_v1.txt'.
0345 # -- ADDED PROGRESS PRINTS EVERY 100 RUNS PROCESSED.
0346 livetime_cut() {
0347     input_file="list/list_runnumber_runtime_v1.txt"
0348     output_file_livetime_v1="list/list_runnumber_livetime_v1.txt"
0349     bad_file_livetime_v1="list/list_runnumber_bad_livetime_v1.txt"
0350     > "$output_file_livetime_v1"
0351     > "$bad_file_livetime_v1"
0352 
0353     total_runs_livetime_v1=0
0354     runs_dropped_livetime_v1=0
0355 
0356     total_input_runs=$(wc -l < "$input_file")
0357     processed=0
0358 
0359     while IFS= read -r runnumber; do
0360         ((processed++))
0361         [[ -z "$runnumber" ]] && continue
0362 
0363         index_to_check=10
0364         query="SELECT raw, live
0365                FROM gl1_scalers
0366                WHERE runnumber = ${runnumber}
0367                  AND index = ${index_to_check};"
0368         result=$(psql -h sphnxdaqdbreplica -d daq -t -c "$query")
0369 
0370         index_pass=false
0371         while IFS='|' read -r raw live; do
0372             raw=$(echo "$raw" | xargs)
0373             live=$(echo "$live" | xargs)
0374             if [[ "$raw" =~ ^[0-9]+$ && "$live" =~ ^[0-9]+$ && "$raw" -ne 0 ]]; then
0375                 ratio=$(echo "scale=2; $live / $raw * 100" | bc -l)
0376                 if (( $(echo "$ratio >= 80" | bc -l) )); then
0377                     index_pass=true
0378                 fi
0379             fi
0380         done <<< "$result"
0381 
0382         if $index_pass; then
0383             echo "$runnumber" >> "$output_file_livetime_v1"
0384             (( total_runs_livetime_v1++ ))
0385         else
0386             echo "$runnumber" >> "$bad_file_livetime_v1"
0387             (( runs_dropped_livetime_v1++ ))
0388         fi
0389 
0390         if (( processed % 100 == 0 )); then
0391             echo "  [Livetime Cut] Processed $processed / $total_input_runs runs so far..."
0392         fi
0393     done < "$input_file"
0394 
0395     echo "After livetime cut (>80%): $total_runs_livetime_v1 runs remain."
0396     echo "Dropped due to livetime: $runs_dropped_livetime_v1"
0397     echo "----------------------------------------"
0398 }
0399 
0400 # (Step 5) Reads from 'list_runnumber_livetime_v1.txt', producing a
0401 # "preMagnet" list. If 'removeRunsWithMissingMaps' is set,
0402 # any runs not found in the known bad tower maps are excluded.
0403 # -- ADDED PROGRESS PRINTS EVERY 100 RUNS PROCESSED.
0404 missing_bad_tower_maps_step() {
0405     input_file="list/list_runnumber_livetime_v1.txt"
0406     pre_magnet_file="FileLists/Full_ppGoldenRunList_Version1_preMagnet.txt"
0407     cp "$input_file" "$pre_magnet_file"
0408 
0409     bad_tower_runs_file="list/list_runs_missing_bad_tower_maps.txt"
0410     available_bad_tower_runs=$(find /cvmfs/sphenix.sdcc.bnl.gov/calibrations/sphnxpro/cdb/CEMC_BadTowerMap \
0411                                -name "*p0*" | cut -d '-' -f2 | cut -dc -f1 | sort | uniq)
0412     echo "$available_bad_tower_runs" > list/available_bad_tower_runs.txt
0413 
0414     total_input_runs=$(wc -l < "$input_file")
0415     processed=0
0416 
0417     # Step 1: create an empty file for runs that are MISSING maps
0418     > "$bad_tower_runs_file"
0419 
0420     # Step 2: We'll store "available_bad_tower_runs.txt" lines in an array for quick membership checks
0421     mapfile -t available_map_array < list/available_bad_tower_runs.txt
0422     declare -A avail_map
0423     for runmap in "${available_map_array[@]}"; do
0424         avail_map["$runmap"]=1
0425     done
0426 
0427     # Step 3: read input_file line by line to see if run is in avail_map
0428     # if it's NOT, that means it is missing => put it in $bad_tower_runs_file
0429     while IFS= read -r runnumber; do
0430         ((processed++))
0431         [[ -z "$runnumber" ]] && continue
0432 
0433         if [[ -z "${avail_map[$runnumber]}" ]]; then
0434             # run is not in the available bad tower array => missing
0435             echo "$runnumber" >> "$bad_tower_runs_file"
0436         fi
0437 
0438         # Print progress every 100 runs
0439         if (( processed % 100 == 0 )); then
0440             echo "  [Bad Tower Step] Processed $processed / $total_input_runs runs so far..."
0441         fi
0442     done < "$input_file"
0443 
0444     total_runs_with_bad_tower=$(grep -Fxf list/available_bad_tower_runs.txt "$input_file" | wc -l)
0445     total_runs_missing_bad_tower=$(wc -l < "$bad_tower_runs_file")
0446 
0447     echo "Runs with bad tower maps: $total_runs_with_bad_tower"
0448     echo "Runs missing bad tower maps: $total_runs_missing_bad_tower"
0449     echo "List of missing map runs: $bad_tower_runs_file"
0450     echo "----------------------------------------"
0451 
0452     export total_runs_missing_bad_tower
0453     rm list/available_bad_tower_runs.txt
0454 
0455     if $REMOVE_MISSING_MAPS; then
0456         echo "Removing runs missing bad tower maps..."
0457         grep -Fxf "$bad_tower_runs_file" -v "$pre_magnet_file" > tmp && mv tmp "$pre_magnet_file"
0458         echo "Removal complete."
0459         echo "----------------------------------------"
0460     fi
0461 
0462     cp "$pre_magnet_file" "${workplace}/../dst_list/Final_RunNumbers_After_All_Cuts.txt"
0463     echo "Final run list (pre-magnet step) stored in ${workplace}/../dst_list/Final_RunNumbers_After_All_Cuts.txt"
0464     echo "----------------------------------------"
0465 
0466     if $NO_RUNNUMBER_LIMIT; then
0467         awk '$1 >= 47289' "$pre_magnet_file" > FileLists/Full_ppGoldenRunList_ge47289_Version1.txt
0468         cp FileLists/Full_ppGoldenRunList_ge47289_Version1.txt \
0469            "${workplace}/../dst_list/Final_RunNumbers_After_All_Cuts_ge47289.txt"
0470 
0471         if $REMOVE_MISSING_MAPS; then
0472             missing_maps_ge47289=$(grep -Fxf FileLists/Full_ppGoldenRunList_ge47289_Version1.txt \
0473                                        "$bad_tower_runs_file" | wc -l)
0474             export missing_maps_ge47289
0475         fi
0476     fi
0477 }
0478 
0479 # (Step 6) If 'removeNoMagnet' is true, read from the preMagnet file
0480 # and exclude runs where magnet_on != 't'. Otherwise, the preMagnet file
0481 # is simply renamed to the final run list. We'll also add a small progress print.
0482 magnet_check_step() {
0483     if [[ "$REMOVE_NO_MAGNET" != true ]]; then
0484         echo "No magnet check requested, skipping..."
0485         mv FileLists/Full_ppGoldenRunList_Version1_preMagnet.txt FileLists/Full_ppGoldenRunList_Version1.txt
0486         return
0487     fi
0488 
0489     echo "Step 6: Checking magnet_on from 'magnet_info' table..."
0490 
0491     pre_magnet_file="FileLists/Full_ppGoldenRunList_Version1_preMagnet.txt"
0492     if [[ ! -f "$pre_magnet_file" ]]; then
0493         echo "[ERROR] No 'preMagnet' file found: $pre_magnet_file"
0494         return
0495     fi
0496 
0497     magnet_off_file="list/list_runs_no_magnet.txt"
0498     > "$magnet_off_file"
0499 
0500     final_list_magnet="FileLists/Full_ppGoldenRunList_Version1.txt"
0501     > "$final_list_magnet"
0502 
0503     total_runs_magnet_ok=0
0504     runs_dropped_magnet=0
0505 
0506     total_input_runs=$(wc -l < "$pre_magnet_file")
0507     processed=0
0508 
0509     while IFS= read -r runnumber; do
0510         ((processed++))
0511         [[ -z "$runnumber" ]] && continue
0512 
0513         query="SELECT magnet_on
0514                FROM magnet_info
0515                WHERE runnumber=${runnumber};"
0516         result=$(psql -h sphnxdaqdbreplica -d daq -t -c "$query" | tr -d '[:space:]')
0517 
0518         if [[ "$result" == "t" ]]; then
0519             echo "$runnumber" >> "$final_list_magnet"
0520             (( total_runs_magnet_ok++ ))
0521         else
0522             echo "$runnumber" >> "$magnet_off_file"
0523             (( runs_dropped_magnet++ ))
0524         fi
0525 
0526         if (( processed % 100 == 0 )); then
0527             echo "  [Magnet Check] Processed $processed / $total_input_runs runs so far..."
0528         fi
0529     done < "$pre_magnet_file"
0530 
0531     echo "Magnet On check: $total_runs_magnet_ok runs are ON"
0532     echo "Dropped (magnet off or missing): $runs_dropped_magnet"
0533     echo "List of dropped runs: $magnet_off_file"
0534     echo "----------------------------------------"
0535 
0536     # Overwrite final list with magnet-checked version
0537     cp "$final_list_magnet" "${workplace}/../dst_list/Final_RunNumbers_After_All_Cuts.txt"
0538 
0539     export total_runs_magnet_off=$runs_dropped_magnet
0540 }
0541 
0542 # Generates Full_ppGoldenRunList_Version1.list from the final text file
0543 # in FileLists/. If removeNoMagnet is false, the script may rename the
0544 # preMagnet file to that final name. Issues a warning if the final file
0545 # is missing.
0546 create_list_file() {
0547     echo "Creating final .list file from the final run list..."
0548 
0549     if [[ ! -f "FileLists/Full_ppGoldenRunList_Version1.txt" ]]; then
0550         if [[ -f "FileLists/Full_ppGoldenRunList_Version1_preMagnet.txt" ]]; then
0551             mv FileLists/Full_ppGoldenRunList_Version1_preMagnet.txt FileLists/Full_ppGoldenRunList_Version1.txt
0552         fi
0553     fi
0554 
0555     if [[ -f "FileLists/Full_ppGoldenRunList_Version1.txt" ]]; then
0556         cp "FileLists/Full_ppGoldenRunList_Version1.txt" Full_ppGoldenRunList_Version1.list
0557         echo ".list file created: Full_ppGoldenRunList_Version1.list"
0558     else
0559         echo "[WARNING] Could not find 'FileLists/Full_ppGoldenRunList_Version1.txt' to create .list!"
0560     fi
0561     echo "----------------------------------------"
0562 }
0563 
0564 # Removes pre-existing .list files in ../dst_list/ to avoid confusion
0565 # prior to generating new DST lists.
0566 clean_old_dst_lists() {
0567     echo "Removing any old DST lists from the parent 'dst_list' directory..."
0568     rm -f "${workplace}/../dst_list/"*.list
0569     echo "Done removing old .list files in dst_list/."
0570     echo "----------------------------------------"
0571 }
0572 
0573 # If 'dontGenerateFileLists' is not specified, runs CreateDstList.pl on
0574 # the final .list to build run-specific .list files for DST creation.
0575 # Prints where the DST lists are saved.
0576 generate_dst_lists() {
0577     if $DONT_GENERATE_FILELISTS; then
0578         echo "[INFO]: Skipping DST list generation due to 'dontGenerateFileLists'."
0579         return
0580     fi
0581 
0582     echo "Generating DST lists for the main scenario..."
0583     cd "${workplace}/../dst_list"
0584 
0585     list_path="${workplace}/Full_ppGoldenRunList_Version1.list"
0586     if [[ ! -f "$list_path" ]]; then
0587         echo "[WARNING] Could not find final .list file at: $list_path"
0588         echo "No DST lists will be created."
0589     else
0590         CreateDstList.pl --build ana450 --cdb 2024p009 DST_CALO_run2pp --list "$list_path"
0591         echo "DST lists generated under ${workplace}/../dst_list"
0592     fi
0593 
0594     if $NO_RUNNUMBER_LIMIT; then
0595         echo "No separate scratch folder is used for the ≥47289 subset."
0596     fi
0597 
0598     echo "----------------------------------------"
0599     cd "$workplace"
0600 }
0601 
0602 # After DST .list files are generated, this function checks which runs
0603 # successfully produced a dst_calo_run2pp-*.list and which did not.
0604 # Successful runs are recorded in list_runnumber_createDstSuccess.txt,
0605 # while failures appear in list_runnumber_createDstFailure.txt.
0606 apply_createDstList_cut() {
0607     echo "Collecting CreateDST File List success/failure for the main scenario..."
0608 
0609     if $DONT_GENERATE_FILELISTS; then
0610         echo "[INFO]: 'dontGenerateFileLists' was provided, so no DST creation was done for main scenario."
0611         export total_runs_createDst_success=0
0612         export runs_dropped_createDst=0
0613         export actual_events_after_createDst=0
0614         export total_runs_after_createDst=0
0615         return
0616     fi
0617 
0618     final_stage4_file="FileLists/Full_ppGoldenRunList_Version1.txt"
0619     if [[ ! -f "$final_stage4_file" ]]; then
0620         echo "[ERROR]: Cannot find final stage file: $final_stage4_file"
0621         export total_runs_createDst_success=0
0622         export runs_dropped_createDst=0
0623         export actual_events_after_createDst=0
0624         export total_runs_after_createDst=0
0625         return
0626     fi
0627 
0628     success_file="list/list_runnumber_createDstSuccess.txt"
0629     failure_file="list/list_runnumber_createDstFailure.txt"
0630     > "$success_file"
0631     > "$failure_file"
0632 
0633     mapfile -t final_stage_runs < "$final_stage4_file"
0634 
0635     base_path="${workplace}/../dst_list"
0636     created_run_nums=()
0637 
0638     for f in "${base_path}/dst_calo_run2pp-"*.list; do
0639         [ -e "$f" ] || continue
0640         bn=$(basename "$f" .list)
0641         runnum_str=${bn#dst_calo_run2pp-}
0642         if [[ "$runnum_str" =~ ^0*([0-9]+)$ ]]; then
0643             runnum=${BASH_REMATCH[1]}
0644             created_run_nums+=("$runnum")
0645         fi
0646     done
0647 
0648     total_runs_createDst_success=0
0649     runs_dropped_createDst=0
0650     declare -A in_created
0651     for rn in "${created_run_nums[@]}"; do
0652         in_created["$rn"]=1
0653     done
0654 
0655     for runnumber in "${final_stage_runs[@]}"; do
0656         if [[ -n "${in_created[$runnumber]}" ]]; then
0657             echo "$runnumber" >> "$success_file"
0658             (( total_runs_createDst_success++ ))
0659         else
0660             echo "$runnumber" >> "$failure_file"
0661             (( runs_dropped_createDst++ ))
0662         fi
0663     done
0664 
0665     echo "Runs with successful .list creation: $total_runs_createDst_success"
0666     echo "Runs with no .list file: $runs_dropped_createDst"
0667     echo "List of runs that failed:  $failure_file"
0668     echo "List of runs that succeeded: $success_file"
0669     echo "----------------------------------------"
0670 
0671     actual_events_after_createDst=$(get_actual_events_from_evt "$success_file")
0672     total_runs_after_createDst=$total_runs_createDst_success
0673 
0674     cp "$success_file" "FileLists/Full_ppGoldenRunList_Version1_DSTsuccess.txt"
0675 
0676     export total_runs_createDst_success
0677     export runs_dropped_createDst
0678     export actual_events_after_createDst
0679     export total_runs_after_createDst
0680 
0681     # If noRunNumberLimit is set, repeat the same success/failure process
0682     # for the run≥47289 scenario.
0683     if $NO_RUNNUMBER_LIMIT; then
0684         echo "Collecting CreateDST File List success/failure for the '≥47289' scenario..."
0685         final_stage4_file_ge47289="FileLists/Full_ppGoldenRunList_ge47289_Version1.txt"
0686         if [[ ! -f "$final_stage4_file_ge47289" ]]; then
0687             echo "[ERROR]: Cannot find the ge47289 final list: $final_stage4_file_ge47289"
0688             export total_runs_createDst_success_ge47289=0
0689             export runs_dropped_createDst_ge47289=0
0690             export actual_events_after_createDst_ge47289=0
0691             export total_runs_after_createDst_ge47289=0
0692         else
0693             success_file_ge47289="list/list_runnumber_createDstSuccess_ge47289.txt"
0694             failure_file_ge47289="list/list_runnumber_createDstFailure_ge47289.txt"
0695             > "$success_file_ge47289"
0696             > "$failure_file_ge47289"
0697 
0698             mapfile -t final_stage_runs_ge47289 < "$final_stage4_file_ge47289"
0699 
0700             base_path_scratch="${workplace}/../dst_list"
0701             created_run_nums_ge47289=()
0702 
0703             for f in "${base_path_scratch}/dst_calo_run2pp-"*.list; do
0704                 [ -e "$f" ] || continue
0705                 bn=$(basename "$f" .list)
0706                 runnum_str=${bn#dst_calo_run2pp-}
0707                 if [[ "$runnum_str" =~ ^0*([0-9]+)$ ]]; then
0708                     runnum=${BASH_REMATCH[1]}
0709                     created_run_nums_ge47289+=("$runnum")
0710                 fi
0711             done
0712 
0713             total_runs_createDst_success_ge47289=0
0714             runs_dropped_createDst_ge47289=0
0715             declare -A in_created_ge47289
0716             for rn in "${created_run_nums_ge47289[@]}"; do
0717                 in_created_ge47289["$rn"]=1
0718             done
0719 
0720             for runnumber in "${final_stage_runs_ge47289[@]}"; do
0721                 if [[ -n "${in_created_ge47289[$runnumber]}" ]]; then
0722                     echo "$runnumber" >> "$success_file_ge47289"
0723                     (( total_runs_createDst_success_ge47289++ ))
0724                 else
0725                     echo "$runnumber" >> "$failure_file_ge47289"
0726                     (( runs_dropped_createDst_ge47289++ ))
0727                 fi
0728             done
0729 
0730             echo "≥47289 scenario: runs with successful .list creation: $total_runs_createDst_success_ge47289"
0731             echo "≥47289 scenario: runs with no .list file: $runs_dropped_createDst_ge47289"
0732             echo "≥47289 scenario: List of runs that failed:  $failure_file_ge47289"
0733             echo "≥47289 scenario: List of runs that succeeded: $success_file_ge47289"
0734             echo "----------------------------------------"
0735 
0736             actual_events_after_createDst_ge47289=$(get_actual_events_from_evt "$success_file_ge47289")
0737             total_runs_after_createDst_ge47289=$total_runs_createDst_success_ge47289
0738 
0739             cp "$success_file_ge47289" "FileLists/Full_ppGoldenRunList_ge47289_Version1_DSTsuccess.txt"
0740 
0741             export total_runs_createDst_success_ge47289
0742             export runs_dropped_createDst_ge47289
0743             export actual_events_after_createDst_ge47289
0744             export total_runs_after_createDst_ge47289
0745         fi
0746     fi
0747 }
0748 
0749 # Collates event/run tallies at each stage. The stages are:
0750 #   1) list_runnumber_all.txt               -> initial
0751 #   2) Full_ppGoldenRunList.txt             -> calo QA
0752 #   3) list_runnumber_runtime_v1.txt        -> runtime
0753 #   4) list_runnumber_livetime_v1.txt       -> livetime
0754 #   5) Full_ppGoldenRunList_Version1_preMagnet.txt -> optional map check
0755 #   6) Full_ppGoldenRunList_Version1.txt    -> optional magnet check
0756 #   7) Full_ppGoldenRunList_Version1_DSTsuccess.txt -> DST creation success
0757 # Compares these runs to a "Stage1" reference for run-based percentages and
0758 # to the Stage1 event count for event-based percentages.
0759 compute_event_counts() {
0760     pre_magnet_file="FileLists/Full_ppGoldenRunList_Version1_preMagnet.txt"
0761     final_file="FileLists/Full_ppGoldenRunList_Version1.txt"
0762 
0763     # Stage1 => list/list_runnumber_all.txt
0764     actual_events_before_cuts=$(get_actual_events_from_evt 'list/list_runnumber_all.txt')
0765     total_runs_before_cuts=$(wc -l < 'list/list_runnumber_all.txt')
0766     actual_events_initial=$actual_events_before_cuts
0767 
0768     # Stage2 => list/Full_ppGoldenRunList.txt
0769     actual_events_calo_qa=$(get_actual_events_from_evt 'list/Full_ppGoldenRunList.txt')
0770     runs_after_calo_qa=$(wc -l < 'list/Full_ppGoldenRunList.txt')
0771 
0772     # Stage3 => runtime
0773     actual_events_after_runtime=$(get_actual_events_from_evt 'list/list_runnumber_runtime_v1.txt')
0774     runs_after_runtime=$(wc -l < 'list/list_runnumber_runtime_v1.txt')
0775 
0776     # Stage4 => livetime
0777     actual_events_after_livetime=$(get_actual_events_from_evt 'list/list_runnumber_livetime_v1.txt')
0778     runs_after_livetime=$(wc -l < 'list/list_runnumber_livetime_v1.txt')
0779 
0780     # Stage5 => preMagnet
0781     if [[ -f "$pre_magnet_file" ]]; then
0782         actual_events_after_badtower=$(get_actual_events_from_evt "$pre_magnet_file")
0783         runs_after_badtower=$(wc -l < "$pre_magnet_file")
0784     else
0785         actual_events_after_badtower=0
0786         runs_after_badtower=0
0787     fi
0788 
0789     # Stage6 => final
0790     if [[ -f "$final_file" ]]; then
0791         actual_events_after_magnet=$(get_actual_events_from_evt "$final_file")
0792         runs_after_magnet=$(wc -l < "$final_file")
0793     else
0794         actual_events_after_magnet=0
0795         runs_after_magnet=0
0796     fi
0797 
0798     # Stage7 => DST creation success
0799     if [[ -f FileLists/Full_ppGoldenRunList_Version1_DSTsuccess.txt ]]; then
0800         actual_events_after_createDst=$(get_actual_events_from_evt "FileLists/Full_ppGoldenRunList_Version1_DSTsuccess.txt")
0801         runs_after_createDst=$(wc -l < "FileLists/Full_ppGoldenRunList_Version1_DSTsuccess.txt")
0802     else
0803         actual_events_after_createDst=0
0804         runs_after_createDst=0
0805     fi
0806 
0807     STAGE1_RUNS=$total_runs_before_cuts
0808     [[ "$STAGE1_RUNS" -eq 0 ]] && STAGE1_RUNS=1
0809     [[ "$actual_events_before_cuts" -eq 0 ]] && actual_events_before_cuts=1
0810 
0811     # run-based percentages
0812     percent_runs_calo_qa=$(echo "scale=2; 100.0*$runs_after_calo_qa/$STAGE1_RUNS" | bc)
0813     percent_runs_after_runtime=$(echo "scale=2; 100.0*$runs_after_runtime/$STAGE1_RUNS" | bc)
0814     percent_runs_after_livetime=$(echo "scale=2; 100.0*$runs_after_livetime/$STAGE1_RUNS" | bc)
0815     percent_runs_after_badtower=$(echo "scale=2; 100.0*$runs_after_badtower/$STAGE1_RUNS" | bc)
0816     percent_runs_after_magnet=$(echo "scale=2; 100.0*$runs_after_magnet/$STAGE1_RUNS" | bc)
0817     percent_runs_after_createDst=$(echo "scale=2; 100.0*$runs_after_createDst/$STAGE1_RUNS" | bc)
0818 
0819     # event-based percentages
0820     percent_actual_events_calo_qa=$(echo "scale=2; 100.0*$actual_events_calo_qa/$actual_events_before_cuts" | bc)
0821     percent_actual_events_after_runtime=$(echo "scale=2; 100.0*$actual_events_after_runtime/$actual_events_before_cuts" | bc)
0822     percent_actual_events_after_livetime=$(echo "scale=2; 100.0*$actual_events_after_livetime/$actual_events_before_cuts" | bc)
0823     percent_actual_events_after_badtower=$(echo "scale=2; 100.0*$actual_events_after_badtower/$actual_events_before_cuts" | bc)
0824     percent_actual_events_after_magnet=$(echo "scale=2; 100.0*$actual_events_after_magnet/$actual_events_before_cuts" | bc)
0825     percent_events_after_createDst=$(echo "scale=2; 100.0*$actual_events_after_createDst/$actual_events_before_cuts" | bc)
0826 
0827     export STAGE1_RUNS
0828     export runs_after_calo_qa
0829     export runs_after_runtime
0830     export runs_after_livetime
0831     export runs_after_badtower
0832     export runs_after_magnet
0833     export runs_after_createDst
0834 
0835     export actual_events_before_cuts
0836     export total_runs_before_cuts
0837     export actual_events_initial
0838 
0839     export actual_events_calo_qa
0840     export actual_events_after_runtime
0841     export actual_events_after_livetime
0842     export actual_events_after_badtower
0843     export actual_events_after_magnet
0844     export actual_events_after_createDst
0845 
0846     export percent_runs_calo_qa
0847     export percent_runs_after_runtime
0848     export percent_runs_after_livetime
0849     export percent_runs_after_badtower
0850     export percent_runs_after_magnet
0851     export percent_runs_after_createDst
0852 
0853     export percent_actual_events_calo_qa
0854     export percent_actual_events_after_runtime
0855     export percent_actual_events_after_livetime
0856     export percent_actual_events_after_badtower
0857     export percent_actual_events_after_magnet
0858     export percent_events_after_createDst
0859 }
0860 
0861 # Displays a multi-stage summary table showing how many runs and events remain
0862 # after each cut. If 'noRunNumberLimit' is active, the script also prints
0863 # a comparison between the full run range and the run≥47289 scenario.
0864 final_summary() {
0865     echo -e "${BOLD}${MAGENTA}========================================${RESET}"
0866     echo -e "${BOLD}${MAGENTA}Final Summary (Version 1)${RESET}"
0867     echo -e "${MAGENTA}----------------------------------------${RESET}"
0868     printf "%-50s | %-35s | %-25s\n" "Stage" ".evt File Events" "Runs"
0869     echo "--------------------------------------------------|-------------------------------------|-------------------------"
0870 
0871     if $NO_RUNNUMBER_LIMIT; then
0872         stage1_label="≥1M events"
0873     else
0874         stage1_label="≥47289 & ≥1M events"
0875     fi
0876 
0877     # Stage 1
0878     printf "%-50s | %-35s | %-25s\n" \
0879     "1) $stage1_label" \
0880     "${actual_events_initial} (100%)" \
0881     "${STAGE1_RUNS} (100%)"
0882 
0883     # Stage 2
0884     printf "%-50s | %-35s | %-25s\n" \
0885     "2) && Golden EMCal/HCal" \
0886     "${actual_events_calo_qa} (${percent_actual_events_calo_qa}%)" \
0887     "${runs_after_calo_qa} (${percent_runs_calo_qa}%)"
0888 
0889     # Stage 3
0890     printf "%-50s | %-35s | %-25s\n" \
0891     "3) && > 5 minutes" \
0892     "${actual_events_after_runtime} (${percent_actual_events_after_runtime}%)" \
0893     "${runs_after_runtime} (${percent_runs_after_runtime}%)"
0894 
0895     # Stage 4
0896     printf "%-50s | %-35s | %-25s\n" \
0897     "4) && MB livetime > 80%" \
0898     "${actual_events_after_livetime} (${percent_actual_events_after_livetime}%)" \
0899     "${runs_after_livetime} (${percent_runs_after_livetime}%)"
0900 
0901     # Stage 5
0902     if $REMOVE_MISSING_MAPS; then
0903         step_label="5) && With Bad Tower Map Available (Removed)"
0904     else
0905         step_label="5) && With Bad Tower Map Available (Not Removed)"
0906     fi
0907     printf "%-50s | %-35s | %-25s\n" \
0908     "$step_label" \
0909     "${actual_events_after_badtower} (${percent_actual_events_after_badtower}%)" \
0910     "${runs_after_badtower} (${percent_runs_after_badtower}%)"
0911 
0912     # Stage 6 - magnet
0913     if [[ "$REMOVE_NO_MAGNET" == true ]]; then
0914         step_label_magnet="6) && Magnet On"
0915         printf "%-50s | %-35s | %-25s\n" \
0916         "$step_label_magnet" \
0917         "${actual_events_after_magnet} (${percent_actual_events_after_magnet}%)" \
0918         "${runs_after_magnet} (${percent_runs_after_magnet}%)"
0919     fi
0920 
0921     # Stage 7 - DST creation
0922     step_label_createDST="7) && CreateDST File List Successes"
0923     printf "%-50s | %-35s | %-25s\n" \
0924     "$step_label_createDST" \
0925     "${actual_events_after_createDst} (${percent_events_after_createDst}%)" \
0926     "${runs_after_createDst} (${percent_runs_after_createDst}%)"
0927 
0928     # Missing map note
0929     if $REMOVE_MISSING_MAPS; then
0930         map_note="Removed from final DST"
0931     else
0932         map_note="Kept in final DST"
0933     fi
0934     printf "%-50s | %-35s | %-25s\n" \
0935     "Missing Map Runs" \
0936     "-" \
0937     "${total_runs_missing_bad_tower} (${map_note})"
0938 
0939     # Magnet note
0940     if [[ "$REMOVE_NO_MAGNET" == true ]]; then
0941         if [[ -z "$total_runs_magnet_off" ]]; then
0942             total_runs_magnet_off=0
0943         fi
0944         mag_note="Removed"
0945         printf "%-50s | %-35s | %-25s\n" \
0946         "No Magnet-On Runs" \
0947         "-" \
0948         "${total_runs_magnet_off} (${mag_note})"
0949     fi
0950 
0951     echo "================================================="
0952     echo "========================================"
0953 
0954     # Conclude with the final run list path
0955     if $REMOVE_MISSING_MAPS; then
0956         echo "Final golden run list (missing maps removed):"
0957     else
0958         echo "Final golden run list (with runs missing maps included):"
0959     fi
0960     echo " --> ${workplace}/../dst_list/Final_RunNumbers_After_All_Cuts.txt"
0961     echo "Done."
0962 
0963     # If noRunNumberLimit => additional table comparing full range vs run≥47289
0964     if $NO_RUNNUMBER_LIMIT; then
0965         echo ""
0966         echo "----------------------------------------"
0967         echo -e "${BOLD}${MAGENTA}Additional Comparison (Before & After Cuts):${RESET} No-limit vs. ≥47289 scenario"
0968         echo ""
0969         cat <<EOCOMPARISON
0970 
0971 Metric                                  | NoLimit(All)                | ≥47289                    | ΔValue           | %Lost
0972 --------------------------------------------------------------------------------------------------------------
0973 EOCOMPARISON
0974 
0975         ev_all_initial=${actual_events_before_cuts:-0}
0976         ev_ge_initial=${actual_events_before_cuts_ge47289:-0}
0977         diff_ev_initial=$(echo "$ev_all_initial - $ev_ge_initial" | bc)
0978         if (( ev_all_initial > 0 )); then
0979             perc_ev_lost_initial=$(echo "scale=2; 100.0*$diff_ev_initial/$ev_all_initial" | bc)
0980         else
0981             perc_ev_lost_initial=0
0982         fi
0983 
0984         run_all_initial=${total_runs_before_cuts:-0}
0985         run_ge_initial=${total_runs_before_cuts_ge47289:-0}
0986         diff_run_initial=$(echo "$run_all_initial - $run_ge_initial" | bc)
0987         if (( run_all_initial > 0 )); then
0988             perc_run_lost_initial=$(echo "scale=2; 100.0*$diff_run_initial/$run_all_initial" | bc)
0989         else
0990             perc_run_lost_initial=0
0991         fi
0992 
0993         printf "%-40s | %-20s | %-20s | %-20s | %-20s\n" \
0994           "Events Before All Cuts" "$ev_all_initial" "$ev_ge_initial" "$diff_ev_initial" "${perc_ev_lost_initial}%"
0995         printf "%-40s | %-20s | %-20s | %-20s | %-20s\n" \
0996           "Runs Before All Cuts"   "$run_all_initial" "$run_ge_initial" "$diff_run_initial" "${perc_run_lost_initial}%"
0997 
0998         echo ""
0999         # After All Cuts => DST
1000         ev_all=${actual_events_after_createDst:-0}
1001         ev_ge=${actual_events_after_createDst_ge47289:-0}
1002         diff_ev=$(echo "$ev_all - $ev_ge" | bc)
1003         if (( ev_all > 0 )); then
1004             perc_ev_lost=$(echo "scale=2; 100.0*$diff_ev/$ev_all" | bc)
1005         else
1006             perc_ev_lost=0
1007         fi
1008 
1009         run_all=${runs_after_createDst:-0}
1010         run_ge=${runs_after_createDst_ge47289:-0}
1011         diff_run=$(echo "$run_all - $run_ge" | bc)
1012         if (( run_all > 0 )); then
1013             perc_run_lost=$(echo "scale=2; 100.0*$diff_run/$run_all" | bc)
1014         else
1015             perc_run_lost=0
1016         fi
1017 
1018         printf "%-40s | %-20s | %-20s | %-20s | %-20s\n" \
1019           "Events After All Cuts" "$ev_all" "$ev_ge" "$diff_ev" "${perc_ev_lost}%"
1020         printf "%-40s | %-20s | %-20s | %-20s | %-20s\n" \
1021           "Runs After All Cuts"   "$run_all" "$run_ge" "$diff_run" "${perc_run_lost}%"
1022 
1023         echo ""
1024         echo "≥47289: DST successes = ${runs_after_createDst_ge47289:-0}, events = ${actual_events_after_createDst_ge47289:-0}"
1025 
1026         if $REMOVE_MISSING_MAPS; then
1027             missing_maps_all=${total_runs_missing_bad_tower:-0}
1028             missing_maps_ge47289=${missing_maps_ge47289:-0}
1029 
1030             diff_maps=$(echo "$missing_maps_all - $missing_maps_ge47289" | bc)
1031             if (( missing_maps_all > 0 )); then
1032                 perc_maps_lost=$(echo "scale=2; 100.0*$diff_maps/$missing_maps_all" | bc)
1033             else
1034                 perc_maps_lost=0
1035             fi
1036 
1037             echo ""
1038             echo "Differences in Missing Bad Tower Map Runs:"
1039             printf "%-40s | %-20s | %-20s | %-20s | %-20s\n" \
1040               "Missing Map Runs" \
1041               "$missing_maps_all" \
1042               "$missing_maps_ge47289" \
1043               "$diff_maps" \
1044               "${perc_maps_lost}%"
1045         fi
1046     fi
1047 }
1048 
1049 ########################################
1050 # MAIN EXECUTION
1051 ########################################
1052 
1053 echo -e "${BOLD}${GREEN}========================================${RESET}"
1054 echo -e "${BOLD}${GREEN}Starting the Golden Run List Generation${RESET}"
1055 echo -e "${BOLD}${GREEN}========================================${RESET}"
1056 
1057 parse_arguments "$@"
1058 set_workplace
1059 setup_directories
1060 clean_previous_data
1061 
1062 extract_initial_runs
1063 validate_golden_list
1064 
1065 apply_incremental_cuts_header
1066 runtime_cut
1067 livetime_cut
1068 missing_bad_tower_maps_step
1069 
1070 magnet_check_step
1071 
1072 create_list_file
1073 clean_old_dst_lists
1074 
1075 if ! $DONT_GENERATE_FILELISTS; then
1076     generate_dst_lists
1077 fi
1078 
1079 apply_createDstList_cut
1080 compute_event_counts
1081 final_summary