SourceXtractorPlusPlus  0.19
SourceXtractor++, the next generation SExtractor
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LdacOutput.cpp
Go to the documentation of this file.
1 
18 #include <sstream>
19 
21 
22 #include "SOURCEXTRACTORPLUSPLUS_VERSION.h"
23 
28 
29 #if BOOST_VERSION < 107300
30 #include <boost/io/detail/quoted_manip.hpp>
31 #else
32 #include <boost/io/quoted.hpp>
33 #endif
34 
35 namespace SourceXtractor {
36 
39 using namespace Euclid::Table;
40 
41 namespace {
42 
43 template<typename T>
44 std::string generateHeader(const std::string& name, T value, const std::string& comment) {
46 
47  str << std::setw(8) << std::left << name << "= "
48  << std::scientific << std::setw(20) << std::right << value
49  << " / ";
50 
51  if (str.str().size() > 80) {
52  throw Elements::Exception() << "Header cannot exceed 80 characters: \"" << str.str() << "\"";
53  }
54 
55  size_t remaining = 80 - str.str().size();
56  if (comment.size() < remaining) {
57  str << comment << std::string(remaining - comment.size(), ' ');
58  } else {
59  // truncate comment if too long
60  str << comment.substr(0, remaining);
61  }
62 
63  return str.str();
64 }
65 
66 template<>
67 std::string generateHeader<std::string>(const std::string& name, std::string value, const std::string& comment) {
68  std::stringstream str, quoted_value;
69 
70  quoted_value << boost::io::quoted(value, '\'', '\'');
71 
72  str << std::setw(8) << std::left << name << "= "
73  << std::setw(20) << std::left << quoted_value.str()
74  << " / ";
75 
76  if (str.str().size() > 80) {
77  throw Elements::Exception() << "Header cannot exceed 80 characters: \"" << str.str() << "\"";
78  }
79 
80  size_t remaining = 80 - str.str().size();
81  if (comment.size() < remaining) {
82  str << comment << std::string(remaining - comment.size(), ' ');
83  } else {
84  // truncate comment if too long
85  str << comment.substr(0, remaining);
86  }
87 
88  return str.str();
89 }
90 
91 static void generateHistory(std::vector<std::string>& headers) {
94 
95  str << "Version " << SOURCEXTRACTORPLUSPLUS_VERSION_STRING;
96  entries.emplace_back(str.str());
97  str.str("");
98 
99  auto t = std::time(nullptr);
100  auto now = *std::gmtime(&t);
101 
102  char date_str[32];
103  strftime(date_str, sizeof(date_str), "%Y-%m-%dT%H:%M:%SZ", &now);
104  str << "Called at " << date_str;
105  entries.emplace_back(str.str());
106  str.str("");
107 
108  for (auto& e : entries) {
109  std::stringstream padder;
110  padder << "HISTORY s++: " << std::setw(67) << std::left << e;
111  headers.emplace_back(padder.str());
112  }
113 }
114 
115 }
116 
118  if (m_fits_writer == nullptr) {
119  const auto& detection_frame_info = source.getProperty<DetectionFrameInfo>();
120  m_rms = detection_frame_info.getBackgroundMedianRms();
121  m_gain = detection_frame_info.getGain();
122 
123  // Headers from the image
124  m_image_metadata = detection_frame_info.getMetadata();
125 
126  writeHeaders();
127 
128  m_fits_writer = std::make_shared<FitsWriter>(m_filename);
129 
130 
131  if (m_part_nb >= 1) {
132  std::stringstream hdu_name;
133  hdu_name << "LDAC_OBJECTS_" << m_part_nb;
134  m_fits_writer->setHduName(hdu_name.str());
135  } else {
136  m_fits_writer->setHduName("LDAC_OBJECTS");
137  }
138  }
140 }
141 
143  auto imhead_writer = Euclid::make_unique<FitsWriter>(m_filename, m_part_nb == 0);
144  if (m_part_nb >= 1) {
145  std::stringstream hdu_name;
146  hdu_name << "LDAC_IMHEAD_" << m_part_nb;
147  imhead_writer->setHduName(hdu_name.str());
148  } else {
149  imhead_writer->setHduName("LDAC_IMHEAD");
150  }
151 
152  // Headers from the image
153  std::vector<std::string> ldac_imhead;
154  for (const auto &p : m_image_metadata) {
155  std::string comment;
156  if (p.second.m_extra.count("comment")) {
157  comment = p.second.m_extra.at("comment");
158  }
159  if (p.second.m_value.type() == typeid(std::string)) {
160  ldac_imhead.emplace_back(generateHeader(p.first, boost::get<std::string>(p.second.m_value), comment));
161  } else {
162  ldac_imhead.emplace_back(generateHeader(p.first, p.second.m_value, comment));
163  }
164  }
165 
166  // Headers from the configuration and detection
167  ldac_imhead.emplace_back(generateHeader("SPPGAIN", m_gain, "Gain used"));
168  ldac_imhead.emplace_back(generateHeader("SPPBKDEV", m_rms, "Median background RMS"));
169 
170  // History, why not
171  generateHistory(ldac_imhead);
172 
173  // END
174  ldac_imhead.emplace_back("END" + std::string(77, ' '));
175 
176  // Join everything as a single string
177  std::string header = std::accumulate(ldac_imhead.begin(), ldac_imhead.end(), std::string());
178 
179  // Write the table
180  auto column_info = std::make_shared<ColumnInfo>(std::vector<ColumnInfo::info_type>{{"Field Header Card", typeid(std::string)}});
181  std::vector<Row> rows{{std::vector<Row::cell_type>{header}, column_info}};
182  imhead_writer->addData(Table{std::move(rows)});
183 }
184 
186  m_part_nb++;
187  // closes current HDU and will trigger a new header HDU when the next source is written
188  m_fits_writer = nullptr;
189 }
190 
191 } // end of namespace SourceXtractor
const PropertyType & getProperty(unsigned int index=0) const
Convenience template method to call getProperty() with a more user-friendly syntax.
T left(T...args)
T end(T...args)
T time(T...args)
T setw(T...args)
STL class.
T at(T...args)
T gmtime(T...args)
constexpr double e
T strftime(T...args)
T str(T...args)
void outputSource(const SourceInterface &source) override
Definition: LdacOutput.cpp:117
T move(T...args)
void outputSource(const SourceInterface &source) override
T scientific(T...args)
T size(T...args)
T begin(T...args)
std::unique_ptr< T > make_unique(Args &&...args)
T substr(T...args)
T accumulate(T...args)
The SourceInterface is an abstract &quot;source&quot; that has properties attached to it.
void nextPart() override
Definition: LdacOutput.cpp:185
T emplace_back(T...args)