4#include "boost/format.hpp"
25struct PersistenceHelper {
27 afw::table::Key<int> footprintKey;
53 explicit SourceFitsWriter(Fits *fits,
int flags) : io::FitsWriter(fits,
flags) {}
56 void _writeTable(std::shared_ptr<BaseTable const>
const &table,
std::size_t nRows)
override;
58 void _writeRecord(BaseRecord
const &record)
override;
60 void _finish()
override {
62 _archive.writeFits(*_fits);
68 std::shared_ptr<BaseRecord> _outRecord;
69 std::shared_ptr<BaseTable> _outTable;
70 Key<int> _footprintKey;
71 io::OutputArchive _archive;
74void SourceFitsWriter::_writeTable(std::shared_ptr<BaseTable const>
const &t,
std::size_t nRows) {
77 throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
78 "Cannot use a SourceFitsWriter on a non-Source table.");
80 if (!(_flags & SOURCE_IO_NO_FOOTPRINTS)) {
81 _mapper = SchemaMapper(t->getSchema(),
true);
85 std::shared_ptr<daf::base::PropertyList> metadata = table->getMetadata();
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();
101 io::FitsWriter::_writeTable(_outTable, nRows);
103 io::FitsWriter::_writeTable(table, nRows);
105 _fits->writeKey(
"AFW_TYPE",
"SOURCE",
"Tells lsst::afw to load this as a Source table.");
108void SourceFitsWriter::_writeRecord(BaseRecord
const &r) {
109 SourceRecord
const &record =
static_cast<SourceRecord
const &
>(
r);
110 if (!(_flags & SOURCE_IO_NO_FOOTPRINTS)) {
111 _outRecord->assign(record, _mapper);
112 std::shared_ptr<afw::detection::Footprint> footprint = record.getFootprint();
114 if ((_flags & SOURCE_IO_NO_HEAVY_FOOTPRINTS) && footprint->isHeavy()) {
115 footprint.
reset(
new afw::detection::Footprint(*footprint));
117 int footprintArchiveId = _archive.
put(footprint);
118 _outRecord->set(_footprintKey, footprintArchiveId);
120 io::FitsWriter::_writeRecord(*_outRecord);
122 io::FitsWriter::_writeRecord(record);
151class OldSourceFootprintReader :
public io::FitsColumnReader {
153 static int readSpecialColumn(io::FitsSchemaInputMapper &mapper, daf::base::PropertyList &metadata,
154 bool stripMetadata, std::string
const &name) {
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) {
168 std::unique_ptr<OldSourceFootprintReader> reader(
new OldSourceFootprintReader());
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");
174 if ((ioFlags & SOURCE_IO_NO_FOOTPRINTS) || mapper.hasArchive()) {
177 if (ioFlags & SOURCE_IO_NO_HEAVY_FOOTPRINTS) {
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.");
206 void readCell(BaseRecord &baseRecord,
std::size_t row, fits::Fits &fits,
207 std::shared_ptr<io::InputArchive>
const &archive)
const override {
208 SourceRecord &record =
static_cast<SourceRecord &
>(baseRecord);
209 std::vector<geom::Span> spansVector;
212 std::size_t spanElementCount = fits.getTableArraySize(row, _spanCol);
213 std::size_t peakElementCount = fits.getTableArraySize(row, _peakCol);
214 if (spanElementCount) {
215 if (spanElementCount % 3) {
217 afw::fits::FitsError,
218 afw::fits::makeErrorMessage(
219 fits.fptr, fits.status,
220 boost::format(
"Number of span elements (%d) must divisible by 3 (row %d)") %
221 spanElementCount % row));
223 std::vector<int> spanElements(spanElementCount);
224 fits.readTableArray(row, _spanCol, spanElementCount, &spanElements.front());
225 std::vector<int>::iterator j = spanElements.begin();
226 while (j != spanElements.end()) {
235 if (peakElementCount) {
236 if (peakElementCount % 3) {
238 afw::fits::FitsError,
239 afw::fits::makeErrorMessage(
240 fits.fptr, fits.status,
241 boost::format(
"Number of peak elements (%d) must divisible by 3 (row %d)") %
242 peakElementCount % row));
244 std::vector<float> peakElements(peakElementCount);
245 fits.readTableArray(row, _peakCol, peakElementCount, &peakElements.front());
246 std::vector<float>::iterator j = peakElements.begin();
247 while (j != peakElements.end()) {
251 fp->addPeak(x, y, value);
254 record.setFootprint(fp);
257 if (_heavyPixCol < 0) {
260 std::size_t heavyPixElementCount = fits.getTableArraySize(row, _heavyPixCol);
261 std::size_t heavyMaskElementCount = fits.getTableArraySize(row, _heavyMaskCol);
262 std::size_t heavyVarElementCount = fits.getTableArraySize(row, _heavyVarCol);
263 if (heavyPixElementCount > 0) {
265 if ((heavyPixElementCount != N) || (heavyMaskElementCount != N) || (heavyVarElementCount != N)) {
267 afw::fits::FitsError,
268 afw::fits::makeErrorMessage(
269 fits.fptr, fits.status,
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 using HeavyFootprint = detection::HeavyFootprint<float>;
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);
294class SourceFootprintReader :
public io::FitsColumnReader {
296 static void setup(io::FitsSchemaInputMapper &mapper,
int ioFlags) {
297 auto item = mapper.find(
"footprint");
299 if (mapper.hasArchive()) {
300 std::unique_ptr<io::FitsColumnReader> reader(
301 new SourceFootprintReader(ioFlags & SOURCE_IO_NO_HEAVY_FOOTPRINTS, item->column));
308 SourceFootprintReader(
bool noHeavy,
int column) : _noHeavy(noHeavy), _column(column) {}
310 void readCell(BaseRecord &record,
std::size_t row, fits::Fits &fits,
311 std::shared_ptr<io::InputArchive>
const &archive)
const override {
313 fits.readTableScalar<
int>(row, _column, id);
314 std::shared_ptr<Footprint> footprint = archive->
get<
Footprint>(id);
315 if (_noHeavy && footprint->isHeavy()) {
325 footprint.reset(
new Footprint(*footprint));
327 static_cast<SourceRecord &
>(record).setFootprint(footprint);
335class SourceFitsReader :
public io::FitsReader {
337 SourceFitsReader() : afw::table::io::FitsReader(
"SOURCE") {}
339 std::shared_ptr<BaseTable> makeTable(io::FitsSchemaInputMapper &mapper,
340 std::shared_ptr<daf::base::PropertyList> metadata,
int ioFlags,
341 bool stripMetadata)
const override {
345 OldSourceFootprintReader::setup(mapper, *metadata, ioFlags, stripMetadata);
348 SourceFootprintReader::setup(mapper, ioFlags);
349 std::shared_ptr<SourceTable> table = SourceTable::make(mapper.finalize());
350 table->setMetadata(metadata);
358static SourceFitsReader
const sourceFitsReader;
371 if (include_covariance) {
376 set(coordErrKey, skyCov);
383 if (include_covariance) {
388 set(coordErrKey, skyCov);
395 _footprint = s._footprint;
404 "Schema for Source must contain at least the keys defined by getMinimalSchema().");
407 table->getSchema().getAliasMap()->setTable(
table);
412 :
SimpleTable(schema, idFactory), _slots(schema) {}
417 if (alias.
compare(0, 4,
"slot") != 0) {
420 _slots.handleAliasChange(alias,
getSchema());
423SourceTable::MinimalSchema::MinimalSchema() {
428SourceTable::MinimalSchema &SourceTable::getMinimalSchema() {
429 static MinimalSchema it;
439 table->getSchema().getAliasMap()->setTable(
table);
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Base class for all records.
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Schema getSchema() const
Return the Schema that holds this record's fields and keys.
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
std::shared_ptr< RecordT > constructRecord(Args &&... args)
Helper function that must be used by all _makeRecord overrides to actually construct records.
Schema getSchema() const
Return the table's schema.
A custom container class for records, based on std::vector.
CovarianceMatrixKey< float, 2 > ErrorKey
static ErrorKey getErrorKey(Schema const &schema)
A FunctorKey used to get or set a lsst::geom::Point from an (x,y) pair of int or double Keys.
Defines the fields and offsets for a table.
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
Schema const getOutputSchema() const
Return the output schema (copy-on-write).
Schema & editOutputSchema()
Return a reference to the output schema that allows it to be modified in place.
void addMinimalSchema(Schema const &minimal, bool doMap=true)
Add the given minimal schema to the output schema.
void setCoord(lsst::geom::SpherePoint const &coord)
static Schema makeMinimalSchema()
Return a minimal schema for Simple tables and records.
std::shared_ptr< IdFactory > getIdFactory()
Return the object that generates IDs for the table (may be null).
SimpleTable(Schema const &schema, std::shared_ptr< IdFactory > const &idFactory)
Custom catalog class for record/table subclasses that are guaranteed to have an ID,...
virtual void _assign(BaseRecord const &other)
Called by assign() after transferring fields to allow subclass data members to be copied.
CentroidSlotDefinition::MeasValue getCentroid() const
Get the value of the Centroid slot measurement.
CentroidSlotDefinition::ErrValue getCentroidErr() const
Get the uncertainty on the Centroid slot measurement.
SourceRecord(ConstructionToken const &token, detail::RecordData &&data)
Constructor used by SourceTable.
void updateCoord(geom::SkyWcs const &wcs, bool include_covariance=true)
Update the coord field using the given Wcs and the field in the centroid slot.
Table class that contains measurements made on a single exposure.
static std::shared_ptr< SourceTable > make(Schema const &schema, std::shared_ptr< IdFactory > const &idFactory)
Construct a new table.
SourceTable(Schema const &schema, std::shared_ptr< IdFactory > const &idFactory)
std::shared_ptr< BaseRecord > _makeRecord() override
Default-construct an associated record (protected implementation).
std::shared_ptr< io::FitsWriter > makeFitsWriter(fits::Fits *fitsfile, int flags) const override
std::shared_ptr< BaseTable > _clone() const override
Clone implementation with noncovariant return types.
void handleAliasChange(std::string const &alias) override
static bool checkSchema(Schema const &other)
Return true if the given schema is a valid SourceTable schema.
Writer object for FITS binary tables.
int put(std::shared_ptr< Persistable const > obj, bool permissive=false)
Save an object to the archive and return a unique ID that can be used to retrieve it from an InputArc...
Reports invalid arguments.
T emplace_back(T... args)
lsst::afw::detection::Footprint Footprint
Eigen::Matrix2f calculateCoordCovariance(geom::SkyWcs const &wcs, lsst::geom::Point2D center, Eigen::Matrix2f err)
Calculate covariance for sky coordinates.
@ SOURCE_IO_NO_FOOTPRINTS
Do not read/write footprints at all.
std::int64_t RecordId
Type used for unique IDs for records.
Point< double, 2 > Point2D
decltype(sizeof(void *)) size_t
T dynamic_pointer_cast(T... args)