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)