summary.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <?php
  2. require __DIR__ . '/commonfoos.php';
  3. $ini_array = parse_ini_file("config.ini");
  4. $token = $ini_array["apitoken"];
  5. $available_seasons = available_seasons($host, $owner, $repo, "energy_points", $token);
  6. $selected_season = isset($_GET["season"]) && in_array($_GET["season"], $available_seasons) ? $_GET["season"] : end($available_seasons);
  7. $selected_season_url = season_table_url($host, $owner, $repo, "", $token, $selected_season);
  8. ?>
  9. <html>
  10. <head>
  11. <script src="plotly-latest.min.js"></script>
  12. <script src="fmin.min.js"></script>
  13. <!--<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> -->
  14. <meta name="viewport" content="width=device-width, initial-scale=1">
  15. <link rel="stylesheet" href="main.css">
  16. <title>Compton interactive plots</title>
  17. </head>
  18. <body>
  19. <div style="display: flex; align-items: center; flex-wrap: wrap; justify-content: center; margin-top: min(20px,2%); margin-bottom: 40px;">
  20. <h2 style="margin: 0;"><a href="./" style="font-size: inherit;">Pictures</a> / Season</h2>
  21. <form name="form" action="" style="padding: 0 15px; margin: auto 0;" method="get">
  22. <select name="season" class="select-css" style="padding: 0.3em 1.3em 0.3em 0.4em;" onchange="this.form.submit()">
  23. <?
  24. foreach ($available_seasons as $season) {
  25. ?><option value="<? echo $season ?>" <? echo isSelected($season, $selected_season) ?>><? echo $season ?></option>
  26. <?
  27. }
  28. ?>
  29. </select>
  30. </form>
  31. <h2 style="margin: 0;">summary</h2>
  32. </div>
  33. <div style="display: flex; align-items: center; flex-wrap: wrap; justify-content: center;">
  34. <div style="max-width: 900px; width: 45%; min-width: min(100%, 600px); margin: 0 max(1%, 10px);">
  35. <h3>Mean energy measurements</h3>
  36. <div id="mean_energy_plot"></div>
  37. </div>
  38. <div style="max-width: 900px; width: 45%; min-width: min(100%, 600px); margin: 0 max(1%, 10px);">
  39. <h3>Spread measurements</h3>
  40. <div id="spread_plot"></div>
  41. </div>
  42. <div style="max-width: 900px; width: 45%; min-width: min(100%, 600px); margin: 0 max(1%, 10px);">
  43. <h3>Mean energy deviations</h3>
  44. <div id="energy_dev_plot"></div>
  45. </div>
  46. <div style="max-width: 900px; width: 45%; min-width: min(100%, 600px); margin: 0 max(1%, 10px);">
  47. <h3>Impact of mean energy deviations</h3>
  48. <div id="impact_energy_dev_plot"></div>
  49. </div>
  50. </div>
  51. <div style="margin-top: 40px; width: 100%;">
  52. <div style="width: min(100%, 600px); margin: 0 auto; font-size: 2rem;">
  53. <h3 style="padding-right: 40px;">Methodology</h3>
  54. <p style="font-size: inherit;"><b>Mean energy measurements:</b> a difference between measured mean beam energy and target beam energy vs target beam energy.</p>
  55. <p style="font-size: inherit;"><b>Spread measurements:</b> a measured mean beam spread vs measured mean beam energy for the given energy points. A line shows the best fit of these points to a linear function (as a result of chi-square minimization)</p>
  56. <p style="font-size: inherit;"><b>Mean energy deviations:</b> a measured mean energy deviations (so-called mean_energy_sys_err) vs measured mean beam energy for the given energy points.</p>
  57. <p style="font-size: inherit;"><b>Impact of mean energy deviations:</b> a part of the mean energy deviation in total uncertainty (as d/√(d<sup>2</sup> + s<sup>2</sup>), where d is the mean energy deviation and s is the mean spread) for the given energy points.</p>
  58. </div>
  59. </div>
  60. <script>
  61. function makeplot() {
  62. Plotly.d3.csv('<? echo $selected_season_url; ?>', (allRows) => {
  63. const {
  64. point_name,
  65. energy_point,
  66. mean_energy,
  67. mean_energy_stat_err,
  68. mean_energy_sys_err,
  69. mean_spread,
  70. mean_spread_stat_err
  71. } = parseResultsTable(allRows);
  72. makeMeanEnergyPlot(energy_point, mean_energy, mean_energy_stat_err, point_name, "mean_energy_plot");
  73. makeSpreadPlot(mean_energy, mean_spread, mean_spread_stat_err, point_name, "spread_plot");
  74. makeMeanDevPlot(mean_energy, mean_energy_sys_err, point_name, "energy_dev_plot");
  75. makeImpactDevPlot(point_name, mean_spread, mean_energy_sys_err, "impact_energy_dev_plot");
  76. });
  77. }
  78. function parseResultsTable(allRows) {
  79. // Extracts a row following the energy point in the total csv file (or null if energy point is not exists)
  80. let data = {};
  81. for (let key of Object.keys(allRows[0])) {
  82. data[key] = [];
  83. }
  84. data['point_name'] = [];
  85. let float_keys = ['energy_point', 'mean_energy', 'mean_energy_stat_err', 'mean_spread', 'mean_spread_stat_err', 'mean_energy_sys_err'];
  86. for (var i = 0; i < allRows.length; i++) {
  87. for (let key of Object.keys(allRows[i])) {
  88. let value = allRows[i][key];
  89. if (float_keys.includes(key)) {
  90. value = parseFloat(value);
  91. }
  92. data[key].push(value);
  93. }
  94. data['point_name'].push(allRows[i]['energy_point'] + '_' + allRows[i]['first_run']);
  95. }
  96. return data;
  97. }
  98. function linear_coeffs(x, y, yerr, remove_outliers = false) {
  99. // Returns a chi square minimizer for linear function
  100. function chi2min(X) {
  101. let k = X[0],
  102. b = X[1];
  103. let chi2 = 0;
  104. for (let i = 0; i < x.length; i++) {
  105. if (remove_outliers && (y[i] < 0.06))
  106. continue;
  107. y0 = k * x[i] + b;
  108. chi2 += Math.pow((y[i] - y0) / yerr[i], 2);
  109. }
  110. return chi2;
  111. }
  112. return chi2min;
  113. }
  114. function getPlotlyDefaults() {
  115. var layout = {
  116. margin: {
  117. l: 50,
  118. r: 50,
  119. b: 50,
  120. t: 50,
  121. pad: 4
  122. },
  123. font: {
  124. size: 18,
  125. },
  126. xaxis: {
  127. title: "Mean beam energy, MeV",
  128. automargin: true,
  129. },
  130. yaxis: {
  131. //domain: [0, 0.2],
  132. automargin: true,
  133. rangemode: 'positive',
  134. title: "Spread, MeV",
  135. hoverformat: '.2f',
  136. },
  137. showlegend: true,
  138. legend: {
  139. x: 0,
  140. xanchor: 'left',
  141. y: 1,
  142. },
  143. paper_bgcolor: 'rgba(0,0,0,0)',
  144. plot_bgcolor: 'rgba(0,0,0,0)',
  145. autosize: true,
  146. };
  147. var config = {
  148. toImageButtonOptions: {
  149. format: 'png', // one of png, svg, jpeg, webp
  150. filename: 'spread_plot_<? echo $selected_season; ?>',
  151. scale: 4,
  152. },
  153. responsive: true,
  154. modeBarButtonsToRemove: ['select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'resetScale2d', 'hoverClosestGl2d', 'hoverClosestPie', 'toggleHover', 'toggleSpikelines'],
  155. displayModeBar: true,
  156. };
  157. return {
  158. "layout": layout,
  159. "config": config,
  160. };
  161. }
  162. function makeMeanEnergyPlot(energy_point, mean_energy, mean_energy_stat_err, texts, elementId) {
  163. // Plots mean energy - target energy vs target energy
  164. var energy_diff = [];
  165. Plotly.d3.zip(mean_energy, energy_point).forEach(e => energy_diff.push(e[0] - e[1]));
  166. var trace1 = {
  167. x: energy_point,
  168. y: energy_diff,
  169. yaxis: 'y',
  170. mode: 'markers',
  171. text: Plotly.d3.zip(texts, mean_energy),
  172. text2: mean_energy,
  173. hovertemplate: "Point: %{text[0]}<br>Mean energy = %{text[1]:.3f} ± %{error_y.array:.3f} MeV" + "<extra></extra>",
  174. //hovermode: "x",
  175. error_y: {
  176. type: 'data',
  177. array: mean_energy_stat_err,
  178. color: '#260101',
  179. },
  180. showlegend: false,
  181. marker: {
  182. color: '#260101',
  183. },
  184. type: "scatter",
  185. };
  186. var traces = [trace1];
  187. var {
  188. layout,
  189. config
  190. } = getPlotlyDefaults();
  191. layout.xaxis.title = "Target energy, MeV";
  192. layout.yaxis.title = "Mean energy - Target energy, MeV";
  193. Plotly.newPlot(elementId, traces, layout, config);
  194. }
  195. function makeMeanDevPlot(mean_energy, mean_energy_sys_err, texts, elementId) {
  196. // Plots mean energy deviations vs mean measured energy
  197. var trace1 = {
  198. x: mean_energy,
  199. y: mean_energy_sys_err,
  200. text: texts,
  201. mode: 'markers',
  202. marker: {
  203. size: 12,
  204. symbol: 'diamond',
  205. },
  206. hovertemplate: "Point: %{text}<br>x = %{x:.2f} MeV<br>y = %{y:.3f} MeV" + "<extra></extra>",
  207. showlegend: false,
  208. };
  209. var traces = [trace1];
  210. var {
  211. layout,
  212. config
  213. } = getPlotlyDefaults()
  214. layout.yaxis.title = "Mean energy deviation, MeV";
  215. Plotly.newPlot(elementId, traces, layout, config);
  216. }
  217. function makeSpreadPlot(mean_energy, mean_spread, mean_spread_stat_err, texts, elementId) {
  218. // Plots spreads vs mean measured energy
  219. var chi2min = linear_coeffs(mean_energy, mean_spread, mean_spread_stat_err, true);
  220. var solution = fmin.nelderMead(chi2min, [0.001, 0]);
  221. var trace1 = {
  222. x: mean_energy,
  223. y: mean_spread,
  224. yaxis: 'y',
  225. mode: 'markers',
  226. text: texts,
  227. hovertemplate: "Point: %{text}<br>x = %{x:.2f} MeV<br>y = %{y:.3f} ± %{error_y.array:.3f} MeV" + "<extra></extra>",
  228. hovermode: "x",
  229. error_y: {
  230. type: 'data',
  231. array: mean_spread_stat_err,
  232. color: '#260101',
  233. },
  234. showlegend: false,
  235. marker: {
  236. color: '#260101',
  237. },
  238. type: "scatter",
  239. };
  240. var trace2 = {
  241. x: [Plotly.d3.min(mean_energy), Plotly.d3.max(mean_energy)],
  242. y: [solution.x[0] * Plotly.d3.min(mean_energy) + solution.x[1], solution.x[0] * Plotly.d3.max(mean_energy) + solution.x[1]],
  243. mode: 'lines',
  244. name: 'Fit: y = ' + Math.round(parseFloat(solution.x[0]) * 1e5) / 1e5 + 'x ' + (Math.sign(solution.x[1]) > 0 ? "+" : "") + Math.round(solution.x[1] * 1e3) / 1e3,
  245. hovermode: false,
  246. hoverinfo: 'none',
  247. };
  248. var traces = [trace1, trace2];
  249. var {
  250. layout,
  251. config
  252. } = getPlotlyDefaults()
  253. Plotly.newPlot(elementId, traces, layout, config);
  254. }
  255. function makeImpactDevPlot(point_name, mean_spread, mean_energy_sys_err, elementId) {
  256. let arr = Plotly.d3.zip(mean_spread, mean_energy_sys_err);
  257. let impact_factor = [];
  258. arr.forEach(e => impact_factor.push(e[1] / Math.pow(e[0] ** 2 + e[1] ** 2, 0.5)));
  259. var data = [{
  260. type: 'bar',
  261. x: impact_factor,
  262. y: point_name,
  263. orientation: 'h',
  264. showlegend: false,
  265. text: impact_factor.map(e => String(Math.round(e * 1e2)) + '%'),
  266. textposition: 'auto',
  267. hovertemplate: "Point: %{y}<br>Impact of %{text} <extra></extra>",
  268. //hoverinfo: 'none',
  269. }];
  270. var {
  271. layout,
  272. config
  273. } = getPlotlyDefaults();
  274. layout.xaxis.range = [0, 1];
  275. layout.yaxis.title = "";
  276. layout.xaxis.title = "Impact of mean energy deviations";
  277. Plotly.newPlot(elementId, data, layout, config);
  278. }
  279. makeplot();
  280. </script>
  281. </body>
  282. </html>