1
1
-- locals ---------------------------------------------------------------------o
2
- local matrix, mtable, tostring, damap, vector, object, plot in MAD
3
- local eps in MAD.constant
4
- local is_number, is_string, is_vector, is_table in MAD.typeid
5
- local openfile, tblcpy, val2keys, fileexists, tblcat, strinter in MAD.utility
6
- local pi, abs, floor, log, max in math
7
- local round in MAD.gmath
2
+ local mtable, damap, object in MAD
3
+ local openfile, fileexists, tblcat, strinter in MAD.utility
4
+ local max in math
5
+
6
+ package.path = package.path .. ";../tools/?.mad"
7
+ local get_diff, save_results, gen_cfg, in_dir, out_dir, plt_dir,
8
+ plot_trk_res, get_prev_res, prnt_results, add_trk_gen_cols,
9
+ show_res in require "track-tool"
8
10
9
11
local create_dif = require "madl_dbgmap".cmpmdump
10
- local plot_id = 0
11
- -- unique plot_id generator
12
- local function newSID ()
13
- plot_id = plot_id % 25 + 1
14
- return plot_id
15
- end
16
12
17
13
local dum = damap() -- get a dummy damap object for reading
18
14
local X0s = {{x=0 , px=0 , y=0 , py=0 , t=0 , pt=0 }, -- zero
19
- {x=3e-3, px=-2e-4, y=-2e-3, py=3e-4, t=0 , pt=0 }, -- 4D
20
- {x=3e-3, px=-2e-4, y=-2e-3, py=3e-4, t=0 , pt=2e-5}, -- 5D
21
- {x=3e-3, px=-2e-4, y=-2e-3, py=3e-4, t=1e-5, pt=2e-5}} -- 6D
15
+ {x=3e-3, px=-2e-4, y=-2e-3, py=3e-4, t=0 , pt=0 }, -- 4D
16
+ {x=3e-3, px=-2e-4, y=-2e-3, py=3e-4, t=0 , pt=2e-5}, -- 5D
17
+ {x=3e-3, px=-2e-4, y=-2e-3, py=3e-4, t=1e-5, pt=2e-5}} -- 6D
22
18
23
19
local coord_str = [[
24
20
x0 = ${x};
@@ -48,19 +44,12 @@ energy = ${energy};
48
44
${test_ctx}
49
45
]]
50
46
51
- local in_dir = \s -> 'input/' ..(s or '')
52
47
local ref_file = openfile(in_dir("ref.madx"), "r")
53
48
local madx_ref = ref_file:read("*a")
54
49
ref_file:close()
55
50
local ref_file = openfile(in_dir("ref.mad"), "r")
56
51
local mad_ref, mad_file = ref_file:read("*a")
57
52
ref_file:close()
58
-
59
- local out_dir = \s -> 'output/'..(s or '')
60
- local plt_dir = \s -> out_dir('plots/'..(s or ''))
61
-
62
- os.execute("mkdir -p "..out_dir()) -- Create output dir if it doesn't exist
63
- os.execute("mkdir -p "..plt_dir()) -- Create image dir if it doesn't exist
64
53
-------------------------------------------------------------------------------o
65
54
66
55
-- Write MAD-X script to elmseq.seq and generate a MAD-NG script and return it-o
@@ -110,253 +99,42 @@ local function do_trck(cfg)
110
99
111
100
-- Grab PTC last map from out file and get diff with mflw[1]
112
101
local ptc_res = getlastmap(out_dir(cfg.name .. "_p.txt")):fromptc()
113
- local dif = mflw[1]:dif(ptc_res)
114
-
115
- -- Setup max matrix (coords x order)
116
- local max_difs = matrix(6, cfg.order+1)
117
-
118
- for i, c in ipairs({"x", "px", "y", "py", "t", "pt"}) do
119
- -- Get max idx for each coordinate at each order
120
- local _, max_idxs = dif[c]:maxbyord()
121
-
122
- -- Create dummy vector to store max values
123
- local max_vals = vector(#max_idxs)
124
-
125
- -- Get max value for each order
126
- max_idxs:map(\x-> x~=0 and abs(dif[c]:get(x))/eps or 0, max_vals)
127
-
128
- -- Add max values to row of matrix
129
- max_difs:setrow(i, max_vals)
130
-
131
- -- Get and add coordinate max to results table
132
- res[c.."_eps"] = max_vals:max()
133
- end
134
-
135
- -- Get and add order max to results table
136
- for i = 1, max_difs.ncol do
137
- res["order"..i-1.."_eps"] = max_difs:getcol(i):max()
138
- end
139
- return res
102
+ return get_diff(mflw[1], ptc_res, cfg.order)
140
103
end
141
104
142
105
local function run_cfg (cfg, results)
143
106
-- Run track for a single configuration
144
107
local res = do_trck(cfg)
145
108
146
- -- Add results and configuration to table
147
- results:addrow{
148
- __cfg=tblcpy(cfg.cur_cfg),
149
- __res=res,
150
- }
151
-
152
- if cfg.doprnt then -- If print mode is on, print results
153
- io.write(cfg.cur_cfg.cfgid, "\t")
154
- -- Print max dif for each order
155
- for i = 1, cfg.order+1 do
156
- local ord_max_dif = res["order"..i-1.."_eps"]
157
- io.write(
158
- ord_max_dif > cfg.tol and (">e+" .. floor(log(ord_max_dif, 10)))
159
- or string.format("%d", ord_max_dif),
160
- "\t"
109
+ save_results(cfg, res, results)
110
+ prnt_results(cfg, res)
111
+ if not cfg.dodbg then return end-- If debug mode is on, stop when max dif is greater than tol
112
+ for i = 1, cfg.order+1 do
113
+ if res["order"..i-1.."_eps"] > cfg.tol then
114
+ io.write("Max dif greater than tolerance, stopping...\n")
115
+ -- Run mad in debug mode and set the program to stop
116
+ create_seq(cfg {debug = 6})
117
+ openfile(in_dir(cfg.name.."_ref.mad"), "w"):write(mad_ref%cfg):close()
118
+ os.execute(
119
+ '../mad '.. in_dir(cfg.name.."_ref.mad")
120
+ ..' >' .. out_dir(cfg.name .. "_n.txt")
161
121
)
162
- end
163
- -- Print current configuration
164
- for i, attr in ipairs(cfg.alist) do
165
- io.write(attr, "=", tostring(cfg.cur_cfg[attr]), ", ")
166
- end
167
- io.write("\n")
168
- end
169
-
170
- if cfg.dodbg then -- If debug mode is on, stop when max dif is greater than tol
171
- for i = 1, cfg.order+1 do
172
- if res["order"..i-1.."_eps"] > cfg.tol then
173
- print("Max dif greater than tolerance, stopping...")
174
- -- Run mad in debug mode and set the program to stop
175
- create_seq(cfg {debug = 6})
176
- openfile(in_dir(cfg.name.."_ref.mad"), "w"):write(mad_ref%cfg):close()
177
- os.execute(
178
- '../mad '.. in_dir(cfg.name.."_ref.mad")
179
- ..' >' .. out_dir(cfg.name .. "_n.txt")
180
- )
181
- create_dif({nam=out_dir(cfg.name)})
182
- cfg.stop = true
183
- end
184
- end
185
- end
186
- end
187
-
188
- -- From cfg object, create every configuration through recursion --------------o
189
- local function gen_cfg(cfg, idx, gen_fun)
190
- if cfg.stop then return end -- Stop if the stop flag is set
191
- local k = cfg.alist[idx]
192
- if not k then
193
- cfg.cur_cfg.cfgid = cfg.cur_cfg.cfgid + 1
194
- return gen_fun() -- Could be changed to any function
195
- end
196
- for i, v in ipairs(cfg[k]) do
197
- cfg.cur_cfg[k] = v
198
- gen_cfg(cfg, idx+1, gen_fun) -- Index required as this needs to stay constant during each call
199
- end
200
- end
201
-
202
- -- Add the generator columns to the table ---------------------------------------o
203
- local function add_gen_cols(results, cfg)
204
- -- Create the result column names as a list
205
- local ord_lst = {}
206
- for i = 0, cfg.order do ord_lst[i+1] = "order"..i.."_eps" end
207
- results.res_cols = tblcat(
208
- ord_lst, {"x_eps", "px_eps", "y_eps", "py_eps", "t_eps", "pt_eps"}
209
- )
210
-
211
- -- Add the cfg columns to the mtable
212
- results:addcol("cfgid", \ri, m -> m.__cfg[ri].cfgid)
213
- for _, k in ipairs(cfg.alist) do
214
- results:addcol(k, \ri, m =>
215
- local v = m.__cfg[ri][k]
216
- return is_table(v) and MAD.tostring(v) or v
217
- end)
218
- end
219
-
220
- -- Add the result columns to the mtable
221
- for _, k in ipairs(results.res_cols) do
222
- results:addcol(k, \ri, m -> round(m.__res[ri][k], 2))
223
- end
224
- end
225
- -------------------------------------------------------------------------------o
226
-
227
- -- Output results of test ----------------------------------------------------o
228
- local function get_lower_bnds(res, tol)
229
- if is_string(tol) then
230
- local bnds_file = mtable:read(tol)
231
- assert(
232
- #bnds_file == #res,
233
- "The tolerance file must have the same number of rows as the configuration file"
234
- )
235
- return \o, ri->bnds_file[ri]["order"..o.."_eps"]
236
- elseif is_number(tol) then
237
- return \->tol
238
- else
239
- return \o->tol[o]
240
- end
241
- end
242
-
243
- local function show_res(res, cfg, attr_cols, tol)
244
- local tol = get_lower_bnds(res, tol)
245
- local col_tbl = {}; for i = 0, res.max_order do col_tbl[i] = {} end
246
- local dum_tbl = mtable(tblcpy(attr_cols))
247
- dum_tbl.novector = true
248
-
249
- io.write("For each order, the number of configurations that failed:\n")
250
- for o = 0, res.max_order do
251
- local err_tbl = dum_tbl:copy()
252
- local max_err = 0
253
- res:foreach(\r, ri =>
254
- max_err = max(max_err, abs(res[ri]["order"..o.."_eps"]))
255
- if res[ri]["order"..o.."_eps"] > tol(o, ri) then
256
- for i, v in ipairs(attr_cols) do
257
- err_tbl[v][ri] = cfg[ri][v]
258
- end
259
- end end)
260
-
261
- -- Printing
262
- io.write("\norder ", o, " (max error = ", max_err, ", tol = ", cfg.run_tol, "):\n")
263
- for _, col_name in ipairs(attr_cols) do
264
- if not (col_name == "cfgid") then
265
- local _, key_cnt = val2keys(err_tbl:getcol(col_name))
266
- io.write(col_name, "\t= ", tostring(key_cnt), "\n")
267
- end
122
+ create_dif({nam=out_dir(cfg.name)})
123
+ cfg.stop = true
124
+ return
268
125
end
269
126
end
270
127
end
271
128
272
- local function get_prev_res(test_name)
273
- -- Read the previous results
274
- local cfg = mtable:read(out_dir(test_name.."_cfg.tfs"))
275
- local res = mtable:read(out_dir(test_name.."_res.tfs"))
276
- return cfg, res
277
- end
278
- -------------------------------------------------------------------------------o
279
-
280
- -- Plot the results -----------------------------------------------------------o
281
- local to_text = \str-> str:gsub("{", ""):gsub("}", ""):gsub("%$", "")
282
- local plot_template = plot {
283
- legendpos = "right top",
284
- prolog = "reset",
285
- ylabel = "Error",
286
- yrange = {1e-16, 1e1},
287
- wsizex = 1080,
288
- wsizey = 720,
289
- exec = false
290
- }
291
-
292
- local colours = {
293
- "red", "blue", "green", "orange", "purple", "brown", "pink", "grey", "black"
294
- }
295
-
296
- local function plot_res(res_cfg_tbl, cfg, cfg_tbl_)
297
- local plot_info = cfg.plot_info or {}
298
- local x_axis_attr = plot_info.x_axis_attr or "${cfgid}"
299
- local cfg_plot = plot_template {
300
- sid = newSID(),
301
- title = cfg.name,
302
- output = plot_info.filename and plt_dir(plot_info.filename) or 2,
303
- xlabel = to_text(x_axis_attr),
304
- exec = false
305
- }
306
- local cfg_tbl = cfg_tbl_ or res_cfg_tbl
307
- local res_tbl = res_cfg_tbl
308
- local n_points = #res_tbl
309
- local series = plot_info.series or {"${cfgid} > 0"}
310
- local n_series = #series
311
- local x_data = table.new(n_series, 0)
312
- local y_data = table.new(n_series, 0)
313
- for i = 1, n_series do
314
- x_data[i], y_data[i] = {}, {}
315
- local cnt = 1
316
- for j = 1, n_points do
317
- if loadstring("return " .. series[i] % cfg_tbl[j])() then
318
- x_data[i][cnt] = loadstring("return " .. x_axis_attr % cfg_tbl[j])()
319
- local y_value = 0
320
- for i = 1, res_tbl.max_order do
321
- y_value = max(y_value, res_tbl[j]["order"..i.."_eps"])
322
- end
323
- y_value = y_value * eps
324
- y_data[i][cnt] = y_value > 1e-16 and y_value or 1e-16
325
- cnt = cnt + 1
326
- end
327
- end
328
- end
329
-
330
- cfg_plot.data, cfg_plot.datastyles, cfg_plot.x1y1, cfg_plot.legend = {}, {}, {}, {}
331
- for i = 1, n_series do
332
- cfg_plot.data["x"..i] = x_data[i]
333
- cfg_plot.data["y"..i] = y_data[i]
334
- cfg_plot.x1y1["x"..i] = "y"..i
335
- cfg_plot.datastyles["y"..i] = {
336
- style = "points",
337
- pointtype = i,
338
- color = colours[i],
339
- }
340
- cfg_plot.legend["y"..i] = to_text(series[i])
341
- end
342
-
343
- plot_info.plotcfg =
344
- [[
345
- set logscale y
346
- ]] .. (plot_info.plotcfg or "")
347
-
348
- cfg_plot (plot_info)
349
- end
350
-
351
129
-- Run test -------------------------------------------------------------------o
352
130
local function run_test(cfg)
353
131
-- If the user does not want to run the test,
354
132
-- just show results from previous run
355
133
if not cfg.dorun then
356
- local cfg_tbl, res_tbl = get_prev_res(cfg.name)
134
+ local cfg_tbl, res_tbl = get_prev_res(cfg.name, out_dir )
357
135
res_tbl.max_order = cfg.order
358
136
if cfg.doprnt then show_res(res_tbl, cfg_tbl, cfg_tbl:colnames(), cfg.tol) end
359
- if cfg.doplot then plot_res (res_tbl, cfg, cfg_tbl) end
137
+ if cfg.doplot then plot_trk_res (res_tbl, cfg, plt_dir , cfg_tbl) end
360
138
return
361
139
end
362
140
@@ -378,18 +156,16 @@ local function run_test(cfg)
378
156
}
379
157
380
158
if cfg.doprnt then
381
- io.write("Running ", cfg.name, " (tol = ", cfg.tol, ")\n")
382
- -- Print the header
383
- io.write("cfgid\t")
384
- for i = 0, cfg.order do io.write("order "..i.."\t") end
159
+ io.write("Running ", cfg.name, " (tol = ", cfg.tol, ")\n", "cfgid\t")
160
+ for i = 0, cfg.order do io.write("order ", i, "\t") end
385
161
io.write("\n")
386
162
end
387
163
388
164
-- Fill the mtable with the cfg and results
389
165
gen_cfg(cfg, 1, \-> run_cfg(cfg, results))
390
166
391
167
-- Add the generator columns to the results table
392
- add_gen_cols (results, cfg)
168
+ add_trk_gen_cols (results, cfg)
393
169
394
170
-- Decide whether to save the results
395
171
local dosave = cfg.dosave or not (
@@ -419,7 +195,7 @@ local function run_test(cfg)
419
195
420
196
-- Plot the results
421
197
if cfg.doplot then
422
- plot_res (results, cfg)
198
+ plot_trk_res (results, cfg, plt_dir )
423
199
end
424
200
425
201
-- Cleanup excess files if the program is not stopped mid-test
0 commit comments