7#include "PAHEmissionModel.h" 
   10#define MYSQLPP_SSQLS_NO_STATICS 
   12#include "Parameters.h" 
   13#include "SpectralFitter.h" 
   20  std::set_new_handler(
nullptr);
 
   22  time_t t = std::time(
nullptr);
 
   24  struct tm *tm_s = std::localtime(&t);
 
   28  std::strftime(str_t, 
sizeof(str_t), 
"%Y%m%d-%X - EXCEPTION: ", tm_s);
 
   30  std::cerr << str_t << 
"Memory allocation failed";
 
   42int main(
const int argc, 
const char *argv[], 
char ** ) {
 
   44  std::set_new_handler(new_handler);
 
   50    parameters.parse(argc, argv);
 
   53    std::cerr << e.what() << std::endl;
 
   62    pahdb.connect(parameters.getDatabase(), parameters.getHost(),
 
   63                  parameters.getUsername(), parameters.getPassword(),
 
   64                  parameters.getPort(), parameters.isCompress(),
 
   65                  parameters.getTimeout(), parameters.getSocket());
 
   67    pahdb.setTable(parameters.getTable());
 
   69    pahdb.setProgress(10.0);
 
   72    std::cerr << e.what() << std::endl;
 
   77  std::vector<std::vector<std::pair<double, double>>> transitions;
 
   79  std::vector<std::vector<double>> spectra;
 
   81  std::vector<double> grid;
 
   83  std::vector<double> temperatures;
 
   85  std::tuple<std::vector<double>, std::vector<double>, std::vector<double>>
 
   94    if (parameters.getTool() == Parameters::Arg::CompareExperimentWithTheory) {
 
   96      transitions = pahdb.getExperimentalAndTheoreticalTransitionsFromId(
 
   97          parameters.getIds().at(0));
 
  100      if (parameters.getTool() == Parameters::Arg::SpectralFit) {
 
  102        FileInput fileinput(parameters.getInputFilename());
 
  104        inputdata = fileinput.readFileFromDisk();
 
  106        pahemissionmodel.setGrid(std::get<0>(inputdata));
 
  108        std::array<double, 2> inputlimits;
 
  110        inputlimits[0] = *max_element(std::get<0>(inputdata).begin(),
 
  111                                      std::get<0>(inputdata).end());
 
  113        inputlimits[1] = *min_element(std::get<0>(inputdata).begin(),
 
  114                                      std::get<0>(inputdata).end());
 
  116        if (parameters.getUnits() == Parameters::Arg::Wavelength) {
 
  118          PAHEmissionModel::convertFromFrequencyToWavelength(inputlimits);
 
  121        parameters.setPlotLimits(inputlimits);
 
  123        spectralfitter.setSpectrum(std::get<1>(inputdata));
 
  125        spectralfitter.setUncertainties(std::get<2>(inputdata));
 
  129        pahemissionmodel.makeGrid(parameters.getPlotLimitsAsFrequencies().at(0),
 
  130                                  parameters.getPlotLimitsAsFrequencies().at(1),
 
  134      grid = pahemissionmodel.getGrid();
 
  136      if (parameters.getTool() != Parameters::Arg::TemperatureStack) {
 
  138        pahemissionmodel.setTransitions(
 
  139            pahdb.getTransitionsFromIds(parameters.getIds()));
 
  142        transitions = pahdb.getTransitionsFromId(parameters.getIds().at(0));
 
  144        transitions = std::vector<std::vector<std::pair<double, double>>>(
 
  145            parameters.getTemperaturesInKelvin().size(), transitions.at(0));
 
  147        pahemissionmodel.setTransitions(transitions);
 
  150      if (parameters.getTable() == PAHdb::Database::Experiment &&
 
  151          (parameters.getModel() == Parameters::Arg::Temperature ||
 
  152           parameters.getModel() == Parameters::Arg::Cascade)) {
 
  153        std::vector<sql_properties> prop = pahdb.getPropertiesByIDs(
 
  154            parameters.getIds()); 
 
  156        std::vector<int> charges;
 
  157        charges.reserve(parameters.getIds().size());
 
  158        std::vector<int> carbons;
 
  159        carbons.reserve(parameters.getIds().size());
 
  160        for (
const auto &properties : prop) {
 
  162          charges.push_back(properties.charge);
 
  163          carbons.push_back(properties.n_c);
 
  166        pahemissionmodel.useApproximate(charges, carbons);
 
  169      switch (parameters.getModel()) {
 
  171      case Parameters::Arg::FixedTemperature:
 
  173        if (parameters.getTool() == Parameters::Arg::TemperatureStack) {
 
  175          pahemissionmodel.applyBlackbodyWithTemperatureForEach(
 
  176              parameters.getTemperaturesInKelvin());
 
  179          pahemissionmodel.applyBlackbodyWithTemperature(
 
  180              parameters.getTemperatureInKelvin());
 
  185      case Parameters::Arg::Temperature:
 
  187        pahemissionmodel.applyTemperatureWithEnergy(parameters.getEnergyInCGS(),
 
  192      case Parameters::Arg::Cascade:
 
  194        pahemissionmodel.applyCascadeWithEnergy(parameters.getEnergyInCGS(),
 
  199      case Parameters::Arg::ZeroKelvin:
 
  205      if (parameters.getShift() != 0.0) {
 
  207        pahemissionmodel.shiftTransitions(parameters.getShift());
 
  210      switch (parameters.getProfile()) {
 
  212      case Parameters::Arg::Gaussian:
 
  214        pahemissionmodel.getSpectraAndConvolveWithGaussianOfFHWM(
 
  215            spectra, parameters.getFWHM());
 
  218      case Parameters::Arg::Drude:
 
  220        pahemissionmodel.getSpectraAndConvolveWithDrudeOfFHWM(
 
  221            spectra, parameters.getFWHM());
 
  224      case Parameters::Arg::Lorentzian:
 
  227        pahemissionmodel.getSpectraAndConvolveWithLorentianOfFHWM(
 
  228            spectra, parameters.getFWHM());
 
  235    std::cerr << e.what() << std::endl;
 
  239      pahdb.setError(e.what());
 
  242      std::cerr << e.what() << std::endl;
 
  250    pahdb.setProgress(60.0);
 
  253    std::cerr << e.what() << std::endl;
 
  258  std::vector<double> small;
 
  260  std::vector<double> large;
 
  262  std::vector<double> anion;
 
  264  std::vector<double> neutral;
 
  266  std::vector<double> cation;
 
  268  if (parameters.getTool() == Parameters::Arg::SpectralFit) {
 
  270    spectralfitter.setPool(spectra);
 
  272    spectralfitter.fitSpectrum();
 
  274    std::vector<unsigned int> indices = spectralfitter.getNonZeroIndices();
 
  276    std::vector<int> ids;
 
  278    for (
const auto index : indices) {
 
  280      ids.push_back(parameters.getIds().at(index));
 
  283    std::vector<sql_properties> prop =
 
  284        pahdb.getPropertiesByIDs(ids); 
 
  286    small = std::vector<double>(grid.size(), 0.0);
 
  288    large = std::vector<double>(grid.size(), 0.0);
 
  290    anion = std::vector<double>(grid.size(), 0.0);
 
  292    neutral = std::vector<double>(grid.size(), 0.0);
 
  294    cation = std::vector<double>(grid.size(), 0.0);
 
  298    for (
const auto &properties : prop) {
 
  302      if (properties.n_c > 50) {
 
  304        for (
auto &l : large) {
 
  306          l += spectralfitter.getWeights().at(indices.at(j)) *
 
  307               spectra.at(indices.at(j)).at(k++);
 
  311        for (
auto &s : small) {
 
  313          s += spectralfitter.getWeights().at(indices.at(j)) *
 
  314               spectra.at(indices.at(j)).at(k++);
 
  320      if (properties.charge < 0) {
 
  322        for (
auto &a : anion) {
 
  324          a += spectralfitter.getWeights().at(indices.at(j)) *
 
  325               spectra.at(indices.at(j)).at(k++);
 
  327      } 
else if (properties.charge == 0) {
 
  329        for (
auto &n : neutral) {
 
  331          n += spectralfitter.getWeights().at(indices.at(j)) *
 
  332               spectra.at(indices.at(j)).at(k++);
 
  336        for (
auto &c : cation) {
 
  338          c += spectralfitter.getWeights().at(indices.at(j)) *
 
  339               spectra.at(indices.at(j)).at(k++);
 
  349    pahdb.setProgress(80.0);
 
  352    std::cerr << e.what() << std::endl;
 
  359  canvas.setSize(parameters.getPlotSize());
 
  361  canvas.setColor(
"ffffff");
 
  363  canvas.setDefaultCharacterHeight(parameters.getPlotSize().at(1) * 2.0 /
 
  370  plot.setXLimits(parameters.getPlotLimits());
 
  372  plot.setDrawHorizontalFineGrid();
 
  374  plot.setDrawVerticalFineGrid();
 
  376  plot.getHorizontalGrid().setColor(
"dedede");
 
  378  plot.getHorizontalGrid().setLineStyle(Plot::Style::Dashed);
 
  380  plot.getVerticalGrid() = plot.getHorizontalGrid();
 
  382  plot.getYAxis().at(0).setWriteLabelsParallel();
 
  384  plot.getYAxis().at(0).setStyle(Axis::Style::WritePowerInFrame);
 
  392  switch (parameters.getUnits()) {
 
  394  case Parameters::Arg::Wavelength:
 
  396    xtitle = 
"#fiwavelength [micron]";
 
  398    xtitle2 = 
"#fifrequency [cm#u-1#d]";
 
  400    if (parameters.getTool() != Parameters::Arg::CompareExperimentWithTheory) {
 
  402      PAHEmissionModel::convertFromFrequencyToWavelength(grid);
 
  405      PAHEmissionModel::convertFromFrequencyToWavelength(transitions);
 
  409  case Parameters::Arg::Frequency:
 
  412    xtitle = 
"#fifrequency [cm#u-1#d]";
 
  414    xtitle2 = 
"#fiwavelength [micron]";
 
  417  if (parameters.getTool() == Parameters::Arg::CompareExperimentWithTheory) {
 
  419    ytitle = 
"#fiintegrated cross-section [#fnx#fi10#u5#d cm/mol]";
 
  420  } 
else if (parameters.getModel() == Parameters::Arg::ZeroKelvin) {
 
  422    ytitle = 
"#ficross-section [#fnx#fi10#u5#d cm#u2#d/mol]";
 
  423  } 
else if (parameters.getModel() == Parameters::Arg::FixedTemperature ||
 
  424             parameters.getModel() == Parameters::Arg::Temperature) {
 
  426    ytitle = 
"#fispectral radiance [erg/s/cm#u-1#d/PAH]";
 
  427  } 
else if (parameters.getModel() == Parameters::Arg::Cascade) {
 
  429    ytitle = 
"#firadiant energy [erg/cm#u-1#d/PAH]";
 
  432  std::vector<Plot> plots;
 
  444  point.setSymbol(256);
 
  448  text.setJustification(Text::RightJustification);
 
  450  text.setColor(
"0000ff");
 
  452  std::vector<std::string> formulae;
 
  456  std::vector<PAHGeometry> geometries;
 
  458  geometries.reserve(2);
 
  460  std::vector<double> sum;
 
  462  std::ostringstream ostr;
 
  464  std::array<double, 2> margins;
 
  466  std::array<double, 2> newmargins;
 
  470  std::array<int, 2> canvassize;
 
  472  std::vector<bool> available;
 
  474  available.reserve(3);
 
  478  std::array<const char *, 3> annotations = {
"Laboratory", 
"Harmonic Theory",
 
  479                                             "Anharmonic Theory"};
 
  481  switch (parameters.getTool()) {
 
  483  case Parameters::Arg::Stack:
 
  484  case Parameters::Arg::TemperatureStack:
 
  486    canvassize[0] = canvas.getSize().at(0);
 
  488    canvassize[1] = canvas.getSize().at(1) +
 
  489                    (spectra.size() - 1) * parameters.getPlotSize().at(1) *
 
  490                        (plot.getYMargins().at(1) - plot.getYMargins().at(0));
 
  492    canvas.setSize(canvassize);
 
  494    margins[0] = plot.getYMargins().at(0) * parameters.getPlotSize().at(1) /
 
  495                 canvas.getSize().at(1);
 
  497    margins[1] = 1.0 - ((1.0 - plot.getYMargins().at(1)) *
 
  498                        parameters.getPlotSize().at(1)) /
 
  499                           canvas.getSize().at(1);
 
  501    panels.setYMargins(margins);
 
  503    panels.setLayout(1, spectra.size());
 
  505    geometries = pahdb.getGeometriesFromIds(parameters.getIds());
 
  507    std::for_each(geometries.begin(), geometries.end(),
 
  508                  std::mem_fn(&PAHGeometry::diagonalize));
 
  510    for (
const auto &spectrum : spectra) {
 
  512      plot.setAdvance(
false);
 
  516      plot.setDrawHorizontalFineGrid();
 
  518      plot.setDrawVerticalFineGrid();
 
  520      plot.getXAxis().at(0).setDrawConventionalAxis(
false);
 
  522      plot.getXAxis().at(0).setDrawUnconventionalAxis(
false);
 
  524      plot.getXAxis().at(0).setDrawConventionalLabels(
false);
 
  526      plot.getYAxis().at(0).setDrawConventionalAxis(
false);
 
  528      plot.getYAxis().at(0).setDrawUnconventionalAxis(
false);
 
  530      plot.getYAxis().at(0).setDrawConventionalLabels(
false);
 
  533          MinMax::min_max(spectrum, MinMax::Nice | MinMax::MaxExtraRoom));
 
  535      plots.push_back(plot);
 
  539      plot.setDrawHorizontalFineGrid(
false);
 
  541      plot.setDrawVerticalFineGrid(
false);
 
  545      if (parameters.getTool() == Parameters::Arg::Stack) {
 
  547        line.setColor(
"cccccc");
 
  549        line.setLineWidth(5);
 
  553        for (
const auto &bonds : geometries.at(i).getBonds()) {
 
  555          for (
const auto &bond : bonds) {
 
  557            line.setStartCoordinates(
 
  558                (plot.getXLimits().at(1) + plot.getXLimits().at(0)) / 2.0 +
 
  559                    geometries.at(i)[j].getX() *
 
  560                        (plot.getXLimits().at(1) - plot.getXLimits().at(0)) /
 
  561                        (28.0 * parameters.getPlotSize().at(0) /
 
  562                         parameters.getPlotSize().at(1)),
 
  563                (plot.getYLimits().at(1) + plot.getYLimits().at(0)) / 2.0 +
 
  564                    geometries.at(i)[j].getY() *
 
  565                        (plot.getYLimits().at(1) - plot.getYLimits().at(0)) /
 
  567                geometries.at(i)[j].getZ());
 
  569            line.setEndCoordinates(
 
  570                (plot.getXLimits().at(1) + plot.getXLimits().at(0)) / 2.0 +
 
  571                    geometries.at(i)[bond].getX() *
 
  572                        (plot.getXLimits().at(1) - plot.getXLimits().at(0)) /
 
  573                        (28.0 * parameters.getPlotSize().at(0) /
 
  574                         parameters.getPlotSize().at(1)),
 
  575                (plot.getYLimits().at(1) + plot.getYLimits().at(0)) / 2.0 +
 
  576                    geometries.at(i)[bond].getY() *
 
  577                        (plot.getYLimits().at(1) - plot.getYLimits().at(0)) /
 
  579                geometries.at(i)[j].getZ());
 
  587        for (
const auto &atom : geometries.at(i)) {
 
  589          point.setCoordinates(
 
  590              (plot.getXLimits().at(1) + plot.getXLimits().at(0)) / 2.0 +
 
  592                      (plot.getXLimits().at(1) - plot.getXLimits().at(0)) /
 
  593                      (28.0 * parameters.getPlotSize().at(0) /
 
  594                       parameters.getPlotSize().at(1)),
 
  595              (plot.getYLimits().at(1) + plot.getYLimits().at(0)) / 2.0 +
 
  597                      (plot.getYLimits().at(1) - plot.getYLimits().at(0)) /
 
  601          point.setColor(atom.getCPKColor());
 
  603          point.setSize(atom.getSize() / 70.0);
 
  608        plots.push_back(plot);
 
  615      formulae = pahdb.getFormulaeFromIds(parameters.getIds());
 
  617      if (parameters.getTool() != Parameters::Arg::TemperatureStack) {
 
  619        text.setText(Text::formatChemicalFormula(formulae.at(i)));
 
  621        text.setCoordinates(0.95, 0.85, 0.0, Text::CoordinateSystem::NORMAL);
 
  625        plots.push_back(plot);
 
  632      if ((parameters.getModel() != Parameters::Arg::ZeroKelvin &&
 
  633           parameters.getModel() != Parameters::Arg::FixedTemperature) ||
 
  634          parameters.getTool() == Parameters::Arg::TemperatureStack) {
 
  638        ostr << static_cast<int>(
 
  639                    parameters.getTool() == Parameters::Arg::TemperatureStack
 
  640                        ? parameters.getTemperaturesInKelvin().at(i)
 
  641                        : temperatures.at(i))
 
  644        text.setText(ostr.str());
 
  646        text.setCoordinates(0.95, 0.75, 0.0, Text::CoordinateSystem::NORMAL);
 
  650        plots.push_back(plot);
 
  655      plot.getXAxis().at(0).setDrawConventionalAxis();
 
  657      plot.getXAxis().at(0).setDrawUnconventionalAxis();
 
  659      plot.getYAxis().at(0).setDrawConventionalAxis();
 
  661      plot.getYAxis().at(0).setDrawUnconventionalAxis();
 
  663      plot.getYAxis().at(0).setDrawConventionalLabels();
 
  667      curve.setXAndY(grid, spectra.at(i++));
 
  671      plot.setAdvance(
true);
 
  673      plots.push_back(plot);
 
  678    plots.front().getXAxis().at(0).setDrawConventionalLabels();
 
  680    plots.front().getXAxis().at(0).setTitle(xtitle);
 
  682    plots.back().getXAxis().at(0).setDrawUnconventionalAxis(
false);
 
  684    plots.back().getXAxis().emplace_back();
 
  686    plots.back().getXAxis().at(1).setDrawConventionalLabels(
false);
 
  690    plots.back().getXAxis().at(1).setReciprocalLabelFormatter();
 
  692    plots.back().getXAxis().at(1).setDrawConventionalAxis(
false);
 
  694    plots.back().getXAxis().at(1).setDrawUnconventionalLabels();
 
  696    plots.back().getXAxis().at(1).setTitle(xtitle2);
 
  702    text.setColor(
"000000");
 
  704    text.setText(ytitle);
 
  706    text.setJustification(Text::CenterJustification);
 
  714        panels.getYMargins().at(0) +
 
  715            (panels.getYMargins().at(1) - panels.getYMargins().at(0)) / 2.0,
 
  721  case Parameters::Arg::CompareExperimentWithTheory:
 
  723    for (
const auto &t : transitions) {
 
  725      available.emplace_back(t.size());
 
  728    npanels = std::count(available.begin(), available.end(), 
true);
 
  730    canvassize[0] = canvas.getSize().at(0);
 
  732    canvassize[1] = canvas.getSize().at(1) +
 
  733                    (npanels - 1) * parameters.getPlotSize().at(1) *
 
  734                        (plot.getYMargins().at(1) - plot.getYMargins().at(0));
 
  736    canvas.setSize(canvassize);
 
  738    margins[0] = plot.getYMargins().at(0) * parameters.getPlotSize().at(1) /
 
  739                 canvas.getSize().at(1);
 
  741    margins[1] = 1.0 - ((1.0 - plot.getYMargins().at(1)) *
 
  742                        parameters.getPlotSize().at(1)) /
 
  743                           canvas.getSize().at(1);
 
  747    plot.setAdvance(
false);
 
  749    plot.getXAxis().at(0).setDrawConventionalAxis(
false);
 
  751    plot.getXAxis().at(0).setDrawUnconventionalAxis(
false);
 
  753    plot.getXAxis().at(0).setDrawConventionalLabels(
false);
 
  755    plot.getYAxis().at(0).setDrawConventionalAxis(
false);
 
  757    plot.getYAxis().at(0).setDrawUnconventionalAxis(
false);
 
  759    plot.getYAxis().at(0).setDrawConventionalLabels(
false);
 
  762        MinMax::min_max(transitions, MinMax::Nice | MinMax::MaxExtraRoom));
 
  764    newmargins[0] = margins[0];
 
  766    newmargins[1] = margins[0] + (margins[1] - margins[0]) / npanels;
 
  768    plot.setYMargins(newmargins);
 
  770    plots.push_back(plot);
 
  774    newmargins[0] = newmargins[1];
 
  776    newmargins[1] = newmargins[1] + (margins[1] - margins[0]) / npanels;
 
  778    plot.setYMargins(newmargins);
 
  780    plots.push_back(plot);
 
  786      newmargins[0] = newmargins[1];
 
  788      newmargins[1] = newmargins[1] + (margins[1] - margins[0]) / npanels;
 
  790      plot.setYMargins(newmargins);
 
  792      plots.push_back(plot);
 
  799    geometries = pahdb.getGeometriesFromIds(parameters.getIds());
 
  801    std::for_each(geometries.begin(), geometries.end(),
 
  802                  std::mem_fn(&PAHGeometry::diagonalize));
 
  804    plot.setDrawHorizontalFineGrid(
false);
 
  806    plot.setDrawVerticalFineGrid(
false);
 
  808    plot.setYMargins(margins);
 
  810    line.setColor(
"cccccc");
 
  812    line.setLineWidth(5);
 
  814    for (
const auto &bonds : geometries.at(0).getBonds()) {
 
  816      for (
const auto bond : bonds) {
 
  818        line.setStartCoordinates(
 
  819            (plot.getXLimits().at(1) + plot.getXLimits().at(0)) / 2.0 +
 
  820                geometries.at(0)[i].getX() *
 
  821                    (plot.getXLimits().at(1) - plot.getXLimits().at(0)) / 28.0,
 
  822            (plot.getYLimits().at(1) + plot.getYLimits().at(0)) / 2.0 +
 
  823                canvas.getAspectRatio() * geometries.at(0)[i].getY() *
 
  824                    (plot.getYLimits().at(1) - plot.getYLimits().at(0)) / 28.0,
 
  825            geometries.at(0)[i].getZ());
 
  827        line.setEndCoordinates(
 
  828            (plot.getXLimits().at(1) + plot.getXLimits().at(0)) / 2.0 +
 
  829                geometries.at(0)[bond].getX() *
 
  830                    (plot.getXLimits().at(1) - plot.getXLimits().at(0)) / 28.0,
 
  831            (plot.getYLimits().at(1) + plot.getYLimits().at(0)) / 2.0 +
 
  832                canvas.getAspectRatio() * geometries.at(0)[bond].getY() *
 
  833                    (plot.getYLimits().at(1) - plot.getYLimits().at(0)) / 28.0,
 
  834            geometries.at(0)[bond].getZ());
 
  844    for (
const auto &atom : geometries.at(0)) {
 
  846      point.setCoordinates(
 
  847          (plot.getXLimits().at(1) + plot.getXLimits().at(0)) / 2.0 +
 
  849                  (plot.getXLimits().at(1) - plot.getXLimits().at(0)) / 28.0,
 
  850          (plot.getYLimits().at(1) + plot.getYLimits().at(0)) / 2.0 +
 
  851              canvas.getAspectRatio() * atom.getY() *
 
  852                  (plot.getYLimits().at(1) - plot.getYLimits().at(0)) / 28.0,
 
  855      point.setColor(atom.getCPKColor());
 
  857      point.setSize(atom.getSize() / 40.0);
 
  864    formulae = pahdb.getFormulaeFromIds(parameters.getIds());
 
  866    text.setColor(
"0000ff");
 
  870    text.setJustification(Text::RightJustification);
 
  872    text.setText(Text::formatChemicalFormula(formulae.at(0)));
 
  874    text.setCoordinates(0.95, 0.95, 0.0, Text::CoordinateSystem::NORMAL);
 
  878    plots.push_back(plot);
 
  882    plot.getXAxis().at(0).setTitle(xtitle);
 
  884    plot.getXAxis().at(0).setDrawConventionalAxis();
 
  888      plot.getXAxis().emplace_back();
 
  890      plot.getXAxis().at(1).setDrawConventionalLabels(
false);
 
  893    plot.getXAxis().at(0).setDrawConventionalLabels();
 
  895    plot.getYAxis().at(0).setDrawConventionalAxis();
 
  897    plot.getYAxis().at(0).setDrawUnconventionalAxis();
 
  899    plot.getYAxis().at(0).setDrawConventionalLabels();
 
  901    newmargins[0] = margins[0];
 
  903    newmargins[1] = margins[0] + (margins[1] - margins[0]) / npanels;
 
  905    plot.setYMargins(newmargins);
 
  907    line.setLineWidth(4);
 
  909    line.setColor(
"ff0000");
 
  911    if (!available.at(i)) {
 
  920    text.setJustification(Text::CenterJustification);
 
  922    text.setText(annotations.at(i));
 
  924    text.setCoordinates(0.5, 0.75, 0.0, Text::CoordinateSystem::NORMAL);
 
  930    for (
const auto &transition : transitions.at(i++)) {
 
  932      line.setStartCoordinates(transition.first, 0.0, 0.0);
 
  934      line.setEndCoordinates(transition.first, transition.second, 0.0);
 
  939    plots.push_back(plot);
 
  943    newmargins[0] = newmargins[1];
 
  945    newmargins[1] = newmargins[1] + (margins[1] - margins[0]) / npanels;
 
  947    plot.setYMargins(newmargins);
 
  951      plot.getXAxis().at(0).setTitle(
"");
 
  953      plot.getXAxis().at(0).setDrawConventionalLabels(
false);
 
  958      plot.getXAxis().emplace_back();
 
  962      plot.getXAxis().at(1).setReciprocalLabelFormatter();
 
  964      plot.getXAxis().at(0).setDrawUnconventionalAxis(
false);
 
  966      plot.getXAxis().at(1).setDrawConventionalAxis(
false);
 
  968      plot.getXAxis().at(1).setDrawConventionalLabels(
false);
 
  970      plot.getXAxis().at(1).setDrawUnconventionalAxis();
 
  972      plot.getXAxis().at(1).setDrawUnconventionalLabels();
 
  974      plot.getXAxis().at(1).setTitle(xtitle2);
 
  976      plot.getXAxis().at(0).setTitle(
"");
 
  978      plot.getXAxis().at(0).setDrawZeroLine();
 
  980      plot.getXAxis().at(0).setDrawConventionalLabels(
false);
 
  983    if (!available.at(i)) {
 
  990    text.setText(annotations.at(i));
 
  992    text.setCoordinates(0.5, 0.75, 0.0, Text::CoordinateSystem::NORMAL);
 
  998    for (
const auto &transition : transitions.at(i++)) {
 
 1000      line.setStartCoordinates(transition.first, 0.0, 0.0);
 
 1002      line.setEndCoordinates(transition.first, transition.second, 0.0);
 
 1007    plots.push_back(plot);
 
 1013      newmargins[0] = newmargins[1];
 
 1015      newmargins[1] = newmargins[1] + (margins[1] - margins[0]) / npanels;
 
 1017      plot.setYMargins(newmargins);
 
 1021      plot.getXAxis().at(1).setReciprocalLabelFormatter();
 
 1023      plot.getXAxis().at(0).setDrawUnconventionalAxis(
false);
 
 1025      plot.getXAxis().at(1).setDrawConventionalAxis(
false);
 
 1027      plot.getXAxis().at(1).setDrawConventionalLabels(
false);
 
 1029      plot.getXAxis().at(1).setDrawUnconventionalAxis();
 
 1031      plot.getXAxis().at(1).setDrawUnconventionalLabels();
 
 1033      plot.getXAxis().at(1).setTitle(xtitle2);
 
 1035      plot.getXAxis().at(0).setTitle(
"");
 
 1037      plot.getXAxis().at(0).setDrawZeroLine();
 
 1039      plot.getXAxis().at(0).setDrawConventionalLabels(
false);
 
 1043      text.setText(annotations.at(i));
 
 1045      text.setCoordinates(0.5, 0.75, 0.0, Text::CoordinateSystem::NORMAL);
 
 1051      for (
const auto &transition : transitions.at(i)) {
 
 1053        line.setStartCoordinates(transition.first, 0.0, 0.0);
 
 1055        line.setEndCoordinates(transition.first, transition.second, 0.0);
 
 1060      plots.push_back(plot);
 
 1065    text.setColor(
"000000");
 
 1067    text.setText(ytitle);
 
 1069    text.setJustification(Text::CenterJustification);
 
 1071    text.setAngle(90.0);
 
 1075    text.setCoordinates(0.0723,
 
 1076                        margins[0] + (margins[1] - margins[0]) / npanels, 0.0);
 
 1081  case Parameters::Arg::SpectralFit:
 
 1085    curve.setXAndY(grid, std::get<1>(inputdata));
 
 1087    if (std::get<2>(inputdata).size() == std::get<1>(inputdata).size()) {
 
 1089      curve.setYErr(std::get<2>(inputdata));
 
 1098    curve.setFill(
false);
 
 1100    curve.setColor(
"dedede");
 
 1102    sum = std::vector<double>(spectra.at(0).size());
 
 1104    for (
auto &spectrum : spectra) {
 
 1108      if (spectralfitter.getWeights().at(i) == 0.0) {
 
 1115      for (
auto &s : spectrum) {
 
 1117        s *= spectralfitter.getWeights().at(i);
 
 1122      curve.setXAndY(grid, spectrum);
 
 1129    curve.setXAndY(grid, sum);
 
 1131    curve.setColor(
"ff0000");
 
 1133    curve.setLineWidth(2);
 
 1137    plot.setYLimits(MinMax::min_max(sum, MinMax::Nice));
 
 1139    text.setJustification(Text::LeftJustification);
 
 1141    text.setColor(
"ff0000");
 
 1143    text.setText(
"total fit");
 
 1145    text.setCoordinates(0.85, 0.90, 0.0, Text::CoordinateSystem::NORMAL);
 
 1149    text.setColor(
"00ff00");
 
 1151    text.setText(
"N#dC#u>50");
 
 1153    text.setCoordinates(0.85, 0.83, 0.0, Text::CoordinateSystem::NORMAL);
 
 1157    text.setColor(
"0000ff");
 
 1159    text.setText(
"N#dC#u<50");
 
 1161    text.setCoordinates(0.85, 0.76, 0.0, Text::CoordinateSystem::NORMAL);
 
 1165    text.setColor(
"fff00f");
 
 1167    text.setText(
"anion");
 
 1169    text.setCoordinates(0.85, 0.69, 0.0, Text::CoordinateSystem::NORMAL);
 
 1173    text.setColor(
"ff00ff");
 
 1175    text.setText(
"neutral");
 
 1177    text.setCoordinates(0.85, 0.62, 0.0, Text::CoordinateSystem::NORMAL);
 
 1181    text.setColor(
"00ffff");
 
 1183    text.setText(
"cation");
 
 1185    text.setCoordinates(0.85, 0.55, 0.0, Text::CoordinateSystem::NORMAL);
 
 1189    curve.setXAndY(grid, large);
 
 1191    curve.setColor(
"00ff00");
 
 1193    curve.setLineWidth(1);
 
 1197    curve.setXAndY(grid, small);
 
 1199    curve.setColor(
"0000ff");
 
 1203    curve.setXAndY(grid, anion);
 
 1205    curve.setColor(
"fff00f");
 
 1209    curve.setXAndY(grid, neutral);
 
 1211    curve.setColor(
"ff00ff");
 
 1215    curve.setXAndY(grid, cation);
 
 1217    curve.setColor(
"00ffff");
 
 1221    plot.getXAxis().at(0).setTitle(xtitle);
 
 1223    plot.getXAxis().emplace_back();
 
 1227    plot.getXAxis().at(1).setReciprocalLabelFormatter();
 
 1229    plot.getXAxis().at(0).setDrawUnconventionalAxis(
false);
 
 1231    plot.getXAxis().at(1).setDrawConventionalAxis(
false);
 
 1233    plot.getXAxis().at(1).setDrawConventionalLabels(
false);
 
 1235    plot.getXAxis().at(1).setDrawUnconventionalAxis();
 
 1237    plot.getXAxis().at(1).setDrawUnconventionalLabels();
 
 1239    plot.getXAxis().at(1).setTitle(xtitle2);
 
 1241    plot.getYAxis().at(0).setTitle(ytitle);
 
 1243    plots.push_back(plot);
 
 1249    ostr << 
"Euclidean distance norm: " << spectralfitter.getNorm();
 
 1251    if (std::get<2>(inputdata).size() == std::get<1>(inputdata).size()) {
 
 1252      ostr << 
" (NNLC; used provided uncertainties)";
 
 1257    text.setColor(
"000000");
 
 1259    text.setText(ostr.str());
 
 1261    text.setCoordinates(0.25, 0.8, 0.0);
 
 1266  case Parameters::Arg::CoAdd:
 
 1269    sum = std::vector<double>(spectra.at(0).size());
 
 1271    for (
const auto &spectrum : spectra) {
 
 1275      for (
auto s : spectrum) {
 
 1277        sum.at(j++) += s * parameters.getWeights().at(i);
 
 1283    curve.setXAndY(grid, sum);
 
 1287    plot.setYLimits(MinMax::min_max(sum, MinMax::Nice));
 
 1289    plot.getXAxis().at(0).setTitle(xtitle);
 
 1291    plot.getXAxis().emplace_back();
 
 1295    plot.getXAxis().at(1).setReciprocalLabelFormatter();
 
 1297    plot.getXAxis().at(0).setDrawUnconventionalAxis(
false);
 
 1299    plot.getXAxis().at(1).setDrawConventionalAxis(
false);
 
 1301    plot.getXAxis().at(1).setDrawConventionalLabels(
false);
 
 1303    plot.getXAxis().at(1).setDrawUnconventionalAxis();
 
 1305    plot.getXAxis().at(1).setDrawUnconventionalLabels();
 
 1307    plot.getXAxis().at(1).setTitle(xtitle2);
 
 1309    plot.getYAxis().at(0).setTitle(ytitle);
 
 1311    plots.push_back(plot);
 
 1318  std::string f(parameters.getOutputFilename());
 
 1322  spectra.insert(spectra.begin(), grid);
 
 1324  time_t t = time(
nullptr);
 
 1326  std::vector<std::string> header{
"NASA Ames PAH IR Spectroscopic Database",
 
 1327                                  std::string(
"Date: ") + ctime(&t),
 
 1328                                  "Version : " PROGRAM_VERSION,
 
 1329                                  "Build: " PROGRAM_BUILD,
 
 1330                                  std::string(
"First column: ") + xtitle,
 
 1331                                  std::string(
"Other columns: ") + ytitle};
 
 1333  if (parameters.getTool() == Parameters::Arg::SpectralFit) {
 
 1335    header.insert(header.end(), {
"First row: UIDs", 
"Second row: weights"});
 
 1337    std::ostringstream uids;
 
 1339    uids << std::right << std::setw(12) << 0 << 
'\t';
 
 1341    std::vector<sql_properties> prop = pahdb.getPropertiesByIDs(
 
 1342        parameters.getIds()); 
 
 1344    for (
const auto &properties : prop) {
 
 1346      uids << std::right << std::setw(12) << properties.uid << 
'\t';
 
 1349    header.insert(header.end(), {uids.str(), 
"First row: weights"});
 
 1351    spectra.at(0).insert(spectra.at(0).begin(), 0);
 
 1353    for (
size_t i = 1; i < spectra.size(); i++) {
 
 1355      spectra.at(i).insert(spectra.at(i).begin(),
 
 1356                           spectralfitter.getWeights().at(i - 1));
 
 1360  fileoutput.writeTableHeaderToDisk(header);
 
 1362  fileoutput.writeTableToDisk(spectra);
 
 1364  if (parameters.isX11()) {
 
 1366    canvas.paintOnScreen();
 
 1369  if (parameters.isPNG()) {
 
 1371    canvas.paintOnPNG(parameters.getOutputFilename());
 
 1374  if (parameters.isJPEG()) {
 
 1376    canvas.paintOnJPEG(parameters.getOutputFilename());
 
 1379  if (parameters.isPostscript()) {
 
 1380    canvas.paintOnPostscript(parameters.getOutputFilename());
 
 1385    pahdb.setProgress(100.0);
 
 1388    std::cerr << e.what() << std::endl;