Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement PhotoCalib tickets/DM-9192 #195

Merged
merged 3 commits into from Apr 28, 2017
Merged

implement PhotoCalib tickets/DM-9192 #195

merged 3 commits into from Apr 28, 2017

Conversation

parejkoj
Copy link
Contributor

No description provided.

*
* @return The flux in maggies and error (sigma).
*/
std::pair<double, double> countsToMaggies(double counts, double countsSigma,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a "value with error" class? Pair is really not the best API for this.

I won't ask if you really need eight overloads...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pair is basically a python tuple containing two things, right? Other suggestions are welcome.

I'd be happy to flatten the overloads, if someone has a suggestion of how. About half of these are already used somewhere in the stack, the others (e.g. SourceRecord or SourceCatalog) are ones we know we want to use.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pair is a bit generic, and it can be hard to remember what the first and second elements are after it's been passed around some. But the appropriateness/inappropriateness of tuples as return types is a controversial subject, so I won't belabor the point.

I'll have to think about the overloads; part of the problem is that apart from Point vs. average I don't see much of a pattern to them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe when I've got some more of the unittest written the use cases will be clearer?

@parejkoj parejkoj force-pushed the tickets/DM-9192 branch 6 times, most recently from 70b9062 to 862e6bb Compare April 8, 2017 23:18
return instance;
}

PersistenceHelper(int tableVersion=PHOTOCALIB_TABLE_CURRENT_VERSION) :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realise the tableVersion is just here to provide for future evolution, but I'm unclear how it's supposed to work, in particular in relation to the get() above with its static instance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Per my comment on JIRA) could this be private?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Table version has been removed after discussion with @TallJimbo who said that we typically only do that when it becomes necessary. That may not be optimal, but then I can also wait and see if we implement a more persistence versioning generic system in the future.

field = schema.addField<int>("field", "archive ID of the BoundedField object");
}

PersistenceHelper(table::Schema const & s) :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? Could you just use PersistenceHelper::get()? Is the idea to support future evolution? If so, could you use get() in conjunction with a tableVersion derived from the table you're reading?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly stole all of this code from @r-owen 's VisitInfo implementation. I don't know what best practices for persistence are, at all. Do we have any guide on the topic?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most useful document I found was https://github.com/lsst/afw/blob/master/doc/tablePersistence.dox, which (for reasons I've not had chance to investigate) doesn't actually seem to be being published by Doxygen. It's by no means a complete reference though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jdswinbank it's published at https://lsst-web.ncsa.illinois.edu/doxygen/x_masterDoxyDoc/afw_table_persistence.html. Maybe a cross-reference needs to be added from the persistence classes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DM-10265.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched to using the get(), removed the schema-based constructor, and made the empty constructor private.

@@ -381,7 +381,7 @@ class ChebyshevBoundedFieldFactory : public table::io::PersistableFactory {
LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
table::BaseRecord const & record = catalogs.front().front();
PersistenceHelper const keys(record.getSchema());
geom::Box2I bbox(record.get(keys.bboxMin), record.get(keys.bboxMax));
geom::Box2I bbox(record.get(keys.bboxMin), record.get(keys.bboxMax), false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is (I assume) what the commit message refers to as

Fix to ChebyshevBF when persisting empty BBox, with test

I think it'd be nice to add a note explaining what the issue was (to the code and/or the commit message), and citing RFC-324.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Nice catch, by the way)

auto& rhsCasted = dynamic_cast<ChebyshevBoundedField const&>(rhs);
bool coefficientsEqual = _coefficients.getShape() == rhsCasted._coefficients.getShape() &&
all(equal(_coefficients, rhsCasted._coefficients));
return getBBox() == rhsCasted.getBBox() && coefficientsEqual;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I'd find that easier to read with some parentheses. I realise that the coding standards might advocate for omitting them, but here I think it's worth the extra visual noise. Your call.

@@ -62,6 +62,7 @@
class ChebyshevBoundedFieldTestCase(lsst.utils.tests.TestCase):

def setUp(self):
self.longMessage = True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn't come across this before. Nice.

countsMag0 = schema.addField<double>("countsMag0", "counts of a zero-magnitude object", "count");
countsMag0Sigma = schema.addField<double>("countsMag0Sigma", "1-sigma error on countsmag0", "count");
isConstant = schema.addField<table::Flag>("isConstant", "Is this spatially-constant?");
field = schema.addField<int>("field", "archive ID of the BoundedField object");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put these in the member initializer list?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again per JIRA, you need to mark the schema as persistent.

(*iter)[1] = toMaggiesSigma(counts, countsSigma, countsMag0, _countsMag0Sigma, maggies);
iter++;
}
if (negatives > 0 && throwOnNegativeFlux) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.

If you are returning a new array (ie, result was created by the immediate caller rather than being passed into it), and throwOnNegativeFlux is true, then after you've thrown nothing is going to get returned. You might as well save time by bailing after the first negative.

If you are not returning a new array, you're going to fill the complete array (with NaNs where you had negative counts), and then throw. The owner of the array will get back the data, but also have to deal with the exception. That's... not unreasonable, but probably deserves documenting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our discussion, I've completely removed the throwOnNegative functionality, thus mooting this question.

(*iter)[1] = toMagnitudeSigma(counts, countsSigma, countsMag0, _countsMag0Sigma, maggies);
iter++;
}
if (negatives > 0 && throwOnNegativeFlux) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above, obviously.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw functionality removed, so moot.

"sourceCatalog"_a, "countsField"_a, "result"_a, "throwOnNegativeCounts"_a=false);

cls.def("countsToMaggies",
(void (PhotoCalib::*)(afw::table::SourceCatalog &, std::string const &, std::string const &, bool) const)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line length.

*
* A PhotoCalib is a BoundedField (a function with a specified domain) that converts between calibrated
* counts-on-chip (ADU) to flux and magnitude. It is defined in terms of "maggies", which are a linear
* unit defined in SDSS: http://www.sdss.org/dr12/algorithms/magnitudes/#nmgy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maggies or nanomaggies?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've defined PhotoCalib in terms of Maggies. I've clarified the docstring here to note that the SDSS link gives the definition in terms of nanomaggies.

@parejkoj
Copy link
Contributor Author

I've renamed things to use "err" and also renamed counts to instFlux.

@parejkoj parejkoj force-pushed the tickets/DM-9192 branch 5 times, most recently from d8e25cf to f13db1e Compare April 28, 2017 00:37
return false;
}
auto rhsCasted = dynamic_cast<ChebyshevBoundedField const *>(&rhs);
if (!rhsCasted) return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the "efficiency" just sidestepping the exception handler, or is there something more subtle going on?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just avoiding (possible) overhead from catch/throw. I'm not sure if the compiler should be able to optimize any of that away in this case, but I'm pretty sure some major ones wouldn't, at least as of a couple of years ago.

Add BoundedField str/repr to pybind11
Fix to ChebyshevBF when persisting empty BBox, with test

Add note about invert bbox on ingest
RFC-322-related code not implemented

Add ticket links and make isConstant a Flag
@parejkoj parejkoj merged commit 4a9eb9b into master Apr 28, 2017
@ktlim ktlim deleted the tickets/DM-9192 branch August 25, 2018 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants