-
Notifications
You must be signed in to change notification settings - Fork 5
/
recon.rb
executable file
·124 lines (106 loc) · 3.39 KB
/
recon.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env ruby
# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2023 Christopher Dilks
require 'yaml'
require 'optparse'
require 'ostruct'
# default CLI options
options = OpenStruct.new
options.sim_file = 'out/sim.edm4hep.root'
options.rec_file = 'out/rec.edm4hep.root'
options.config_file = 'config/recon_main.yaml'
options.dry_run = false
options.debug_run = false
options.eicrecon_bin = 'eicrecon'
# parse CLI options
OptionParser.new do |o|
o.banner = "USAGE: #{$0} [OPTIONS]..."
o.separator('')
o.separator('OPTIONS:')
o.on("-c", "--config [FILE]", "Configuration YAML file", "Default: #{options.config_file}"){ |a| options.config_file = a }
o.separator('')
o.on("-s", "--sim [FILE]", "Simulation input file", "Default: #{options.sim_file}"){ |a| options.sim_file = a }
o.separator('')
o.on("-r", "--rec [FILE]", "Reconstruction output file", "Default: #{options.rec_file}"){ |a| options.rec_file = a }
o.separator('')
o.on("-d", "--dry-run", "Dry run: just print the EICrecon command and exit"){ options.dry_run = true }
o.separator('')
o.on("-D", "--debug", "Run in GDB debugger"){
options.debug_run = true
options.eicrecon_bin = 'gdb --args eicrecon'
}
o.separator('')
o.on_tail("-h", "--help", "Show this message") do
puts o
exit 2
end
end.parse!(ARGV)
# puts "OPTIONS: #{options}"
# check for existence of input files
[
options.sim_file,
options.config_file,
].each do |name|
unless File.exist? name
$stderr.puts "ERROR: file '#{name}' does not exist"
exit 1
end
end
# parse configuration file to Hash
config_yaml = YAML.load_file options.config_file
# parse a YAML tree of settings, returning an Array of strings with:
# - list of node path keys combined with `String.join ':'`
# - leaf node appended as "=#{leaf}"
# - Array leaves will be returned as `String.join ','`
def traverse(tree, tree_name='')
case tree.class.name
when 'Hash' # if a sub-tree, recurse
tree.map do |branch_name, branch|
next_name = [tree_name, branch_name].join(':').sub /^:/, ''
traverse branch, next_name
end.flatten
when 'Array' # if an array, return Array.join ','
"#{tree_name}=#{tree.join ','}"
else # if a leaf, append it to the final string and stop recursion
[tree_name, tree.to_s].join '='
end
end
# convert parsed config file settings into 'key=value' pairs JANA can use
arg_list = traverse config_yaml
# fix: key name of log level settings
arg_list.map! do |it|
if it.match? /^log_levels:/
it.sub(/^log_levels:/,'').sub(/\=/,':LogLevel=')
else
it
end
end
# append CLI settings
arg_list += traverse({
"podio:output_file" => options.rec_file,
})
# if debugging, override the timeout
arg_list += traverse({ "jana:timeout" => "0" }) if options.debug_run
# prepend '-P' to each setting, and add quotes around the value
arg_list.map! do |it|
'-P' + it.sub(/.*\=/, '\0"') + '"'
end
# finally, append the input file name
arg_list << options.sim_file
# build the eicrecon command
eicrecon_cmd = [options.eicrecon_bin, *arg_list].join ' '
# print eicrecon command
puts """
EICRECON ARGUMENTS: ["""
arg_list.each{ |it| puts " #{it}," }
puts """]
EICRECON COMMAND:
#{eicrecon_cmd}
"""
# if a dry run, exit prematurely
if options.dry_run
puts "\nThis is a dry run: stopping before running the above command\n\n"
exit
end
# run eicrecon: `exec` hands process control over to `eicrecon_cmd`
exec eicrecon_cmd