SourceXtractorPlusPlus 1.0.3
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
LdacOutput.cpp
Go to the documentation of this file.
1
17
18#include <sstream>
19
20#include <AlexandriaKernel/memory_tools.h>
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
35namespace SourceXtractor {
36
37using Euclid::Configuration::ConfigManager;
39using namespace Euclid::Table;
40
41namespace {
42
43template<typename T>
44std::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
66template<>
67std::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
91static 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
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
T accumulate(T... args)
T at(T... args)
T begin(T... args)
void outputSource(const SourceInterface &source) override
std::map< std::string, MetadataEntry > m_image_metadata
Definition LdacOutput.h:42
std::shared_ptr< Euclid::Table::FitsWriter > m_fits_writer
Definition LdacOutput.h:40
void outputSource(const SourceInterface &source) override
DetectionImage::PixelType m_rms
Definition LdacOutput.h:43
The SourceInterface is an abstract "source" that has properties attached to it.
const PropertyType & getProperty(unsigned int index=0) const
Convenience template method to call getProperty() with a more user-friendly syntax.
T emplace_back(T... args)
T end(T... args)
T scientific(T... args)
T gmtime(T... args)
T left(T... args)
T make_shared(T... args)
T move(T... args)
constexpr double e
std::unique_ptr< T > make_unique(Args &&... args)
T setw(T... args)
T size(T... args)
T str(T... args)
T strftime(T... args)
T substr(T... args)
T time(T... args)