4 #include "boost/iterator/transform_iterator.hpp"
25 struct PersistenceHelper {
51 class SourceFitsWriter :
public io::FitsWriter {
53 explicit SourceFitsWriter(Fits *
fits,
int flags) : io::FitsWriter(
fits, flags) {}
58 void _writeRecord(BaseRecord
const &record)
override;
60 void _finish()
override {
70 Key<int> _footprintKey;
78 "Cannot use a SourceFitsWriter on a non-Source table.");
87 metadata = std::static_pointer_cast<daf::base::PropertyList>(metadata->deepCopy());
89 metadata.
reset(
new daf::base::PropertyList());
97 metadata->set(
"AR_HDU", 3,
98 "HDU (1-indexed) containing the archive index for non-record data (e.g. Footprints)");
99 _outTable->setMetadata(metadata);
100 _outRecord = _outTable->makeRecord();
105 _fits->writeKey(
"AFW_TYPE",
"SOURCE",
"Tells lsst::afw to load this as a Source table.");
108 void SourceFitsWriter::_writeRecord(BaseRecord
const &r) {
109 SourceRecord
const &record =
static_cast<SourceRecord
const &
>(r);
117 int footprintArchiveId =
_archive.put(footprint);
118 _outRecord->
set(_footprintKey, footprintArchiveId);
151 class OldSourceFootprintReader :
public io::FitsColumnReader {
153 static int readSpecialColumn(io::FitsSchemaInputMapper &
mapper, daf::base::PropertyList &metadata,
155 int column = metadata.get(
name, 0);
159 metadata.remove(
name);
166 static void setup(io::FitsSchemaInputMapper &
mapper, daf::base::PropertyList &metadata,
int ioFlags,
167 bool stripMetadata) {
169 reader->_spanCol = readSpecialColumn(
mapper, metadata, stripMetadata,
"SPANCOL");
170 reader->_peakCol = readSpecialColumn(
mapper, metadata, stripMetadata,
"PEAKCOL");
171 reader->_heavyPixCol = readSpecialColumn(
mapper, metadata, stripMetadata,
"HVYPIXCO");
172 reader->_heavyMaskCol = readSpecialColumn(
mapper, metadata, stripMetadata,
"HVYMSKCO");
173 reader->_heavyVarCol = readSpecialColumn(
mapper, metadata, stripMetadata,
"HVYVARCO");
178 reader->_heavyPixCol = -1;
179 reader->_heavyMaskCol = -1;
180 reader->_heavyVarCol = -1;
184 if ((reader->_spanCol >= 0) != (reader->_peakCol >= 0)) {
186 "Corrupted catalog: either both or none of the Footprint Span/Peak columns "
189 if (reader->_spanCol < 0) {
192 if ((reader->_heavyPixCol >= 0) != (reader->_heavyMaskCol >= 0) ||
193 (reader->_heavyPixCol >= 0) != (reader->_heavyVarCol >= 0)) {
195 afw::fits::FitsError,
196 "Corrupted catalog: either all or none of the HeavyFootprint columns must be present.");
198 if (reader->_heavyPixCol >= 0 && reader->_spanCol < 0) {
200 "Corrupted catalog: HeavyFootprint columns with no Span/Peak columns.");
208 SourceRecord &record =
static_cast<SourceRecord &
>(baseRecord);
212 int spanElementCount =
fits.getTableArraySize(
row, _spanCol);
213 int peakElementCount =
fits.getTableArraySize(
row, _peakCol);
214 if (spanElementCount) {
215 if (spanElementCount % 3) {
217 afw::fits::FitsError,
220 boost::format(
"Number of span elements (%d) must divisible by 3 (row %d)") %
221 spanElementCount %
row));
224 fits.readTableArray(
row, _spanCol, spanElementCount, &spanElements.front());
226 while (j != spanElements.end()) {
234 std::make_shared<geom::SpanSet>(
std::move(spansVector)));
235 if (peakElementCount) {
236 if (peakElementCount % 3) {
238 afw::fits::FitsError,
241 boost::format(
"Number of peak elements (%d) must divisible by 3 (row %d)") %
242 peakElementCount %
row));
245 fits.readTableArray(
row, _peakCol, peakElementCount, &peakElements.front());
247 while (j != peakElements.end()) {
251 fp->addPeak(
x,
y, value);
254 record.setFootprint(fp);
257 if (_heavyPixCol < 0) {
260 int heavyPixElementCount =
fits.getTableArraySize(
row, _heavyPixCol);
261 int heavyMaskElementCount =
fits.getTableArraySize(
row, _heavyMaskCol);
262 int heavyVarElementCount =
fits.getTableArraySize(
row, _heavyVarCol);
263 if (heavyPixElementCount > 0) {
264 int N = fp->getArea();
265 if ((heavyPixElementCount != N) || (heavyMaskElementCount != N) || (heavyVarElementCount != N)) {
267 afw::fits::FitsError,
270 boost::format(
"Number of HeavyFootprint elements (pix %d, mask %d, var %d) "
271 "must all be equal to footprint area (%d)") %
272 heavyPixElementCount % heavyMaskElementCount % heavyVarElementCount %
276 typedef detection::HeavyFootprint<float, image::MaskPixel, image::VariancePixel> HeavyFootprint;
278 fits.readTableArray(
row, _heavyPixCol, N, heavy->getImageArray().getData());
279 fits.readTableArray(
row, _heavyMaskCol, N, heavy->getMaskArray().getData());
280 fits.readTableArray(
row, _heavyVarCol, N, heavy->getVarianceArray().getData());
281 record.setFootprint(heavy);
294 class SourceFootprintReader :
public io::FitsColumnReader {
296 static void setup(io::FitsSchemaInputMapper &
mapper,
int ioFlags) {
297 auto item =
mapper.find(
"footprint");
299 if (
mapper.hasArchive()) {
308 SourceFootprintReader(
bool noHeavy,
int column) : _noHeavy(noHeavy), _column(column) {}
313 fits.readTableScalar<
int>(
row, _column,
id);
315 if (_noHeavy && footprint->isHeavy()) {
325 footprint.reset(
new Footprint(*footprint));
327 static_cast<SourceRecord &
>(record).setFootprint(footprint);
335 class SourceFitsReader :
public io::FitsReader {
337 SourceFitsReader() :
afw::table::io::FitsReader(
"SOURCE") {}
341 bool stripMetadata)
const override {
345 OldSourceFootprintReader::setup(
mapper, *metadata, ioFlags, stripMetadata);
348 SourceFootprintReader::setup(
mapper, ioFlags);
350 table->setMetadata(metadata);
358 static SourceFitsReader
const sourceFitsReader;
377 _footprint = s._footprint;
386 "Schema for Source must contain at least the keys defined by getMinimalSchema().");
399 if (alias.
compare(0, 4,
"slot") != 0) {
405 SourceTable::MinimalSchema::MinimalSchema() {
407 parent =
schema.addField<
RecordId>(
"parent",
"unique ID of parent source");
410 SourceTable::MinimalSchema &SourceTable::getMinimalSchema() {
411 static MinimalSchema it;
416 return std::make_shared<SourceFitsWriter>(fitsfile, flags);
424 auto record = constructRecord<SourceRecord>();