a Code for the Combination of Indirect and Direct Constraints on High Energy Physics Models Logo
SpectrumPlotter.cpp
Go to the documentation of this file.
1/*
2 * SpectrumPlotter.cpp
3 *
4 * Created on: Feb 26, 2012
5 * Author: Ben O'Leary (benjamin.oleary@gmail.com)
6 * Copyright 2012 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
15
16namespace LHPC
17{
18 namespace SLHA
19 {
20 int const SpectrumPlotter::unitIndex( 11 );
21 int const SpectrumPlotter::scaleIndex( 12 );
24 int const SpectrumPlotter::gnuplotIndex( 21 );
25 int const SpectrumPlotter::latexIndex( 22 );
26 int const SpectrumPlotter::dvipsIndex( 23 );
27 int const SpectrumPlotter::ps2epsIndex( 24 );
28 int const SpectrumPlotter::rmIndex( 25 );
29 int const SpectrumPlotter::mvIndex( 26 );
31 "LHPC_SpectrumPlotter_gnuplot.dat" );
33 "LHPC_SpectrumPlotter_gnuplot.input" );
34 std::string const
35 SpectrumPlotter::gnuplotTexBaseName( "LHPC_SpectrumPlotter_gnuplot_TeX" );
36 std::string const
37 SpectrumPlotter::fullLatexBaseName( "LHPC_SpectrumPlotter_LaTeX" );
38 double const SpectrumPlotter::automaticScaleFactor( 1.1 );
40 double const SpectrumPlotter::marginWidth( 10.0 );
41 double const SpectrumPlotter::joinerWidth( 15.0 );
42 double const SpectrumPlotter::flatBitWidth( 100.0 - joinerWidth );
43 double const SpectrumPlotter::columnPairOffset( 10.0 );
45
46
48 StringBlock const& linePlottingBlock,
49 FmassBlock const* const fmassPointer,
50 MassBlock const* const massPointer ) :
51 plotControlBlock( plotControlBlock ),
52 linePlottingBlock( linePlottingBlock ),
53 fmassPointer( fmassPointer ),
54 massPointer( massPointer ),
55 unitString( "GeV" ),
56 unitFactor( 1.0 ),
57 scaleMaximum( -1.0 ),
58 largestMass( 0.0 ),
59 columnSet(),
60 columnPointer( NULL ),
61 plotLineMap( NULL ),
62 lineIterator(),
63 lineAdder(),
64 lowerMassIterator(),
65 upperMassIterator(),
66 notYetFinishedShuffling( false ),
67 remainingShuffles( maximumLabelFloatingShuffles ),
68 whichMassEigenstate( 0 ),
69 massValue( 0.0 ),
70 labelRoomWidth( 30.0 ),
71 labelLatexWidth( labelRoomWidth ),
72 fullColumnWidth( labelRoomWidth + joinerWidth
73 + flatBitWidth + columnPairOffset
74 + joinerWidth + labelRoomWidth ),
75 labelSeparation( 0.05 ),
76 labelAverage( 0.0 ),
77 lastOperationSuccessful( false ),
78 systemCallReturn( -1 ),
79 fullLatexFilename( fullLatexBaseName ),
80 gnuplotCommand( "" ),
81 latexCommand( "" ),
82 dvipsCommand( "" ),
83 ps2epsCommand( "" ),
84 epsiInstead( false ),
85 mainCleanupCommand( "" ),
86 moveCommand( "" ),
87 leftColumnRatherThanRight( false ),
88 leftLineXValue( 0.0 ),
89 middleLineXValue( 0.0 ),
90 rightLineXValue( 0.0 ),
91 gnuplotLineIndex( 0 ),
92 gnuplotLabelString( "" )
93 {
94 fullLatexFilename.append( ".tex" );
95 }
96
98 {
99 // does nothing.
100 }
101
102
103 bool
104 SpectrumPlotter::plotSpectrum( std::string const& plotFileName,
105 bool const shouldCleanUp )
106 {
107 loadCommands( plotFileName );
108 loadLines();
109 sortMasses();
110 floatLabels();
113 {
114 systemCallReturn = system( gnuplotCommand.c_str() );
115 // "gnuplot LHPC_SpectrumPlotter_gnuplot.input"
116 }
117 if( -1 != systemCallReturn )
118 {
119 systemCallReturn = system( latexCommand.c_str() );
120 // "latex LHPC_SpectrumPlotter_LaTeX.tex"
121 }
122 if( -1 != systemCallReturn )
123 {
124 systemCallReturn = system( dvipsCommand.c_str() );
125 // "dvips LHPC_SpectrumPlotter_LaTeX.dvi"
126 }
127 if( -1 != systemCallReturn )
128 {
129 systemCallReturn = system( ps2epsCommand.c_str() );
130 // "ps2eps LHPC_SpectrumPlotter_LaTeX.ps"
131 }
132 if( ( -1 != systemCallReturn )
133 &&
134 shouldCleanUp )
135 {
136 systemCallReturn = system( mainCleanupCommand.c_str() );
137 /* "rm LHPC_SpectrumPlotter_gnuplot.dat \
138 * LHPC_SpectrumPlotter_gnuplot.input \
139 * LHPC_SpectrumPlotter_gnuplot_TeX.eps \
140 * LHPC_SpectrumPlotter_gnuplot_TeX.tex \
141 * LHPC_SpectrumPlotter_LaTeX.aux \
142 * LHPC_SpectrumPlotter_LaTeX.dvi \
143 * LHPC_SpectrumPlotter_LaTeX.log \
144 * LHPC_SpectrumPlotter_LaTeX.ps \
145 * LHPC_SpectrumPlotter_LaTeX.tex"
146 */
147 }
148 if( -1 != systemCallReturn )
149 {
150 systemCallReturn = system( moveCommand.c_str() );
151 // "mv LHPC_SpectrumPlotter_LaTeX.eps plotFileName"
152 }
153 if( -1 != systemCallReturn )
154 {
155 return true;
156 }
157 else
158 {
159 return false;
160 }
161 }
162
163 void
164 SpectrumPlotter::loadCommands( std::string const& plotFileName )
165 {
166 // 1st the defaults are loaded:
167 unitFactor = 1.0;
168 scaleMaximum = -1.0;
169 labelSeparation = 0.05;
170 labelRoomWidth = 30.0;
171 gnuplotCommand.assign( "/usr/bin/gnuplot" );
172 latexCommand.assign( "/usr/bin/latex" );
173 dvipsCommand.assign( "/usr/bin/dvips" );
174 ps2epsCommand.assign( "/usr/bin/ps2eps" );
175 mainCleanupCommand.assign( "/bin/rm" );
176 moveCommand.assign( "/bin/mv" );
177 // then, if there is a control block, it is used to overwrite defaults:
179 {
180 if( plotControlBlock[ 0 ].hasEntry( unitIndex ) )
181 {
184 if( 0 == unitString.compare( "GEV" ) )
185 {
186 unitFactor = 1.0;
187 }
188 else if( 0 == unitString.compare( "TEV" ) )
189 {
190 unitFactor = 0.001;
191 }
192 else if( 0 == unitString.compare( "MEV" ) )
193 {
194 unitFactor = 1000.0;
195 }
196 else if( 0 == unitString.compare( "KEV" ) )
197 {
198 unitFactor = 1000000.0;
199 }
200 else if( 0 == unitString.compare( "EV" ) )
201 {
202 unitFactor = 1000000000.0;
203 }
204 else
205 {
206 unitFactor = 1.0;
207 std::cout
208 << std::endl
209 << "LHPC::warning! SpectrumPlotter did not understand \""
210 << plotControlBlock( unitIndex ) << "\" as a unit (acceptable"
211 << " units are \"GeV\", \"TeV\", \"MeV\", \"keV\", and \"eV\"),"
212 << " and is defaulting to GeV.";
213 std::cout << std::endl;
214 }
215 }
216 if( plotControlBlock[ 0 ].hasEntry( scaleIndex ) )
217 {
220 }
221 if( plotControlBlock[ 0 ].hasEntry( labelYSizeIndex ) )
222 {
225 labelYSizeIndex ) ) );
226 // the label separation is given as a percentage of the scale range
227 // in the control block.
228 }
229 if( plotControlBlock[ 0 ].hasEntry( labelXSizeIndex ) )
230 {
233 // the label separation is given as a percentage of the plot line
234 // width in the control block.
235 }
236 if( plotControlBlock[ 0 ].hasEntry( gnuplotIndex ) )
237 {
239 }
240 if( plotControlBlock[ 0 ].hasEntry( latexIndex ) )
241 {
243 }
244 if( plotControlBlock[ 0 ].hasEntry( dvipsIndex ) )
245 {
247 }
248 if( plotControlBlock[ 0 ].hasEntry( ps2epsIndex ) )
249 {
251 }
252 if( plotControlBlock[ 0 ].hasEntry( rmIndex ) )
253 {
255 }
256 if( plotControlBlock[ 0 ].hasEntry( mvIndex ) )
257 {
259 }
260 }
261 // finally, stuff derived from the control block or defaults is set:
265 gnuplotCommand.append( " " );
267 // "gnuplot LHPC_SpectrumPlotter_gnuplot.input"
268 latexCommand.append( " " );
270 latexCommand.append( ".tex" );
271 // "latex LHPC_SpectrumPlotter_LaTeX.tex"
272 dvipsCommand.append( " " );
274 dvipsCommand.append( ".dvi" );
275 // "dvips LHPC_SpectrumPlotter_LaTeX.dvi"
276 if( 0 == ps2epsCommand.compare( ( ps2epsCommand.size() - 7 ),
277 7,
278 "ps2epsi" ) )
279 {
280 epsiInstead = true;
281 ps2epsCommand.append( " " );
282 }
283 else
284 {
285 ps2epsCommand.append( " -f " );
286 }
288 ps2epsCommand.append( ".ps" );
289 if( epsiInstead )
290 {
291 ps2epsCommand.append( " " );
293 ps2epsCommand.append( ".eps" );
294 }
295 // "ps2eps - f LHPC_SpectrumPlotter_LaTeX.ps" or
296 // "ps2epsi LHPC_SpectrumPlotter_LaTeX.ps LHPC_SpectrumPlotter_LaTeX.eps"
297 mainCleanupCommand.append( " " );
299 mainCleanupCommand.append( " " );
301 mainCleanupCommand.append( " " );
303 mainCleanupCommand.append( ".eps " );
305 mainCleanupCommand.append( ".tex " );
307 mainCleanupCommand.append( ".aux " );
309 mainCleanupCommand.append( ".dvi " );
311 mainCleanupCommand.append( ".log " );
313 mainCleanupCommand.append( ".ps " );
315 mainCleanupCommand.append( ".tex" );
316 /* "rm LHPC_SpectrumPlotter_gnuplot.dat \
317 * LHPC_SpectrumPlotter_gnuplot.input \
318 * LHPC_SpectrumPlotter_gnuplot_TeX.eps \
319 * LHPC_SpectrumPlotter_gnuplot_TeX.tex \
320 * LHPC_SpectrumPlotter_LaTeX.aux \
321 * LHPC_SpectrumPlotter_LaTeX.dvi \
322 * LHPC_SpectrumPlotter_LaTeX.log \
323 * LHPC_SpectrumPlotter_LaTeX.ps \
324 * LHPC_SpectrumPlotter_LaTeX.tex"
325 */
326 moveCommand.append( " " );
328 moveCommand.append( ".eps" );
329 moveCommand.append( " " );
330 moveCommand.append( plotFileName );
331 // "mv LHPC_SpectrumPlotter_LaTeX.eps plotFileName"
332
333 // debugging:
349 }
350
351 void
353 {
355 {
356 plotLineMap = &(linePlottingBlock[ 0 ].getValueMap());
357 lineIterator = plotLineMap->begin();
358 while( plotLineMap->end() != lineIterator )
359 // for each mass eigenstate specified to be plotted...
360 {
363
364 // whether there is a mass for the line needs to be checked (FMASS is
365 // checked for before MASS):
366 if( ( NULL != fmassPointer )
367 &&
369 &&
370 ( (*fmassPointer)[ 0 ].hasEntry( whichMassEigenstate ) ) )
371 {
373 = ( unitFactor
374 * (*fmassPointer)( whichMassEigenstate ).getValue() );
376 }
377 else if( ( NULL != massPointer )
378 &&
380 &&
381 ( (*massPointer)[ 0 ].hasEntry( whichMassEigenstate ) ) )
382 {
383 massValue = ( unitFactor * (*massPointer)( whichMassEigenstate ) );
385 }
386
388 // if there was a mass recorded for this mass eigenstate...
389 {
391 massValue );
392 if( lineAdder.getColumn() >= columnSet.getSize() )
393 {
394 columnSet.setSize( lineAdder.getColumn() + 1 );
395 }
396 // now columnSet is large enough for the line to be put into its
397 // appropriate column:
398 columnSet[ lineAdder.getColumn() ].push_back( lineAdder );
399 }
400 ++lineIterator;
401 }
402 }
403 }
404
405 void
407 // this sorts all the masses in the columns, & then sets the scale range,
408 // then deals with any labels above the final scaleMaximum.
409 {
410 largestMass = 0.0;
411 for( int whichColumn( columnSet.getLastIndex() );
412 0 < whichColumn;
413 --whichColumn )
414 {
415 columnPointer = columnSet.getPointer( whichColumn );
416 if( !(columnPointer->empty()) )
417 {
419 if( columnPointer->back().getMass() > largestMass )
420 {
421 largestMass = columnPointer->back().getMass();
422 }
423 }
424 }
425 if( 0.0 >= scaleMaximum )
426 // if the scale is to be automatically decided by the largest mass...
427 {
429 }
430 // now that the scale range is known, the separation between labels can
431 // be fixed.
433
434 // now labels above scaleMaximum get the mass appended in brackets, get
435 // moved to just beneath scaleMaximum, & get flagged as center-justified.
436 for( int whichColumn( columnSet.getLastIndex() );
437 0 < whichColumn;
438 --whichColumn )
439 {
440 columnPointer = columnSet.getPointer( whichColumn );
441 for( std::list< SpectrumPlotting::LineData >::iterator
442 lineIterator( columnPointer->begin() );
443 columnPointer->end() != lineIterator;
444 ++lineIterator )
445 {
446 if( lineIterator->getMass() > scaleMaximum )
447 {
448 lineIterator->relabelForOverlargeMass( scaleMaximum );
449 }
450 }
451 }
452 }
453
454 void
456 // this tries to move all the labels up or down until they are all
457 // separated by ( labelSeparation * scaleMaximum ).
458 {
459 for( int whichColumn( columnSet.getLastIndex() );
460 0 < whichColumn;
461 --whichColumn )
462 {
463 columnPointer = columnSet.getPointer( whichColumn );
464 if( 1 < columnPointer->size() )
465 // the labels only need to be checked for overlap if there are at
466 // least 2 lines in the column.
467 {
469 // at least one iteration of the shuffling loop must be performed so
470 // that at least the labels are checked to be in position.
472 // each column is allowed to try floating the labels apart
473 // maximumLabelFloatingShuffles times.
475 &&
476 ( 0 < remainingShuffles ) )
477 {
479 // each iteration starts by assuming that it just finds that all
480 // the labels are sufficiently separate, with no floating needed.
483 // if the lowest label is too low, it is bumped up to its lowest
484 // allowed position:
485 if( labelSeparation > lowerMassIterator->getLabelPosition() )
486 {
488 // moving the lowest label means that the column has to be
489 // checked again for overlapping labels.
490 lowerMassIterator->setLabelPosition( labelSeparation );
491 }
494 while( upperMassIterator != columnPointer->end() )
495 // lowerMassIterator is always 1 step behind upperMassIterator.
496 {
497 if( labelSeparation > ( upperMassIterator->getLabelPosition()
498 - lowerMassIterator->getLabelPosition() ) )
499 // if a pair of overlapping labels is found...
500 {
502 /* ... first notYetFinishedShuffling is set to true since this
503 * iteration did not merely confirm that the labels are in
504 * order & well separated. then the labels are floated away
505 * from each other around their average position. since the
506 * conditional does not check for the absolute separation, if
507 * labels ever get twisted past each other, the conditional
508 * will find them, & since the lines are sorted according to
509 * their mass value rather than their current label position,
510 * the labels get separated in the right direction.
511 */
513 = ( 0.5 * ( upperMassIterator->getLabelPosition()
514 + lowerMassIterator->getLabelPosition() ) );
515 lowerMassIterator->setLabelPosition( labelAverage
517 * labelSeparation );
518 upperMassIterator->setLabelPosition( labelAverage
520 * labelSeparation );
521 }
524 }
525 /* now upperMassIterator is at columnPointer->end(), so
526 * lowerMassIterator is at the highest label, which is ensured to
527 * be lower than its highest value:
528 */
530 < lowerMassIterator->getLabelPosition() )
531 {
533 // moving the highest label means that the column has to be
534 // checked again for overlapping labels.
535 lowerMassIterator->setLabelPosition( scaleMaximum
536 - labelSeparation );
537 }
538 } // end of loop over shuffles.
539 } // end of if the column had 2 or more lines.
540 } // end of loop over columns.
541 }
542
543 bool
545 {
546 std::ofstream gnuplotDataFile( gnuplotDataFileName.c_str() );
547 std::ofstream gnuplotCommandFile( gnuplotCommandFileName.c_str() );
548 if( gnuplotDataFile.is_open()
549 &&
550 gnuplotCommandFile.is_open() )
551 {
552 bool returnBool( true );
553 gnuplotCommandFile
554 << "set term epslatex color solid"
555 << std::endl << "set output \"" << gnuplotTexBaseName << ".eps\""
556 << std::endl << "set format x \"\""
557 << std::endl << "unset xtics"
558 << std::endl << "set ytics out"
559 << std::endl;
560
562 for( int whichColumn( columnSet.getLastIndex() );
563 0 < whichColumn;
564 --whichColumn )
565 {
566 columnPointer = columnSet.getPointer( whichColumn );
567 if( 1 == ( whichColumn % 2 ) )
568 // if the column gets its labels to its left...
569 {
571 }
572 else
573 {
575 }
576
578 = ( ( ((double)( ( whichColumn - 1 ) / 2 )) * fullColumnWidth )
581 {
584 }
585 else
586 {
590 }
591
592 for( std::list< SpectrumPlotting::LineData >::iterator
593 lineIterator( columnPointer->begin() );
594 columnPointer->end() != lineIterator;
595 ++lineIterator )
596 {
597 gnuplotLabelString.assign( "{" );
598
599 /* since the labels are centered by gnuplot, left justification is
600 * hacked in by having a phantom to the left, so that the label
601 * is only visible from the right of the center point of the label,
602 * & similar for right justification.
603 */
605 == lineIterator->getJustification() )
606 {
607 gnuplotLabelString.append( "{\\phantom{" );
608 gnuplotLabelString.append( lineIterator->getLabelString() );
609 gnuplotLabelString.append( "}{" );
610 gnuplotLabelString.append( lineIterator->getLabelString() );
611 gnuplotLabelString.append( "}}" );
612 }
614 == lineIterator->getJustification() )
615 {
616 gnuplotLabelString.append( "{" );
617 gnuplotLabelString.append( lineIterator->getLabelString() );
618 gnuplotLabelString.append( "}{\\phantom{" );
619 gnuplotLabelString.append( lineIterator->getLabelString() );
620 gnuplotLabelString.append( "}}" );
621 }
622 else
623 // this case should only be center-justified.
624 {
625 gnuplotLabelString.append( lineIterator->getLabelString() );
626 }
627 gnuplotLabelString.append( "}" );
628
630 {
631 gnuplotDataFile
632 << leftLineXValue << " " << lineIterator->getLabelPosition()
633 << std::endl
634 << middleLineXValue << " " << lineIterator->getMass()
635 << std::endl
636 << rightLineXValue << " " << lineIterator->getMass()
637 << std::endl;
638
639 gnuplotCommandFile
640 << "set label '" << gnuplotLabelString << "' at "
641 << leftLineXValue << ", "
642 << lineIterator->getLabelPosition() << std::endl;
643 }
644 else
645 {
646 gnuplotDataFile
647 << leftLineXValue << " " << lineIterator->getMass()
648 << std::endl
649 << middleLineXValue << " " << lineIterator->getMass()
650 << std::endl
651 << rightLineXValue << " " << lineIterator->getLabelPosition()
652 << std::endl;
653
654 gnuplotCommandFile
655 << "set label '" << gnuplotLabelString << "' at "
656 << rightLineXValue << ", "
657 << lineIterator->getLabelPosition() << std::endl;
658 }
659
660 // gnuplot treats double blank lines as meaning that the data
661 // above has a separate "index":
662 gnuplotDataFile << std::endl << std::endl;
663
664 gnuplotCommandFile
665 << "set style line " << (++gnuplotLineIndex) << " lt rgb \""
666 << lineIterator->getColor() << "\" lw 3"
667 << std::endl;
668 // gnuplotLineIndex is incremented to give each line its own unique
669 // linestyle.
670 } // end of loop over lines within the column.
671 } // end of loop over columns.
672
673 gnuplotDataFile.close();
674
675 // finally construct the plot command:
676 gnuplotCommandFile
677 << "plot [0:"
678 << ( ( (double)( ( columnSet.getLastIndex() / 2 )
679 + ( columnSet.getLastIndex() % 2 ) )
681 + 2.0 * marginWidth )
682 // this should correctly count the number of column pairs, even if the
683 // last pair is only one column.
684 << "] [0:" << scaleMaximum << "] '" << gnuplotDataFileName
685 << "' index 0 notitle with lines ls 1";
686 for( int whichLine( 1 );
687 gnuplotLineIndex > whichLine;
688 ++whichLine )
689 {
690 gnuplotCommandFile
691 << ", '" << gnuplotDataFileName
692 << "' index " << whichLine
693 << " notitle with lines ls " << ( whichLine + 1 );
694 }
695 gnuplotCommandFile << std::endl;
696 gnuplotCommandFile.close();
697
698 std::ofstream fullLatexFile( fullLatexFilename.c_str() );
699 if( fullLatexFile.is_open() )
700 {
701 fullLatexFile
702 << "\\documentclass{article}" << std::endl
703 << "\\usepackage{graphics}" << std::endl
704 << "\\newlength\\labelmover" << std::endl
705 << "\\begin{document}" << std::endl
706 << "\\pagestyle{empty}" << std::endl
707 << "\\begin{center}" << std::endl
708 << "\\input{./" << gnuplotTexBaseName << ".tex}" << std::endl
709 << "\\end{center}" << std::endl
710 << "\\end{document}" << std::endl;
711 fullLatexFile.close();
712 }
713 else
714 {
715 returnBool = false;
716 }
717 return returnBool;
718 }
719 else
720 {
721 return false;
722 }
723 }
724
725 }
726
727}
static double stringToDouble(std::string const &stringToInterpret)
static void transformToUppercase(std::string &stringToTransform)
int getNumberOfCopiesWithDifferentScale() const
Definition: SlhaBlock.hpp:222
static std::string const fullLatexBaseName
LineMap::const_iterator lineIterator
std::list< SpectrumPlotting::LineData >::iterator upperMassIterator
BOL::VectorlikeArray< LineList > columnSet
static std::string const gnuplotCommandFileName
static std::string const gnuplotDataFileName
static int const labelXSizeIndex
MassBlock const *const massPointer
static double const joinerWidth
SpectrumPlotting::LineData lineAdder
static std::string const gnuplotTexBaseName
static double const automaticScaleFactor
static int const labelYSizeIndex
static double const marginWidth
FmassBlock const *const fmassPointer
static int const maximumLabelFloatingShuffles
StringBlock const & plotControlBlock
SpectrumPlotter(StringBlock const &plotControlBlock, StringBlock const &linePlottingBlock, FmassBlock const *const fmassPointer, MassBlock const *const massPointer=NULL)
void loadCommands(std::string const &plotFileName)
StringBlock const & linePlottingBlock
std::list< SpectrumPlotting::LineData >::iterator lowerMassIterator
static double const flatBitWidth
bool plotSpectrum(std::string const &plotFileName, bool const shouldCleanUp=true)
static double const labelSeparationShuffleFactor
static double const columnPairOffset
void setValues(std::string const &dataString, double const massValue)
Definition: LineData.cpp:63
static bool lowToHigh(LineData const &firstLineData, LineData const &secondLineData)
Definition: LineData.hpp:88