Skip to content

Commit

Permalink
Change TransformBoundedField table persistence
Browse files Browse the repository at this point in the history
from using a variable-length string field to a variable-length
array of uint8 encoding the transform's string representation.
Update the test_transformBoundedField to torture-test that
on a transform with a long string representation.
  • Loading branch information
r-owen committed Sep 30, 2017
1 parent 3d1d310 commit 490acaa
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
13 changes: 8 additions & 5 deletions src/math/TransformBoundedField.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
* see <http://www.lsstcorp.org/LegalNotices/>.
*/

#include <cstdint>
#include <memory>
#include <string>

#include "ndarray/eigen.h"
#include "astshim.h"
#include "lsst/afw/formatters/Utils.h"
#include "lsst/afw/math/TransformBoundedField.h"
#include "lsst/afw/table/io/InputArchive.h"
#include "lsst/afw/table/io/OutputArchive.h"
Expand Down Expand Up @@ -81,16 +83,17 @@ struct PersistenceHelper {
table::Schema schema;
table::PointKey<int> bboxMin;
table::PointKey<int> bboxMax;
table::Key<std::string> frameSet;
// store the FrameSet as string encoded as a variable-length vector of bytes
table::Key<table::Array<std::uint8_t>> frameSet;

PersistenceHelper()
: schema(),
bboxMin(table::PointKey<int>::addFields(schema, "bbox_min", "lower-left corner of bounding box",
"pixel")),
bboxMax(table::PointKey<int>::addFields(schema, "bbox_max",
"upper-right corner of bounding box", "pixel")),
frameSet(schema.addField<std::string>("frameSet", "FrameSet contained in the Transform", 0,
false)) {}
frameSet(schema.addField<table::Array<std::uint8_t>>(
"frameSet", "FrameSet contained in the Transform", "", 0)) {}

PersistenceHelper(table::Schema const& s)
: schema(s), bboxMin(s["bbox_min"]), bboxMax(s["bbox_max"]), frameSet(s["frameSet"]) {}
Expand All @@ -109,7 +112,7 @@ class TransformBoundedFieldFactory : public table::io::PersistableFactory {
PersistenceHelper const keys(record.getSchema());
// NOTE: needed invert=false in case min=-1, max=0 (empty bbox). See RFC-324 and DM-10200
geom::Box2I bbox(record.get(keys.bboxMin), record.get(keys.bboxMax), false);
auto frameSetStr = record.get(keys.frameSet);
auto frameSetStr = formatters::bytesToString(record.get(keys.frameSet));
auto transform =
geom::Transform<geom::Point2Endpoint, geom::GenericEndpoint>::readString(frameSetStr);
return std::make_shared<TransformBoundedField>(bbox, transform);
Expand All @@ -134,7 +137,7 @@ void TransformBoundedField::write(OutputArchiveHandle& handle) const {
std::shared_ptr<table::BaseRecord> record = catalog.addNew();
record->set(keys.bboxMin, getBBox().getMin());
record->set(keys.bboxMax, getBBox().getMax());
record->set(keys.frameSet, getTransform().writeString());
record->set(keys.frameSet, formatters::stringToBytes(getTransform().writeString()));
handle.saveCatalog(catalog);
}

Expand Down
36 changes: 36 additions & 0 deletions tests/test_transformBoundedField.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,42 @@ def testPersistenceAndEquality(self):
assert_allclose(resArr, readResArr)
self.assertEqual(readField.getBBox(), self.bbox)

def testComplexPersistence(self):
"""Test persistence of a TransformBoundedField whose string representation is huge
"""
# DM-11964 shows that CFITSIO cannot handle string fields
# in binary tables that have more than 28799 characters
# make sure the test has plenty of margin
minChars = 10 * 28799
degree = 100 # make large enough that len(transform.writeString()) > minChars
n_coeffs = (degree + 1) * (degree + 2) // 2
coeffs = np.zeros((n_coeffs, 4), dtype=float)
k = 0
for j in range(degree+1):
for i in range(degree-j+1):
coeffs[k][0] = np.random.random()
coeffs[k][1] = 1
coeffs[k][2] = i
coeffs[k][3] = j
k += 1
chebyMap = astshim.PolyMap(coeffs, 1)
transform = lsst.afw.geom.TransformPoint2ToGeneric(chebyMap)
print("nchar=%s; minChar=%s" % (len(transform.writeString()), minChars))
self.assertGreater(len(transform.writeString()), minChars)
complexBoundedField = TransformBoundedField(self.bbox, transform)
with lsst.utils.tests.getTempFilePath(".fits") as filename:
complexBoundedField.writeFits(filename)
readField = TransformBoundedField.readFits(filename)

self.assertTrue(complexBoundedField == readField)
self.assertFalse(complexBoundedField != readField)
self.assertEqual(complexBoundedField, readField)

resArr = complexBoundedField.evaluate(self.xList, self.yList)
readResArr = readField.evaluate(self.xList, self.yList)
assert_allclose(resArr, readResArr)
self.assertEqual(readField.getBBox(), self.bbox)


class MemoryTester(lsst.utils.tests.MemoryTestCase):
pass
Expand Down

0 comments on commit 490acaa

Please sign in to comment.