59 namespace extensions {
65 lsst::meas::extensions::psfex::Psf
const&
psf,
73 _poly = poly_copy(
psf.impl->poly);
75 _pixstep =
psf.impl->pixstep;
81 for (
int i = 0; i !=
psf.impl->poly->ndim; ++i) {
82 _context[i].first =
psf.impl->contextoffset[i];
83 _context[i].second =
psf.impl->contextscale[i];
87 PsfexPsf::PsfexPsf() : ImagePsf(),
105 return std::make_shared<PsfexPsf>(*
this);
116 double pos[MAXCONTEXT];
120 str(
boost::format(
"Only spatial variation (ndim == 2) is supported; saw %d")
126 position = _averagePosition;
129 for (
int i = 0; i <
ndim; ++i) {
130 pos[i] = (position[i] - _context[i].first)/_context[i].
second;
133 poly_func(_poly, pos);
135 int const w = _size[0], h = _size[1];
140 const int nbasis = _size.
size() > 2 ? _size[2] : 1;
144 float const vigstep = 1/_pixstep;
145 float const dx = 0.0, dy = 0.0;
150 int sampleW =
bbox.getWidth();
151 int sampleH =
bbox.getHeight();
155 for (
int i = 0; i != nbasis; ++i) {
159 vignet_resample(
const_cast<float *
>(&_comp[i*
w*h]),
w, h,
160 &sampledBasis[0], sampleW, sampleH,
161 -dx*vigstep, -dy*vigstep, vigstep, 1.0);
166 float *pl = &sampledBasis[0];
167 for (
int y = 0;
y != sampleH; ++
y) {
168 for (
int x = 0;
x != sampleW; ++
x) {
174 kernels.
push_back(std::make_shared<afw::math::FixedKernel>(kim));
178 _kernel = std::make_shared<afw::math::LinearCombinationKernel>(kernels, weights);
190 PsfexPsf::doComputeKernelImage(
geom::Point2D const& position,
203 int const w = _size[0], h = _size[1];
204 int sampleW =
static_cast<int>(
w*_pixstep);
205 int sampleH =
static_cast<int>(h*_pixstep);
208 if (sampleW % 2 == 0) sampleW += 1;
209 if (sampleH % 2 == 0) sampleH += 1;
211 float dx = center[0] -
static_cast<int>(center[0]);
212 float dy = center[1] -
static_cast<int>(center[1]);
214 if (dx > 0.5) dx -= 1.0;
215 if (dy > 0.5) dy -= 1.0;
219 static_cast<int>(center[1] - dy + 0.5) - sampleH/2),
230 double pos[MAXCONTEXT];
234 str(
boost::format(
"Only spatial variation (ndim == 2) is supported; saw %d")
239 for (
int i = 0; i <
ndim; ++i) {
240 pos[i] = (position[i] - _context[i].first)/_context[i].
second;
243 poly_func(_poly, pos);
245 int const w = _size[0], h = _size[1];
247 const int nbasis = _size.
size() > 2 ? _size[2] : 1;
250 int const npix =
w*h;
251 for (
int i = 0; i != nbasis; ++i) {
252 float *pl = &fullresIm[0];
253 float const fac = _poly->basis[i];
254 float const *ppc = &_comp[i*
w*h];
256 for (
int j = 0; j != npix; ++j) {
264 float const vigstep = 1/_pixstep;
265 float dx = center[0] -
static_cast<int>(center[0]);
266 float dy = center[1] -
static_cast<int>(center[1]);
267 if (dx > 0.5) dx -= 1.0;
268 if (dy > 0.5) dy -= 1.0;
275 int sampleW =
bbox.getWidth();
276 int sampleH =
bbox.getHeight();
280 vignet_resample(&fullresIm[0],
w, h,
281 &sampledIm[0], sampleW, sampleH,
282 -dx*vigstep, -dy*vigstep, vigstep, 1.0);
284 float *pl = &sampledIm[0];
285 float const sum =
std::accumulate(pl, pl + sampleW*sampleH,
static_cast<float>(0));
286 for (
int y = 0;
y != sampleH; ++
y) {
287 for (
int x = 0;
x != sampleW; ++
x) {
288 (*im)(
x,
y) = *pl++/sum;
300 namespace table = afw::table;
304 class PsfexPsfSchema1 {
308 ndim(
schema.addField<int>(
"ndim",
"Number of elements in group")),
309 ngroup(
schema.addField<int>(
"ngroup",
"Number of elements in degree")),
310 ncoeff(
schema.addField<int>(
"ncoeff",
"Number of coefficients")),
316 averagePosition(
afw::table::PointKey<double>::addFields(
schema,
"averagePosition",
"average position of stars used to make the PSF",
"pixel")),
317 _pixstep(
schema.addField<float>(
"_pixstep",
"oversampling",
"pixel"))
337 class PsfexPsfSchema2 {
340 int size_size,
int comp_size,
int context_size) :
343 group(
schema.addField<table::Array<int> >(
"group",
"Groups (of coefficients?)",
ndim)),
344 degree(
schema.addField<table::Array<int> >(
"degree",
"Degree in each group",
ngroup)),
345 basis(
schema.addField<table::Array<double> >(
"basis",
"Values of the basis functions",
ncoeff)),
346 coeff(
schema.addField<table::Array<double> >(
"coeff",
"Polynomial coefficients",
ncoeff)),
347 _size(
schema.addField<table::Array<int> >(
"_size",
"PSF dimensions", size_size)),
348 _comp(
schema.addField<table::Array<float> >(
"_comp",
"Complete pixel data", comp_size)),
350 "Offset to apply to context data", context_size)),
352 "Scale to apply to context data", context_size))
359 table::Key<table::Array<int> >
group;
361 table::Key<table::Array<double> >
basis;
362 table::Key<table::Array<double> >
coeff;
364 table::Key<table::Array<int> >
_size;
365 table::Key<table::Array<float> >
_comp;
370 std::string getPsfexPsfPersistenceName() {
return "PsfexPsf"; }
381 read(InputArchive
const & archive, CatalogVector
const & catalogs)
const {
387 int size_size, comp_size, context_size;
389 PsfexPsfSchema1
const &
keys = PsfexPsfSchema1();
402 size_size = record.
get(
keys._size_size);
403 comp_size = record.
get(
keys._comp_size);
404 context_size = record.
get(
keys._context_size);
409 size_size, comp_size, context_size);
421 for (
int i = 0; i !=
ndim; ++i) {
444 result->_size.assign(begin, begin + size_size);
448 result->_comp.assign(begin, begin + comp_size);
453 result->_context.resize(context_size);
454 for (
int i = 0; i != context_size; ++i) {
455 result->_context[i].first = begin1[i];
456 result->_context[i].second = begin2[i];
470 detail::PsfexPsfFactory registration(getPsfexPsfPersistenceName());
475 std::string PsfexPsf::getPythonModule()
const {
return "lsst.meas.extensions.psfex"; }
477 std::string PsfexPsf::getPersistenceName()
const {
return getPsfexPsfPersistenceName(); }
483 PsfexPsfSchema1
const keys;
488 record->set(
keys.ndim, _poly->ndim);
489 record->set(
keys.ngroup, _poly->ngroup);
490 record->set(
keys.ncoeff, _poly->ncoeff);
492 record->set(
keys.averagePosition, _averagePosition);
493 record->set(
keys._pixstep, _pixstep);
494 record->set(
keys._size_size, _size.
size());
495 record->set(
keys._comp_size, _comp.
size());
496 record->set(
keys._context_size, _context.
size());
502 PsfexPsfSchema2
const keys(_poly->ndim, _poly->ngroup, _poly->ncoeff,
508 int *begin = record->getElement(
keys.group);
509 std::copy(_poly->group, _poly->group + _poly->ndim, begin);
512 int *begin = record->getElement(
keys.degree);
513 std::copy(_poly->degree, _poly->degree + _poly->ngroup, begin);
516 double *begin = record->getElement(
keys.basis);
517 std::copy(_poly->basis, _poly->basis + _poly->ncoeff, begin);
520 double *begin = record->getElement(
keys.coeff);
521 std::copy(_poly->coeff, _poly->coeff + _poly->ncoeff, begin);
525 int *begin = record->getElement(
keys._size);
529 float *begin = record->getElement(
keys._comp);
533 double *begin1 = record->getElement(
keys._context_first);
534 double *begin2 = record->getElement(
keys._context_second);
535 for (
unsigned int i = 0; i != _context.
size(); ++i) {
536 begin1[i] = _context[i].first;
537 begin2[i] = _context[i].second;
table::Key< std::string > name
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Utilities for persisting KernelPsf and subclasses thereof.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Describe the colour of a source.
Base class for all records.
Field< T >::Element * getElement(Key< T > const &key)
Return a pointer to the underlying elements of a field (non-const).
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
An object passed to Persistable::write to allow it to persist itself.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
An integer coordinate rectangle.
Represent a PSF as a linear combination of PSFEX (== Karhunen-Loeve) basis functions.
std::shared_ptr< lsst::afw::math::LinearCombinationKernel const > getKernel(lsst::geom::Point2D=lsst::geom::Point2D(std::numeric_limits< double >::quiet_NaN())) const
Return the PSF's basis functions as a spatially-invariant LinearCombinationKernel with unit weights.
void write(lsst::afw::table::io::OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
std::shared_ptr< lsst::afw::detection::Psf > clone() const override
Polymorphic deep copy; should usually be unnecessary as Psfs are immutable.x.
virtual std::shared_ptr< lsst::afw::detection::Psf::Image > _doComputeImage(lsst::geom::Point2D const &position, lsst::afw::image::Color const &color, lsst::geom::Point2D const ¢er) const
Compute an image of the Psf at the specified position/colour, at pixel position in the output image.
std::shared_ptr< afw::detection::Psf > resized(int width, int height) const override
Return a clone with specified kernel dimensions.
PsfexPsfFactory(std::string const &name)
virtual std::shared_ptr< table::io::Persistable > read(InputArchive const &archive, CatalogVector const &catalogs) const
Reports invalid arguments.
Reports errors in the logical structure of the program.
Low-level polynomials (including special polynomials) in C++.
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
A base class for image defects.
table::Key< int > _context_size
table::Key< table::Array< int > > _size
table::Key< table::Array< int > > degree
table::PointKey< double > averagePosition
table::Key< table::Array< float > > _comp
table::Key< float > _pixstep
table::Key< table::Array< double > > _context_first
table::Key< table::Array< double > > coeff
table::Key< table::Array< double > > basis
table::Key< table::Array< double > > _context_second
table::Key< table::Array< int > > group
table::Key< int > _comp_size
table::Key< int > _size_size