1
+ -- locals ---------------------------------------------------------------------o
2
+ local mtable, damap, plot, tostring in MAD
3
+ local openfile, fileexists, tblcat, tblcpy in MAD.utility
4
+ local max, abs in math
5
+ local eps in MAD.constant
6
+
7
+ package.path = package.path .. ";../tools/?.mad"
8
+ local get_diff, save_results, gen_cfg, in_dir, out_dir, plt_dir,
9
+ plot_trk_res, get_prev_res, prnt_results, add_trk_gen_cols,
10
+ show_res, get_trk_y_val, newSID, get_lower_bnds, X0s, ptc_strs,
11
+ create_madx_seq, get_last_ptc_map in require "track-tool"
12
+
13
+ local create_dif = require "madl_dbgmap".cmpmdump
14
+ local coord_str, test_ctx, madx_script in ptc_strs
15
+ local method_list = {2, 4, 6, 8, "'teapot'"}
16
+
17
+ local ref_file = openfile(in_dir("ref.madx"), "r")
18
+ local madx_ref = ref_file:read("*a")
19
+ ref_file:close()
20
+ local ref_file = openfile(in_dir("ref.mad"), "r")
21
+ local mad_ref, mad_file = ref_file:read("*a")
22
+ ref_file:close()
23
+ -------------------------------------------------------------------------------o
24
+
25
+ -- Run track and PTC from cur_cfg and create results --------------------------o
26
+ local function do_trck(cfg)
27
+ -- Create results table
28
+ local res = {}
29
+
30
+ -- Create element sequence w/ current cfg context
31
+ create_madx_seq(cfg)
32
+ local ptc_res
33
+ if cfg.doptc and cfg.cur_cfg.method ~= "'teapot'" then
34
+ -- Run MAD-X-PTC
35
+ assert(os.execute(
36
+ '../madx64 '.. in_dir(cfg.name .. "_ref.madx")
37
+ ..' >' .. out_dir(cfg.name .. "_p.txt")
38
+ ))
39
+ -- Grab PTC last map from out file and get diff with mflw[1]
40
+ ptc_res = get_last_ptc_map(out_dir(cfg.name .. "_p.txt")):fromptc()
41
+ end
42
+ MADX.elm = nil -- Remove element so that next test can be run with new values
43
+
44
+ -- Run MAD-NG track
45
+ local _, mflw = mad_file()
46
+
47
+ return mflw[1], ptc_res
48
+ end
49
+
50
+ local function run_cfg (cfg, results)
51
+ -- Run track for a single configuration
52
+ if cfg.cur_cfg.nslice == 1 and cfg.cur_cfg.method == method_list[1] then -- All of one configuration about to start
53
+ local cur_cfg = cfg.cur_cfg -- Cache the current cfg
54
+
55
+ cfg.cur_cfg = cfg.converge_to -- Set the cfg to converge to
56
+ cfg.ng_target, cfg.ptc_target = do_trck(cfg) -- Run track to get the target result
57
+ cfg.cur_cfg = cur_cfg -- Restore the current cfg
58
+ end
59
+ local ng_target in cfg
60
+ local ng_res, ptc_res = do_trck(cfg)
61
+ local ng_dif = get_diff(ng_target, ng_res, cfg.order)
62
+ local ptc_dif = ptc_res and get_diff(cfg.ptc_target, ptc_res, cfg.order)
63
+
64
+ ng_dif["converged"] = true
65
+ for i = 0, cfg.order do
66
+ if abs(ng_dif["order"..i.."_eps"]) > cfg.tol then
67
+ ng_dif["converged"] = false
68
+ break
69
+ end
70
+ end
71
+ ng_dif.ptc_or_ng = "ng"
72
+ save_results(cfg, ng_dif, results)
73
+ prnt_results(cfg, ng_dif, results)
74
+ if ptc_res then
75
+ ptc_dif["converged"] = true
76
+ for i = 0, cfg.order do
77
+ if abs(ptc_dif["order"..i.."_eps"]) > cfg.tol then
78
+ ptc_dif["converged"] = false
79
+ break
80
+ end
81
+ end
82
+ ptc_dif.ptc_or_ng = "ptc"
83
+ save_results(cfg, ptc_dif, results)
84
+ prnt_results(cfg, ptc_dif, results)
85
+ end
86
+ end
87
+
88
+ -- Plot the results -----------------------------------------------------------o
89
+ local to_text = \str-> str:gsub("{", ""):gsub("}", ""):gsub("%$", "")
90
+ local series = {}
91
+ local legend = {}
92
+ for i, method in ipairs(method_list) do
93
+ series[i] = "${method} == "..method
94
+ legend["y"..i] = "Method "..tostring(method):gsub("'teapot'", "t")
95
+ end
96
+ local plot_template = plot {
97
+ prolog = [[
98
+ reset
99
+ f(x) = a*x**b
100
+ FIT_LIMIT = 1e-20
101
+ set format "%.1t{\327}10^{%T}"
102
+ set key noautotitle
103
+ ]],
104
+ ylabel = "Error",
105
+ yrange = {1e-16, 1e1},
106
+ wsizex = 1080,
107
+ wsizey = 720,
108
+ series = series,
109
+ legend = legend,
110
+ scrdump = "plot.gp",
111
+ exec = false,
112
+ }
113
+
114
+ local colours = {
115
+ "red", "blue", "green", "orange", "purple", "brown", "pink", "grey", "black"
116
+ }
117
+
118
+ -- Plot the results -----------------------------------------------------------o
119
+ local function plot_res(res_cfg_tbl, cfg, plt_dir, dofit, cfg_tbl_)
120
+ local legend, series = tblcpy(plot_template.legend), plot_template.series
121
+ local cfg_tbl, dif_tbl = cfg_tbl_ or res_cfg_tbl, res_cfg_tbl
122
+ for _, ptc_or_ng in ipairs {"ng", cfg.doptc and "ptc" or nil} do
123
+ local is_ptc = ptc_or_ng == "ptc"
124
+ local plot_info = cfg.plot_info or {}
125
+ local x_axis_attr, filename, pointtype in plot_info
126
+ local cfg_plot = plot_template {
127
+ sid = newSID(),
128
+ title = cfg.name,
129
+ output = filename and plt_dir(ptc_or_ng .. "_" .. filename) or 2,
130
+ exec = false,
131
+ }
132
+ local n_points, n_series = #dif_tbl, is_ptc and 4 or #series ! Should be 5
133
+ local x_data, y_data = table.new(n_series, 0), table.new(n_series, 0)
134
+ local converge_points = {} -- Set default instead?
135
+ for i = 1, n_series do
136
+ x_data[i], y_data[i] = {}, {}
137
+ local cnt = 1
138
+ for j = 1, n_points do
139
+ if dif_tbl[j].ptc_or_ng == ptc_or_ng and
140
+ assert(loadstring("return " .. series[i] % cfg_tbl[j]))() then
141
+ x_data[i][cnt] = assert(loadstring("return " .. x_axis_attr % cfg_tbl[j]))()
142
+ local y_value = get_trk_y_val(dif_tbl[j], cfg)
143
+ y_data[i][cnt] = y_value > 1e-16 and y_value or 1e-16
144
+ if dif_tbl[j].converged then
145
+ converge_points[i] = math.max(x_data[i][cnt], converge_points[i] or 0)
146
+ end
147
+ cnt = cnt + 1
148
+ end
149
+ end
150
+ end
151
+
152
+ cfg_plot.data, cfg_plot.datastyles, cfg_plot.x1y1 = {}, {}, {}
153
+ local plotcfg, epilog = "", ""
154
+ for i = 1, n_series do
155
+ cfg_plot.data["x"..i] = x_data[i]
156
+ cfg_plot.data["y"..i] = y_data[i]
157
+ cfg_plot.x1y1["x"..i] = "y"..i
158
+ cfg_plot.datastyles["y"..i] = {
159
+ style = "points",
160
+ pointtype = i,!assert(loadstring("return " .. (pointtype or i) % cfg_tbl[j]))(),
161
+ color = colours[i],
162
+ }
163
+ cfg_plot.legend["y"..i] = legend["y"..i] .. (dofit and
164
+ "'.sprintf('= %.2g x^{%.2g}', a"..i..", b"..i..").'" or "")
165
+ if dofit then
166
+ plotcfg = plotcfg .. string.format("b%d=%d\nf%d(x) = a%d*x**b%d\n", i, 2, i, i, i)
167
+ plotcfg = plotcfg .. string.format("fit [%.3f:10] f%d(x) '$MAD_DATA' index %d using 1:2::($2**(0.5)) via a%d, b%d\n", converge_points[i] or 0, i, i-1, i, i)
168
+ epilog = epilog .. "replot ["..(converge_points[i] or eps)..":10] f"..i.."(x) linecolor '"..colours[i].."'\n"
169
+ end
170
+ end
171
+ plot_info.plotcfg = plotcfg ..
172
+ [[
173
+ set logscale y
174
+ ]] .. (plot_info.plotcfg or "")
175
+ plot_info.prolog = cfg_plot.prolog .. (plot_info.prolog or "")
176
+ plot_info.epilog = epilog .. [[
177
+ set term png enhanced font ',' size 1080,720;
178
+ set out "]]..cfg_plot.output..[[";
179
+ replot
180
+ ]]
181
+ plot_info.title = plot_info.title and ptc_or_ng:upper() .. " " .. plot_info.title or nil
182
+
183
+ cfg_plot (plot_info)
184
+ end
185
+ end
186
+ -- Run test -------------------------------------------------------------------o
187
+ local function run_test(cfg)
188
+ -- If the user does not want to run the test,
189
+ -- just show results from previous run
190
+ if not cfg.dorun then
191
+ local cfg_tbl, res_tbl = get_prev_res(cfg.name, out_dir)
192
+ res_tbl.max_order = cfg.order
193
+ if cfg.doprnt then show_res(res_tbl, cfg_tbl, cfg_tbl:colnames(), cfg.tol) end
194
+ if cfg.doplot then plot_res(res_tbl, cfg, plt_dir, cfg.dofit, cfg_tbl) end
195
+ return
196
+ end
197
+
198
+ -- Generate the reference file
199
+ cfg.seq_file = in_dir(cfg.name.."_seq.seq")
200
+ openfile(in_dir(cfg.name .. "_ref.madx"), "w"):write(madx_ref % cfg):close()
201
+
202
+ -- Load the MAD reference file and set the input sequence name
203
+ mad_file = loadstring(mad_ref % cfg)
204
+
205
+ -- Create new table for cur_cfg for each cfg set
206
+ cfg.cur_cfg = {cfgid = 0}
207
+
208
+ -- Create the mtable to store the results
209
+ local results = mtable(cfg.name){
210
+ "__cfg", "__res",
211
+ max_order = cfg.order,
212
+ run_tol = cfg.tol,
213
+ }
214
+
215
+ if cfg.doprnt then
216
+ io.write("Running ", cfg.name, " (tol = ", cfg.tol, ")\n")
217
+ for i = 0, cfg.order do io.write("order ", i, "\t") end
218
+ io.write("\n")
219
+ end
220
+
221
+ cfg.alist[#cfg.alist+1] = "method"
222
+ cfg.alist[#cfg.alist+1] = "nslice"
223
+ cfg.nslice = {
224
+ 1,2,4,6,8,10,
225
+ 20,40,60,80,100,
226
+ 125,150,175,200,500,1000,
227
+ -- 2000,5000,10000
228
+ }
229
+ cfg.method = method_list
230
+
231
+ -- Fill the mtable with the cfg and results
232
+ gen_cfg(cfg, 1, \-> run_cfg(cfg, results))
233
+
234
+ -- Add the generator columns to the results table
235
+ add_trk_gen_cols(results, cfg)
236
+ results:addcol("converged", \ri,m->m.__res[ri].converged)
237
+ results:addcol("ptc_or_ng", \ri,m->m.__res[ri].ptc_or_ng)
238
+
239
+ -- Decide whether to save the results
240
+ local dosave = cfg.dosave or not (
241
+ fileexists(out_dir(results.name.."_cfg.tfs")) and
242
+ fileexists(out_dir(results.name.."_res.tfs"))
243
+ )
244
+
245
+ -- Save the results (if required)
246
+ if dosave then
247
+ local hdr_lst = {"name", "date", "time", "origin", "max_order", "run_tol"}
248
+ results:write(
249
+ out_dir(results.name.."_cfg.tfs"),
250
+ tblcat({"cfgid"}, cfg.alist),
251
+ hdr_lst
252
+ )
253
+ results:write(
254
+ out_dir(results.name.."_res.tfs"),
255
+ tblcat({"cfgid", "converged", "ptc_or_ng"}, results.res_cols),
256
+ hdr_lst
257
+ )
258
+ end
259
+
260
+ -- Print the results
261
+ if cfg.doprnt then
262
+ show_res(results, results, cfg.alist, cfg.tol)
263
+ end
264
+
265
+ -- -- Plot the results
266
+ if cfg.doplot then
267
+ plot_res(results, cfg, plt_dir, cfg.dofit)
268
+ end
269
+
270
+ -- Cleanup excess files if the program is not stopped mid-test
271
+ if not cfg.stop then
272
+ os.remove(in_dir( cfg.name .. "_ref.madx"))
273
+ os.remove(out_dir(cfg.name .. "_p.txt" ))
274
+ os.remove(in_dir( cfg.name .. "_seq.seq" ))
275
+ os.remove("internal_mag_pot.txt")
276
+ os.remove("fort.18")
277
+ end
278
+ end
279
+ -------------------------------------------------------------------------------o
280
+ return { run_test = run_test }
0 commit comments