cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
TopdrawerDrawer.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2013-2022 Laurent Forthomme
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <cmath>
20#include <fstream>
21
24#include "CepGen/Utils/Drawer.h"
25#include "CepGen/Utils/Graph.h"
27#include "CepGen/Utils/Piper.h"
28#include "CepGen/Utils/String.h"
29#include "CepGen/Version.h"
30
31#ifndef TD_BIN
32#error "Topdrawer executable must be specified using TD_BIN!"
33#else
34#define STRINGIFY(x) #x
35#define TOSTRING(x) STRINGIFY(x)
36#define TD TOSTRING(TD_BIN)
37#endif
38
39namespace cepgen {
40 namespace utils {
41 class TopdrawerDrawer : public Drawer {
42 public:
43 explicit TopdrawerDrawer(const ParametersList&);
44
46
47 const TopdrawerDrawer& draw(const Graph1D&, const Mode&) const override;
48 const TopdrawerDrawer& draw(const Graph2D&, const Mode&) const override;
49 const TopdrawerDrawer& draw(const Hist1D&, const Mode&) const override;
50 const TopdrawerDrawer& draw(const Hist2D&, const Mode&) const override;
51
52 const TopdrawerDrawer& draw(const DrawableColl&,
53 const std::string& name = "",
54 const std::string& title = "",
55 const Mode& mode = Mode::none) const override;
56
57 private:
58 static void execute(const Piper::Commands&, const std::string&);
59 static Piper::Commands plot(const Graph1D&);
60 static Piper::Commands plot(const Graph2D&, const Mode&);
61 static Piper::Commands plot(const Hist1D&);
62 static Piper::Commands plot(const Hist2D&, const Mode&);
63 static Piper::Commands postDraw(const Drawable&, const Mode&);
64 static Piper::Commands stringify(const std::string&, const std::string&);
65 static const std::map<std::string, std::pair<char, char> > kSpecChars;
66
67 Piper::Commands preDraw(const Drawable&, const Mode&) const;
68
69 const std::string font_;
70 const bool filling_;
71 };
72
73 const std::map<std::string, std::pair<char, char> > TopdrawerDrawer::kSpecChars = {
74 {"Alpha", {'A', 'F'}}, {"Beta", {'B', 'F'}},
75 {"Chi", {'C', 'F'}}, {"Delta", {'D', 'F'}},
76 {"Epsilon", {'E', 'F'}}, {"Phi", {'F', 'F'}},
77 {"Gamma", {'G', 'F'}}, {"Eta", {'H', 'F'}},
78 {"Iota", {'I', 'F'}}, {"Kappa", {'K', 'F'}},
79 {"Lambda", {'L', 'F'}}, {"Mu", {'M', 'F'}},
80 {"Nu", {'N', 'F'}}, {"Omicron", {'O', 'F'}},
81 {"Pi", {'P', 'F'}}, {"Theta", {'Q', 'F'}},
82 {"Rho", {'R', 'F'}}, {"Sigma", {'S', 'F'}},
83 {"Tau", {'T', 'F'}}, {"Upsilon", {'U', 'F'}},
84 {"Omega", {'W', 'F'}}, {"Xi", {'X', 'F'}},
85 {"Psi", {'Y', 'F'}}, {"Zeta", {'Z', 'F'}},
86 {"alpha", {'A', 'G'}}, {"beta", {'B', 'G'}},
87 {"chi", {'C', 'G'}}, {"delta", {'D', 'G'}},
88 {"epsilon", {'E', 'G'}}, {"phi", {'G', 'G'}},
89 {"gamma", {'G', 'G'}}, {"eta", {'H', 'G'}},
90 {"iota", {'I', 'G'}}, {"kappa", {'K', 'G'}},
91 {"lambda", {'L', 'G'}}, {"mu", {'M', 'G'}},
92 {"nu", {'N', 'G'}}, {"omicron", {'O', 'G'}},
93 {"pi", {'P', 'G'}}, {"theta", {'Q', 'G'}},
94 {"rho", {'R', 'G'}}, {"sigma", {'S', 'G'}},
95 {"tau", {'T', 'G'}}, {"upsilon", {'U', 'G'}},
96 {"omega", {'W', 'G'}}, {"xi", {'X', 'G'}},
97 {"psi", {'Y', 'G'}}, {"zeta", {'Z', 'G'}},
98 {"simeq", {'C', 'M'}}, {"gt", {'G', 'M'}},
99 {"ge", {'H', 'M'}}, {"int", {'I', 'M'}},
100 {"icirc", {'J', 'M'}}, {"lt", {'L', 'M'}},
101 {"le", {'M', 'M'}}, {"neq", {'N', 'M'}},
102 {"sim", {'S', 'M'}}, {"perp", {'T', 'M'}},
103 {"dpar", {'Y', 'M'}}, {"infty", {'0', 'M'}},
104 {"sqrt", {'2', 'M'}}, {"pm", {'+', 'M'}},
105 {"mp", {'-', 'M'}}, {"otimes", {'*', 'M'}},
106 {"equiv", {'=', 'M'}}, {"cdot", {'.', 'M'}},
107 {"times", {'1', 'O'}}, {"leftarrow", {'L', 'W'}},
108 {"rightarrow", {'R', 'W'}}, {"leftrightarrow", {'B', 'W'}},
109 {"langle", {'B', 'S'}}, {"rangle", {'E', 'S'}},
110 {"hbar", {'H', 'K'}}, {"lambdabar", {'L', 'K'}}};
111
113 : Drawer(params), font_(toUpper(steer<std::string>("font"))), filling_(steer<bool>("filling")) {}
114
115 const TopdrawerDrawer& TopdrawerDrawer::draw(const Graph1D& graph, const Mode& mode) const {
116 Piper::Commands cmds;
117 cmds += preDraw(graph, mode);
118 cmds += plot(graph);
119 cmds += stringify("TITLE TOP", graph.title());
120 cmds += postDraw(graph, mode);
121 execute(cmds, graph.name());
122 return *this;
123 }
124
125 const TopdrawerDrawer& TopdrawerDrawer::draw(const Graph2D& graph, const Mode& mode) const {
126 Piper::Commands cmds;
127 cmds += preDraw(graph, mode);
128 cmds += plot(graph, mode);
129 cmds += stringify("TITLE TOP", graph.title());
130 cmds += postDraw(graph, mode);
131 execute(cmds, graph.name());
132 return *this;
133 }
134
135 const TopdrawerDrawer& TopdrawerDrawer::draw(const Hist1D& hist, const Mode& mode) const {
136 Piper::Commands cmds;
137 cmds += preDraw(hist, mode);
138 cmds += plot(hist);
139 cmds += stringify("TITLE TOP", hist.title());
140 cmds += postDraw(hist, mode);
141 execute(cmds, hist.name());
142 return *this;
143 }
144
145 const TopdrawerDrawer& TopdrawerDrawer::draw(const Hist2D& hist, const Mode& mode) const {
146 Piper::Commands cmds;
147 cmds += preDraw(hist, mode);
148 cmds += plot(hist, mode);
149 cmds += stringify("TITLE TOP", hist.title());
150 cmds += postDraw(hist, mode);
151 execute(cmds, hist.name());
152 return *this;
153 }
154
156 const std::string& name,
157 const std::string& title,
158 const Mode& mode) const {
159 std::vector<std::string> line_styles = {
160 "SOLID", "DOTS", "DASHES", "DAASHES", "DOTDASH", "SPACE", "PATTERNED", "FUNNY", "PERMANENT"};
161 size_t plot_id = 0;
162 Piper::Commands cmds;
163 const Drawable* first{nullptr};
164 Piper::Commands cmds_plots;
165 for (const auto* obj : objs) {
166 auto line_style = plot_id % line_styles.size();
167 if (obj->isGraph1D()) {
168 const auto* gr = dynamic_cast<const Graph1D*>(obj);
169 cmds_plots.emplace_back("SET TEXTURE " + line_styles.at(line_style));
170 cmds_plots += plot(*gr);
171 if (!first)
172 first = gr;
173 } else if (obj->isHist1D()) {
174 const auto* hist = dynamic_cast<const Hist1D*>(obj);
175 cmds_plots.emplace_back("SET TEXTURE " + line_styles.at(line_style));
176 cmds_plots += plot(*hist);
177 if (!first)
178 first = hist;
179 } else
180 throw CG_FATAL("TopdrawerDrawer:draw") << "Invalid object type to be plotted in multigraph!";
181 ++plot_id;
182 }
183 cmds += preDraw(*first, mode);
184 cmds += cmds_plots;
185 cmds += postDraw(*first, mode);
186 cmds += stringify("TITLE TOP", title);
187 execute(cmds, name);
188 return *this;
189 }
190
191 Piper::Commands TopdrawerDrawer::plot(const Graph1D& graph) {
192 Piper::Commands cmds;
193 for (const auto& pt : graph.points())
194 cmds += format("%g,%g,%g,%g", pt.first.value, pt.second, pt.first.value_unc, pt.second.uncertainty());
195 cmds += "JOIN";
196 return cmds;
197 }
198
199 Piper::Commands TopdrawerDrawer::plot(const Graph2D& graph, const Mode& mode) {
200 Piper::Commands cmds;
201 auto to_fortran_float = [](double val) -> std::string {
202 return utils::replaceAll(utils::format("%g", val), {{"e", "D"}});
203 };
204 cmds += "READ MESH";
205 std::ostringstream osl;
206 for (const auto& yval : graph.yCoords())
207 osl << " " << to_fortran_float(fabs(yval) < 1.e-14 ? 0. : yval);
208 cmds += "Y" + osl.str();
209 for (const auto& xval : graph.points()) {
210 osl.str("");
211 osl << "X " << to_fortran_float(xval.first.value) << " Z";
212 for (const auto& yval : xval.second)
213 osl << " " << (std::isfinite(yval.second) ? to_fortran_float(yval.second) : "0.");
214 cmds += osl.str();
215 }
216 if (mode & Mode::col)
217 cmds += "JOIN";
218 else if (mode & Mode::cont)
219 cmds += "CONTOUR";
220 else {
221 cmds += "SET THREE OFF";
222 cmds += "PLOT";
223 }
224 return cmds;
225 }
226
227 Piper::Commands TopdrawerDrawer::plot(const Hist1D& hist) {
228 Piper::Commands cmds;
229 for (size_t i = 0; i < hist.nbins(); ++i) {
230 const auto& bin = hist.binRange(i);
231 const auto& val = hist.value(i);
232 cmds += format("%g,%g,%g,%g", bin.x(0.5), val, 0.5 * bin.range(), val.uncertainty());
233 }
234 cmds += "HIST";
235 return cmds;
236 }
237
238 Piper::Commands TopdrawerDrawer::plot(const Hist2D& hist, const Mode& mode) {
239 Piper::Commands cmds;
240 cmds += "READ MESH BINS";
241 std::ostringstream osl;
242 std::string sep;
243 for (size_t iy = 0; iy < hist.nbinsY(); ++iy)
244 osl << sep << hist.binRangeY(iy).min(), sep = " ";
245 osl << " " << hist.binRangeY(hist.nbinsY() - 1).max();
246 cmds += "FOR Y=" + osl.str();
247 for (size_t ix = 0; ix < hist.nbinsX(); ++ix) {
248 osl.str("");
249 osl << "X=" << hist.binRangeX(ix).x(0.5) << " Z=";
250 for (size_t iy = 0; iy < hist.nbinsY(); ++iy) {
251 osl << " " << hist.value(ix, iy);
252 }
253 cmds += osl.str();
254 }
255 if (mode & Mode::col)
256 cmds += "JOIN";
257 else if (mode & Mode::cont)
258 cmds += "CONTOUR";
259 else {
260 cmds += "SET THREE OFF";
261 cmds += "PLOT";
262 }
263 return cmds;
264 }
265
266 Piper::Commands TopdrawerDrawer::preDraw(const Drawable& dr, const Mode& mode) const {
267 Piper::Commands cmds;
268 cmds += "SET DEVICE POSTSCR ORIENTATION 3";
269 cmds += "SET FONT " + font_;
270 if (filling_)
271 cmds += "SET FILL FULL";
272 if (mode & Mode::grid)
273 cmds += "SET GRID ON WIDTH=1 DOTS";
274 if (mode & Mode::logx)
275 cmds += "SET SCALE X LOG";
276 if (mode & Mode::logy)
277 cmds += "SET SCALE Y LOG";
278 if (mode & Mode::logz)
279 cmds += "SET SCALE Z LOG";
280 const auto& xrng = dr.xAxis().range();
281 if (xrng.valid())
282 cmds += format("SET LIMITS X %g TO %g", xrng.min(), xrng.max());
283 const auto& yrng = dr.yAxis().range();
284 if (yrng.valid())
285 cmds += format("SET LIMITS Y %g TO %g", yrng.min(), yrng.max());
286 const auto& zrng = dr.zAxis().range();
287 if (zrng.valid())
288 cmds += format("SET LIMITS Z %g TO %g", zrng.min(), zrng.max());
289 return cmds;
290 }
291
292 Piper::Commands TopdrawerDrawer::postDraw(const Drawable& dr, const Mode&) {
293 Piper::Commands cmds;
294 cmds += stringify("TITLE BOTTOM", dr.xAxis().label());
295 cmds += stringify("TITLE LEFT", dr.yAxis().label());
296 cmds += stringify("TITLE CENTER 10.8 9.25", "CepGen v" + version::tag);
297 return cmds;
298 }
299
300 void TopdrawerDrawer::execute(const Piper::Commands& cmds, const std::string& name) {
301 Piper("TOPDRAWER_OUTPUT=" + name + ".ps " + TD).execute(cmds).execute({"EXIT"});
302 CG_DEBUG("TopdrawerDrawer:execute") << "Topdrawer just plotted:\n" << cmds;
303 }
304
305 Piper::Commands TopdrawerDrawer::stringify(const std::string& label, const std::string& str) {
306 bool in_math{false}, in_bs{false}, in_sub{false}, in_sup{false};
307 std::map<int, std::string> m_spec_char, m_sub_char;
308 std::string lab;
309 auto str_parsed = utils::parseSpecialChars(str);
310 for (size_t i = 0; i < str_parsed.size(); ++i) {
311 const auto ch = str_parsed[i];
312 if (ch == '$' && (i == 0 || str_parsed[i - 1] != '\\')) {
313 in_math = !in_math;
314 continue;
315 }
316 // check if we are in superscript/subscript mode
317 if (ch == '_') {
318 in_sub = true;
319 m_sub_char[lab.size()] = "";
320 continue;
321 }
322 if (ch == '^') {
323 in_sup = true;
324 m_sub_char[lab.size()] = "";
325 continue;
326 }
327 if (in_sub || in_sup) {
328 if (ch == '{') {
329 lab.push_back(in_sup ? '0' : '2');
330 continue;
331 }
332 if (ch == '}') {
333 lab.push_back(in_sup ? '1' : '3');
334 if (in_sub)
335 in_sub = false;
336 if (in_sup)
337 in_sup = false;
338 continue;
339 }
340 m_sub_char.rbegin()->second.push_back(ch);
341 lab.push_back(ch);
342 continue;
343 }
344 // check if we have a special character
345 if (ch == '\\') {
346 in_bs = true;
347 m_spec_char[lab.size()] = "";
348 lab.push_back('*');
349 continue;
350 }
351 if (in_bs) {
352 if (ch == ' ' || ch == '_' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' ||
353 ch == ']')
354 in_bs = false;
355 else if (ch == '\\') {
356 m_spec_char[lab.size()] = "";
357 lab.push_back('*');
358 continue;
359 } else {
360 m_spec_char.rbegin()->second.push_back(ch);
361 continue;
362 }
363 }
364 // otherwise assume we are just pushing into the characters buffer
365 lab.push_back(ch);
366 }
367 std::string mod(lab.size(), ' ');
368 for (const auto& ch : m_spec_char) {
369 if (kSpecChars.count(ch.second) == 0) {
370 CG_WARNING("TopdrawerDrawer:stringify")
371 << "Special character '" << ch.second << "' is not defined. Please either define it or use another one.";
372 continue;
373 }
374 const auto& tok = kSpecChars.at(ch.second);
375 lab[ch.first] = tok.first;
376 mod[ch.first] = tok.second;
377 }
378 for (const auto& ch : m_sub_char) {
379 mod[ch.first] = 'C';
380 mod[ch.first + ch.second.size() + 1] = 'C';
381 }
382 Piper::Commands out;
383 out += label + " '" + lab + "'";
384 out += "CASE" + std::string(label.size() - 4, ' ') + " '" + mod + "'";
385 return out;
386 }
387
389 auto desc = Drawer::description();
390 desc.setDescription("Topdrawer plotter");
391 desc.add<std::string>("font", "duplex").setDescription("Topdrawer font to use");
392 desc.add<bool>("filling", true).setDescription("allow to fill the whole available space?");
393 return desc;
394 }
395 } // namespace utils
396} // namespace cepgen
#define REGISTER_DRAWER(name, obj)
Add a drawing utilitary.
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_WARNING(mod)
Definition Message.h:228
#define CG_DEBUG(mod)
Definition Message.h:220
cepgen::utils::TopdrawerDrawer TopdrawerDrawer
const std::string & name() const
Module unique indexing name.
Definition NamedModule.h:42
A description object for parameters collection.
static ParametersDescription description()
Description of all object parameters.
Definition Steerable.cpp:42
A generic object which can be drawn in the standard output.
Definition Drawable.h:31
const std::string & name() const
Drawable name.
Definition Drawable.h:37
const std::string & title() const
Drawable name.
Definition Drawable.h:42
A generic drawing utility.
Definition Drawer.h:36
A one-dimensional graph object.
Definition Graph.h:29
A two-dimensional graph object.
Definition Graph.h:58
1D histogram container
Definition Histogram.h:72
2D histogram container
Definition Histogram.h:146
const TopdrawerDrawer & draw(const Graph1D &, const Mode &) const override
Draw a one-dimensional graph.
static ParametersDescription description()
TopdrawerDrawer(const ParametersList &)
std::string format(const std::string &fmt, Args... args)
Format a string using a printf style format descriptor.
Definition String.h:61
std::string parseSpecialChars(const std::string &str)
Transform all emoji-like special characters into their LaTeX representation.
Definition String.cpp:90
std::vector< const Drawable * > DrawableColl
A collection of drawable objects.
Definition Drawer.h:34
std::string toUpper(const std::string &str)
Capitalise a string.
Definition String.cpp:297
size_t replaceAll(std::string &str, const std::string &from, const std::string &to)
Replace all occurrences of a text by another.
Definition String.cpp:118
Common namespace for this Monte Carlo generator.
A collection of commands to pipe to the session.
Definition Piper.h:36
static const std::string tag
CepGen version.
Definition Version.h:28