a Code for the Combination of Indirect and Direct Constraints on High Energy Physics Models Logo
SlhaValuePlotter.cpp
Go to the documentation of this file.
1/*
2 * SlhaValuePlotter.cpp
3 *
4 * Created on: Mar 22, 2015
5 * Author: Ben O'Leary (benjamin.oleary@gmail.com)
6 * Copyright 2015 Ben O'Leary
7 *
8 * This file is part of LesHouchesParserClasses, released under the
9 * GNU General Public License. Please see the accompanying
10 * README.LHPC_CPP.txt file for a full list of files, brief documentation
11 * on how to use these classes, and further details on the license.
12 */
13
14#include "../../include/SSP/SlhaValuePlotter.hpp"
15
16namespace LHPC
17{
18 namespace SLHA
19 {
20 std::string const
21 SlhaValuePlotter::gnuplotDataFileName( "LHPC_SlhaPlotter_gnuplot.dat" );
23 "LHPC_SlhaPlotter_gnuplot.input" );
24 std::string const
25 SlhaValuePlotter::gnuplotTexBaseName( "LHPC_SlhaPlotter_gnuplot_TeX" );
26 std::string const
27 SlhaValuePlotter::fullLatexBaseName( "LHPC_SlhaPlotter_LaTeX" );
30 double const SlhaValuePlotter::flatBitWidth( 100.0 );
31
33
34 SlhaValuePlotter::SlhaValuePlotter(std::string const& xmlInputFilename) :
35 generalControlsXml( "" ),
36 columnDefinitionsXml( "" ),
37 marginWidth( 10.0 ),
38 joinerWidth( 15.0 ),
39 columnPairOffset( 10.0 ),
40 useAbsoluteValues( false ),
41 verticalAxisLabel( "" ),
42 verticalAxisScaling( -1.0 ),
43 verticalAxisUpperRange( -1.0 ),
44 labelHeightFractionOfRange( -1.0 ),
45 horizontalAxisLabel( "" ),
46 labelWidth( -1.0 ),
47 gnuplotCommand( "" ),
48 latexCommand( "" ),
49 dvipsCommand( "" ),
50 ps2epsCommand( "" ),
51 deleteCommand( "" ),
52 moveCommand( "" ),
53 columnSet(),
54 labelHeight( -1.0 ),
55 labelShuffleDistance( -1.0 ),
56 fullColumnWidth( -1.0 ),
57 lineColoringPointers()
58 {
59 BOL::AsciiXmlParser xmlParser;
60 if( xmlParser.openRootElementOfFile( xmlInputFilename ) )
61 {
62 while( xmlParser.readNextElement() )
63 {
64 if( xmlParser.currentElementNameMatches( "GeneralControls" ) )
65 {
66 generalControlsXml.assign(
68 }
69 else if( xmlParser.currentElementNameMatches( "ColumnDefinitions" ) )
70 {
73 }
74 }
75 xmlParser.closeFile();
76 }
77 else
78 {
79 throw std::runtime_error( "Could not open "
80 + xmlInputFilename
81 + " as valid XML file." );
82 }
83 }
84
86 {
87 for( size_t deletionIndex( 0 );
88 deletionIndex < lineColoringPointers.size();
89 ++deletionIndex )
90 {
91 delete lineColoringPointers[ deletionIndex ];
92 }
93 }
94
95
96 // This parses the label settings and commands from generalControlsXml.
98 {
99 BOL::AsciiXmlParser xmlParser;
100 if( xmlParser.loadString( generalControlsXml ) )
101 {
102 while( xmlParser.readNextElement() )
103 {
104 if( xmlParser.currentElementNameMatches( "UseAbsoluteValues" ) )
105 {
106 std::string
107 inputXml( xmlParser.getTrimmedCurrentElementContent() );
109 useAbsoluteValues = ( inputXml.compare( "true" ) == 0 );
110 }
111 else if( xmlParser.currentElementNameMatches( "VerticalAxisLabel" ) )
112 {
113 verticalAxisLabel.assign(
115 }
116 else if( xmlParser.currentElementNameMatches(
117 "VerticalAxisScaling" ) )
118 {
122 }
123 else if( xmlParser.currentElementNameMatches(
124 "VerticalAxisUpperRange" ) )
125 {
129 }
130 else if( xmlParser.currentElementNameMatches( "LabelHeight" ) )
131 {
135 }
136 else if( xmlParser.currentElementNameMatches(
137 "HorizontalAxisLabel" ) )
138 {
139 horizontalAxisLabel.assign(
141 }
142 else if( xmlParser.currentElementNameMatches( "LabelWidth" ) )
143 {
147 }
148 else if( xmlParser.currentElementNameMatches( "GnuplotExecutable" ) )
149 {
150 gnuplotCommand.assign(
152 }
153 else if( xmlParser.currentElementNameMatches( "LatexExecutable" ) )
154 {
155 latexCommand.assign( xmlParser.getTrimmedCurrentElementContent() );
156 }
157 else if( xmlParser.currentElementNameMatches( "DvipsExecutable" ) )
158 {
159 dvipsCommand.assign( xmlParser.getTrimmedCurrentElementContent() );
160 }
161 else if( xmlParser.currentElementNameMatches( "Ps2epsExecutable" ) )
162 {
163 ps2epsCommand.assign(
165 }
166 else if( xmlParser.currentElementNameMatches( "RemoveCommand" ) )
167 {
168 deleteCommand.assign(
170 }
171 else if( xmlParser.currentElementNameMatches( "MoveCommand" ) )
172 {
173 moveCommand.assign( xmlParser.getTrimmedCurrentElementContent() );
174 }
175 else if( xmlParser.currentElementNameMatches( "MarginWidth" ) )
176 {
179 }
180 else if( xmlParser.currentElementNameMatches( "JoinerWidth" ) )
181 {
184 }
185 else if( xmlParser.currentElementNameMatches( "ColumnPairOffset" ) )
186 {
189 }
190 }
191 gnuplotCommand.append( " " );
193 // "gnuplot LHPC_SlhaPlotter_gnuplot.input"
194 latexCommand.append( " " );
196 latexCommand.append( ".tex" );
197 // "latex LHPC_SlhaPlotter_LaTeX.tex"
198 dvipsCommand.append( " " );
200 dvipsCommand.append( ".dvi" );
201 // "dvips LHPC_SlhaPlotter_LaTeX.dvi"
202 if( 0 == ps2epsCommand.compare( ( ps2epsCommand.size() - 7 ),
203 7,
204 "ps2epsi" ) )
205 {
206 ps2epsCommand.append( " " );
208 ps2epsCommand.append( ".ps" );
209 ps2epsCommand.append( " " );
211 ps2epsCommand.append( ".eps" );
212 }
213 else
214 {
215 ps2epsCommand.append( " -f " );
217 ps2epsCommand.append( ".ps" );
218 }
219 // "ps2eps - f LHPC_SlhaPlotter_LaTeX.ps" or
220 // "ps2epsi LHPC_SlhaPlotter_LaTeX.ps LHPC_SlhaPlotter_LaTeX.eps"
221 deleteCommand.append( " " );
223 deleteCommand.append( " " );
225 deleteCommand.append( " " );
227 deleteCommand.append( ".eps " );
229 deleteCommand.append( ".tex " );
231 deleteCommand.append( ".aux " );
233 deleteCommand.append( ".dvi " );
235 deleteCommand.append( ".log " );
237 deleteCommand.append( ".ps " );
239 deleteCommand.append( ".tex" );
240 /* "rm LHPC_SpectrumPlotter_gnuplot.dat \
241 * LHPC_SlhaPlotter_gnuplot.input \
242 * LHPC_SlhaPlotter_gnuplot_TeX.eps \
243 * LHPC_SlhaPlotter_gnuplot_TeX.tex \
244 * LHPC_SlhaPlotter_LaTeX.aux \
245 * LHPC_SlhaPlotter_LaTeX.dvi \
246 * LHPC_SlhaPlotter_LaTeX.log \
247 * LHPC_SlhaPlotter_LaTeX.ps \
248 * LHPC_SlhaPlotter_LaTeX.tex"
249 */
250 moveCommand.append( " " );
252 moveCommand.append( ".eps" );
253 moveCommand.append( " " );
254
260 + labelWidth );
261 }
262 else
263 {
264 throw std::runtime_error( "Could not parse <SpecificInput>." );
265 }
266 }
267
268 // This sets up the maximum vertical range, and takes care of labels for
269 // lines which would be above the upper limit.
270 void SlhaValuePlotter::setUpVerticalRange( double const largestValueFound )
271 {
272 // If the maximum range is to be automatically calculated, the value for
273 // verticalAxisUpperRange was given as zero or a negative number.
274 if( verticalAxisUpperRange <= 0.0 )
275 {
276 verticalAxisUpperRange = ( largestValueFound * automaticScaleFactor );
277 }
278 else
279 {
280 for( std::vector< std::list< SlhaValuePlotLine > >::iterator
281 whichColumn( columnSet.begin() );
282 whichColumn < columnSet.end();
283 ++whichColumn )
284 {
285 for( std::list< SlhaValuePlotLine >::iterator
286 whichLine( whichColumn->begin() );
287 whichLine != whichColumn->end();
288 ++whichLine )
289 {
290 if( whichLine->getValue() > verticalAxisUpperRange )
291 {
292 whichLine->relabelForAboveRange( verticalAxisUpperRange );
293 }
294 }
295 }
296 }
297
298 // Either way, the label height is set as the fraction times the range.
301 }
302
303 // This tries to move all the labels up or down until they are all
304 // separated by ( labelHeightFractionOfRange * verticalAxisUpperRange ).
306 {
307 for( std::vector< std::list< SlhaValuePlotLine > >::iterator
308 whichColumn( columnSet.begin() );
309 whichColumn < columnSet.end();
310 ++whichColumn )
311 {
312 // Each column has 2 sets of labels to float independently, so pointers
313 // to the SlhaValuePlotLine objects which have labels on the left are
314 // sorted into one vector and on the right to another vector, and each
315 // of those vectors is the used to float the labels off each other.
316 std::vector< SlhaValuePlotLine* > leftLabels;
317 std::vector< SlhaValuePlotLine* > rightLabels;
318 for( std::list< SlhaValuePlotLine >::iterator
319 columnLine( whichColumn->begin() );
320 columnLine != whichColumn->end();
321 ++columnLine )
322 {
323 if( columnLine->hasLabelOnLeftOfColumn() )
324 {
325 leftLabels.push_back( &(*columnLine) );
326 }
327 else
328 {
329 rightLabels.push_back( &(*columnLine) );
330 }
331 }
332 floatLabelsFromOneSide( leftLabels );
333 floatLabelsFromOneSide( rightLabels );
334 } // End of loop over columns.
335 }
336
337
338 // This prepares input files for gnuplot to plot the lines.
340 {
341 std::string const
342 gnuplotDataFileName( "LHPC_SlhaPlotter_gnuplot.dat" );
343 std::string const
344 gnuplotCommandFileName( "LHPC_SlhaPlotter_gnuplot.input" );
345 std::string const
346 gnuplotTexBaseName( "LHPC_SlhaPlotter_gnuplot_TeX" );
347
348 std::ofstream gnuplotDataFile( gnuplotDataFileName.c_str() );
349 std::ofstream gnuplotCommandFile( gnuplotCommandFileName.c_str() );
350 if( !( gnuplotDataFile.is_open()
351 &&
352 gnuplotCommandFile.is_open() ) )
353 {
354 throw std::runtime_error( "Could not open "
356 + " and "
358 + " as temporary files!" );
359 }
360
361 gnuplotCommandFile
362 << "set term epslatex color solid"
363 << std::endl << "set output \"" << gnuplotTexBaseName << ".eps\""
364 << std::endl << "set format x \"\""
365 << std::endl << "set xlabel \"" << horizontalAxisLabel << "\""
366 << std::endl << "set ylabel \"" << verticalAxisLabel << "\""
367 << std::endl << "unset xtics"
368 << std::endl << "set ytics out"
369 << std::endl;
370
371 int gnuplotLineIndex( 0 );
372
373 for( int columnIndex( columnSet.size() - 1);
374 columnIndex >= 0;
375 --columnIndex )
376 {
377 for( std::list< SlhaValuePlotLine >::iterator
378 columnLine( columnSet[ columnIndex ].begin() );
379 columnLine != columnSet[ columnIndex ].end();
380 ++columnLine )
381 {
382 columnLine->writeLineData( gnuplotLineIndex,
383 gnuplotDataFile,
384 gnuplotCommandFile );
385 columnLine->writeLabel( gnuplotCommandFile );
386 }
387 }
388
389 gnuplotDataFile.close();
390
391 // Finally the plot command is constructed.
392 gnuplotCommandFile
393 << "plot [0:"
394 << ( ( columnSet.size() * fullColumnWidth ) + 2.0 * marginWidth )
395 << "] [0:" << verticalAxisUpperRange << "] '" << gnuplotDataFileName
396 << "' index 0 notitle with lines ls 1";
397 for( int lineIndex( 1 );
398 lineIndex < gnuplotLineIndex;
399 ++lineIndex )
400 {
401 gnuplotCommandFile
402 << ", '" << gnuplotDataFileName
403 << "' index " << lineIndex
404 << " notitle with lines ls " << ( lineIndex + 1 );
405 }
406 gnuplotCommandFile << std::endl;
407 gnuplotCommandFile.close();
408
409 std::ofstream latexFile( ( fullLatexBaseName + ".tex" ).c_str() );
410 if( !(latexFile.is_open()) )
411 {
412 throw std::runtime_error( "Could not open "
414 + ".tex as a temporary file!" );
415 }
416 latexFile
417 << "\\documentclass{article}" << std::endl
418 << "\\usepackage{graphics}" << std::endl
419 << "\\newlength\\labelmover" << std::endl
420 << "\\begin{document}" << std::endl
421 << "\\pagestyle{empty}" << std::endl
422 << "\\begin{center}" << std::endl
423 << "\\input{./" << gnuplotTexBaseName << ".tex}" << std::endl
424 << "\\end{center}" << std::endl
425 << "\\end{document}" << std::endl;
426 latexFile.close();
427 }
428
429 // This executes the commands to run gnuplot etc. on the prepared input
430 // files.
431 void SlhaValuePlotter::executeCommands( std::string plotFilename,
432 bool const shouldCleanUp )
433 {
434 int systemReturn( 0 );
435 systemReturn = system( gnuplotCommand.c_str() );
436 // "gnuplot LHPC_SpectrumPlotter_gnuplot.input"
437 systemReturn = system( latexCommand.c_str() );
438 // "latex LHPC_SpectrumPlotter_LaTeX.tex"
439 systemReturn = system( dvipsCommand.c_str() );
440 // "dvips LHPC_SpectrumPlotter_LaTeX.dvi"
441 systemReturn = system( ps2epsCommand.c_str() );
442 // "ps2eps LHPC_SpectrumPlotter_LaTeX.ps"
443 if( shouldCleanUp )
444 {
445 systemReturn = system( deleteCommand.c_str() );
446 /* "rm LHPC_SpectrumPlotter_gnuplot.dat \
447 * LHPC_SpectrumPlotter_gnuplot.input \
448 * LHPC_SpectrumPlotter_gnuplot_TeX.eps \
449 * LHPC_SpectrumPlotter_gnuplot_TeX.tex \
450 * LHPC_SpectrumPlotter_LaTeX.aux \
451 * LHPC_SpectrumPlotter_LaTeX.dvi \
452 * LHPC_SpectrumPlotter_LaTeX.log \
453 * LHPC_SpectrumPlotter_LaTeX.ps \
454 * LHPC_SpectrumPlotter_LaTeX.tex"
455 */
456 }
457 systemReturn = system( (moveCommand + plotFilename).c_str() );
458 // "mv LHPC_SpectrumPlotter_LaTeX.eps plotFileName"
459
460 if( systemReturn == -1 )
461 {
462 std::cout
463 << std::endl
464 << "Call to \"system\" returned -1. No idea what to do with that.";
465 std::cout << std::endl;
466
467 }
468 }
469
470 // This adds a new column to columnSet based on the given definition.
471 void
472 SlhaValuePlotter::addNewColumn( std::string columnDefinitionXml,
474 {
475 BOL::AsciiXmlParser xmlParser;
476 if( xmlParser.loadString( columnDefinitionXml ) )
477 {
478 columnSet.push_back( std::list< SlhaValuePlotLine >() );
479 while( xmlParser.readNextElement() )
480 {
481 if( xmlParser.currentElementNameMatches( "ColumnLine" ) )
482 {
484 slhaParser);
485 }
486 }
487 }
488 else
489 {
490 throw std::runtime_error( "Could not parse <ColumnDefinition>." );
491 }
492 }
493
494 // This adds a new column line to the last column in columnSet based on the
495 // given definition.
496 void
497 SlhaValuePlotter::addColumnLine( std::string lineDefinitionXml,
499 {
500 double slhaValue( 0.0 );
501 std::string labelString( "" );
502 bool labelLeftOfColumn( true );
503 SlhaValueLineColoring const* lineColoring( NULL );
504
505 BOL::AsciiXmlParser xmlParser;
506 if( xmlParser.loadString( lineDefinitionXml ) )
507 {
508 while( xmlParser.readNextElement() )
509 {
510 if( xmlParser.currentElementNameMatches( "SlhaValue" ) )
511 {
512 slhaValue = slhaParser.getDouble(
515 &&
516 ( slhaValue < 0.0 ) )
517 {
518 slhaValue = -slhaValue;
519 }
520 slhaValue *= verticalAxisScaling;
521 }
522 else if( xmlParser.currentElementNameMatches( "LabelLatex" ) )
523 {
524 labelString = xmlParser.getTrimmedCurrentElementContent();
525 }
526 else if( xmlParser.currentElementNameMatches( "LabelSide" ) )
527 {
528 std::string
529 whichSide( xmlParser.getTrimmedCurrentElementContent() );
531
532 labelLeftOfColumn = ( whichSide.compare( "left" ) == 0 );
533 }
534 else if( xmlParser.currentElementNameMatches( "LineColor" ) )
535 {
536 std::map< std::string, std::string > const&
537 lineAttributes( xmlParser.getCurrentElementAttributes() );
538 std::map< std::string, std::string >::const_iterator
539 attributeFinder( lineAttributes.find( "DrawType" ) );
540 if( attributeFinder != lineAttributes.end() )
541 {
542 lineColoring = getNewLineColoring( attributeFinder->second,
544 slhaParser );
545 }
546 else
547 {
548 throw std::runtime_error(
549 "Unknown \"DrawType\" in <LineColor>." );
550 }
551 }
552 }
553 }
554 double const columnCenterPosition( marginWidth
555 + ( ( columnSet.size() - 0.5 )
556 * fullColumnWidth ) );
557 columnSet.back().push_back( SlhaValuePlotLine( slhaValue,
558 columnCenterPosition,
562 labelString,
563 labelLeftOfColumn,
564 lineColoring ) );
565 }
566
567 // This tries to move all the labels up or down until they are all
568 // separated by ( labelHeightFractionOfRange * verticalAxisUpperRange ).
570 std::vector< SlhaValuePlotLine* >& labelSet )
571 {
572 // The labels only need to be checked for overlap if there are at least 2
573 // labels.
574 if( labelSet.size() > 1 )
575 {
576 // At least one iteration of the shuffling loop must be performed so
577 // that at least the labels are checked to be in position.
578 bool notYetFinishedShuffling( true );
579 int remainingShuffles( maximumLabelFloatingShuffles );
580 // Each column is allowed to try floating the labels apart
581 // maximumLabelFloatingShuffles times.
582
583 std::vector< SlhaValuePlotLine* >::iterator
584 lowerLine( labelSet.begin() );
585 std::vector< SlhaValuePlotLine* >::iterator upperLine( lowerLine );
586
587 while( notYetFinishedShuffling
588 &&
589 ( remainingShuffles > 0 ) )
590 {
591 notYetFinishedShuffling = false;
592 // each iteration starts by assuming that it just finds that all
593 // the labels are sufficiently separate, with no floating needed.
594 --remainingShuffles;
595 lowerLine = labelSet.begin();
596 // if the lowest label is too low, it is bumped up to its lowest
597 // allowed position:
598 if( (*lowerLine)->getLabelPosition() < labelHeight )
599 {
600 notYetFinishedShuffling = true;
601 // moving the lowest label means that the column has to be
602 // checked again for overlapping labels.
603 (*lowerLine)->setLabelPosition( labelHeight );
604 }
605 upperLine = lowerLine;
606 ++upperLine;
607 // The lower line iterator is always 1 step behind the upper line
608 // iterator.
609 while( upperLine < labelSet.end() )
610 {
611 if( ( (*upperLine)->getLabelPosition()
612 - (*lowerLine)->getLabelPosition() ) < labelHeight )
613 {
614 // If a pair of overlapping labels is found,
615 // notYetFinishedShuffling is set to true since this iteration
616 // did not merely confirm that the labels are in order and well
617 // separated.
618 notYetFinishedShuffling = true;
619
620 // Now the labels are floated away from each other around their
621 // average position. Since the conditional does not check for
622 // the absolute separation, if labels ever get twisted past
623 // each other, the conditional will find them, and since the
624 // lines are sorted according to their SLHA value rather than
625 // their current label position, the labels get separated in the
626 // right direction.
627 double const
628 labelAverage( 0.5 * ( (*upperLine)->getLabelPosition()
629 + (*lowerLine)->getLabelPosition() ) );
630 (*lowerLine)->setLabelPosition( labelAverage
632 (*upperLine)->setLabelPosition( labelAverage
634 }
635 ++lowerLine;
636 ++upperLine;
637 }
638 // Now upperLine is at columnPointer->end(), so lowerLine is at the
639 // highest label, which is ensured to be lower than its allowed
640 // highest value:
641 if( (*lowerLine)->getLabelPosition() > ( verticalAxisUpperRange
642 - labelHeight ) )
643 {
644 // Moving the highest label means that the column has to be
645 // checked again for overlapping labels.
646 notYetFinishedShuffling = true;
647 (*lowerLine)->setLabelPosition( verticalAxisUpperRange
648 - labelHeight );
649 }
650 } // End of loop over shuffles.
651 } // End of if the column had 2 or more labels on the relevant side.
652 }
653
654 } /* namespace SLHA */
655} /* namespace LHPC */
std::map< std::string, std::string > const & getCurrentElementAttributes()
bool loadString(std::string const stringToParse)
bool currentElementNameMatches(std::string const &comparisonString) const
std::string getTrimmedCurrentElementContent() const
bool openRootElementOfFile(std::string const &fileName)
static void transformToLowercase(std::string &stringToTransform)
static double stringToDouble(std::string const &stringToInterpret)
static double const flatBitWidth
void addColumnLine(std::string lineDefinitionXml, LHPC::SlhaSimplisticInterpreter &slhaParser)
static double const labelSeparationShuffleFactor
static std::string const fullLatexBaseName
SlhaValuePlotter(std::string const &xmlInputFilename)
std::vector< SlhaValueLineColoring * > lineColoringPointers
static std::string const gnuplotDataFileName
void executeCommands(std::string plotFilename, bool const shouldCleanUp)
static int const maximumLabelFloatingShuffles
static std::string const gnuplotTexBaseName
static double const automaticScaleFactor
static std::string const gnuplotCommandFileName
SlhaValueLineColoring * getNewLineColoring(std::string const &drawType, std::string const &xmlBody, LHPC::SlhaSimplisticInterpreter &slhaParser)
void addNewColumn(std::string columnDefinitionXml, LHPC::SlhaSimplisticInterpreter &slhaParser)
void setUpVerticalRange(double const largestValueFound)
std::vector< std::list< SlhaValuePlotLine > > columnSet
void floatLabelsFromOneSide(std::vector< SlhaValuePlotLine * > &labelSet)
double getDouble(std::string blockNameAndIndices)