Skip to content

Commit 8ab000b

Browse files
authored
Merge pull request #303 from jgray-19/test_ptc
Update NG vs PTC Tests
2 parents 4abd4ff + ec2f655 commit 8ab000b

File tree

3 files changed

+311
-259
lines changed

3 files changed

+311
-259
lines changed

tests/tests/test-ptc-maps/test-quad-maps.mad

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ local function testQUADhe ()
245245
local cfg = ref_cfg "quadhe" {
246246
elm = [[
247247
QUADRUPOLE, at=0.75, l=1.5, k1=${k1}, k1s=${k1s}, fringe=7,
248-
k0=${k0}, e1=${e1}, e2=${e2}, h1=${h1}, h2=${h2}, bend_fringe=true
248+
k0=${k0}, e1=${e1}, e2=${e2}, h1=${h1}, h2=${h2}, bend_fringe=true,
249+
fringe_max=${fringe_max}
249250
]],
250251

251252
tol = 500,
@@ -262,9 +263,10 @@ local function testQUADhe ()
262263
e2 = {0, 0.3, 0.8},
263264
h1 = {0, 0.04, 0.05},
264265
h2 = {0, 0.04, 0.05},
266+
fringe_max = {2, 5},
265267
alist = tblcat(
266268
ref_cfg.alist,
267-
{"k1", "k1s", "k0", "e1", "e2", "h1", "h2"}
269+
{"k1", "k1s", "k0", "e1", "e2", "h1", "h2", "fringe_max"}
268270
),
269271

270272
plot_info = {

tests/tests/test-ptc-maps/trackvsptc.mad

Lines changed: 33 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
11
-- 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"
810

911
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
1612

1713
local dum = damap() -- get a dummy damap object for reading
1814
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
2218

2319
local coord_str = [[
2420
x0 = ${x};
@@ -48,19 +44,12 @@ energy = ${energy};
4844
${test_ctx}
4945
]]
5046

51-
local in_dir = \s -> 'input/' ..(s or '')
5247
local ref_file = openfile(in_dir("ref.madx"), "r")
5348
local madx_ref = ref_file:read("*a")
5449
ref_file:close()
5550
local ref_file = openfile(in_dir("ref.mad"), "r")
5651
local mad_ref, mad_file = ref_file:read("*a")
5752
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
6453
-------------------------------------------------------------------------------o
6554

6655
-- 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)
11099

111100
-- Grab PTC last map from out file and get diff with mflw[1]
112101
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)
140103
end
141104

142105
local function run_cfg (cfg, results)
143106
-- Run track for a single configuration
144107
local res = do_trck(cfg)
145108

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")
161121
)
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
268125
end
269126
end
270127
end
271128

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-
351129
-- Run test -------------------------------------------------------------------o
352130
local function run_test(cfg)
353131
-- If the user does not want to run the test,
354132
-- just show results from previous run
355133
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)
357135
res_tbl.max_order = cfg.order
358136
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
360138
return
361139
end
362140

@@ -378,18 +156,16 @@ local function run_test(cfg)
378156
}
379157

380158
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
385161
io.write("\n")
386162
end
387163

388164
-- Fill the mtable with the cfg and results
389165
gen_cfg(cfg, 1, \-> run_cfg(cfg, results))
390166

391167
-- Add the generator columns to the results table
392-
add_gen_cols(results, cfg)
168+
add_trk_gen_cols(results, cfg)
393169

394170
-- Decide whether to save the results
395171
local dosave = cfg.dosave or not (
@@ -419,7 +195,7 @@ local function run_test(cfg)
419195

420196
-- Plot the results
421197
if cfg.doplot then
422-
plot_res(results, cfg)
198+
plot_trk_res(results, cfg, plt_dir)
423199
end
424200

425201
-- Cleanup excess files if the program is not stopped mid-test

0 commit comments

Comments
 (0)