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

DM-23044: PTC task should persist usable linearity models #29

Merged
merged 28 commits into from Apr 7, 2020

Conversation

plazas
Copy link
Contributor

@plazas plazas commented Mar 28, 2020

No description provided.

@plazas plazas requested a review from timj March 28, 2020 17:13
Copy link
Member

@timj timj left a comment

Choose a reason for hiding this comment

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

I have quite a few questions and comments. Some of my questions are my lack of understanding of what Linearizer does.

now = datetime.datetime.utcnow()
butler = dataRef.getButler()

for linPair in [("LOOKUPTABLE", 'linearizeLut'), ("LINEARIZEPOLYNOMIAL", 'linearizePolynomial'),
Copy link
Member

Choose a reason for hiding this comment

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

change this to

for linType, dataType in [("LOOKUPTABLE", 'linearizeLut'), ("LINEARIZEPOLYNOMIAL", 'linearizePolynomial')]:

instruName=self.config.instrumentName,
linearizerType=linType, tableArray=tableArray,
log=self.log)
butler.put(linearizer.toDict(), datasetType=dataType, dataId={'detector': detNum,
Copy link
Member

Choose a reason for hiding this comment

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

Why are we putting a dict here and not the actual linearizer object? I don't really understand gen2 so maybe I'm getting confused but shouldn't it be able to take a special object?

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 tried getting rid of "toDict" and it did not work properly. It seems that gen2 butler expects a dict.

Copy link
Member

Choose a reason for hiding this comment

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

You would need to teach it to do the right thing like we taught butler to understand that Defects can be put.

Copy link
Member

Choose a reason for hiding this comment

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

I see that cp_pipe doesn't use the butler for defects but does try to use the butler for ptc. I think that explains why Butler.put has not been set up for Defects. It should be simple for Linearizer to have the dataset type added to gen2 butler since it emulates a normal Catalog by supporting writeFits.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the linearizer should be treated like a fits catalog and written as a fits catalog? Should not they be human-readable?

Copy link
Member

Choose a reason for hiding this comment

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

You are putting them into a butler so the format does not have to be the same as the format you use in obs_lsst_data. If you have been copying the files out of the butler manually then that would make a difference (otherwise you'd need a quick readFits/writeText copy-like command). I don't know how easy it is to add a new formatter in gen2 that would call writeText directly so maybe it's not going to be possible to do this in gen2 properly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At this moment I don't know either how easy what you describe would be. Could this be left for a future ticket, if necessary?

Detector object
instruName : `str`, optional
Instrument name
linearizerType : `str`, optional
Copy link
Member

Choose a reason for hiding this comment

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

Given that you default linearizerType argument to an empty string and then raise an exception if you give an empty string, doesn't that mean that the parameter is not optional at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I set "LINEARIZEPOLYNOMIAL" as default.

Copy link
Member

Choose a reason for hiding this comment

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

Is that a safe default to use? Are you better off always being explicit?

Detector name
detNum : `int`
Detector number
detector : `lsst.afw.cameraGeom.detector.detector.Detector`
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be lsst.afw.cameraGeom.Detector

Copy link
Member

Choose a reason for hiding this comment

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

Also, don't pass in detNum and detName if you are already passing in the entire detector object. Calculate what you need directly in this method.

----------
dataset : `lsst.cp.pipe.ptc.PhotonTransferCurveDataset`
The dataset containing the means, variances and exposure times
detName : `srt`
Copy link
Member

Choose a reason for hiding this comment

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

str not srt.

linearizer = Linearizer(table=tableArray, log=log)
else:
raise RuntimeError("tableArray must be provided when creating a LookupTable linearizer")
elif linearizerType in ['LINEARIZESQUARED', 'LINEARIZEPOLYNOMIAL']:
Copy link
Member

Choose a reason for hiding this comment

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

In general using a list for a readonly sequence seems odd to me and a tuple might be better. Also be consistent with quote type. You mostly seem to use double quotes so use them everywhere.

ampName = amp.getName()
if linearizerType == 'LOOKUPTABLE':
linearizer.linearityCoeffs[ampName] = [i, 0]
linearizer.linearityType[ampName] = "LookupTable"
Copy link
Member

Choose a reason for hiding this comment

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

A way to remove the linearity type from the if clauses would be to define the mapping in a dict:

linearityType = {"LOOKUPTABLE": "LookupTable", "LINEARIZESQUARED": "Squared"}
for ... in ...:
    linearizer.linearityType[ampName] = linearityType[linearizerType]

Saying that, why do you need to tell the Linearizer object what each amp is when it seems to be a constant? Am I seeing a special case here or is it always true that every amp has the same type? Could you instead have Linearizer subclasses that have their type defined for them like @SimonKrughoff did for the Curve class? Maybe @czwa can tell me. Of course if each amp can have different types then that would explain this but the code here doesn't allow that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Having this be amplifier based instead of detector (or camera) based is a result of directly mapping the cameraGeom linearity parameters to the new Linearizer. I also didn't want to prevent different amplifiers from having different correction types (because electronics can always be difficult in unique ways).

Copy link
Member

Choose a reason for hiding this comment

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

So this means that Linearizer can support per-amp but this cp_pipe task can't. Can this be mentioned somewhere in the task docstring?

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 left the "if" clauses because there are other things specific to each linearizer type that are being set. I added clarification regarding the linearizers in the doc-string of "MeasurePhotonTransferCurveTask".

meanSignalVector = k0 + k1*exposureTimeVector + k2*exposureTimeVector^2 +...
+ kn*exposureTimeVector^n, with n = "polynomialFitDegreeNonLinearity".

linearizerTableRow: list of `np.float`
linearizerTableRow : list of `np.float`
Copy link
Member

Choose a reason for hiding this comment

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

Use back ticks. I think np.float and float are interchangeable so do they really need to be numpy floats?

@@ -623,55 +735,76 @@ def calculateLinearityResidualAndLinearizers(self, exposureTimeVector, meanSigna

Returns
-------
c0: `np.float`
polynomialLinearizerCoefficients : `list` of `np.float`
Copy link
Member

Choose a reason for hiding this comment

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

Do not use np abbreviation in docstrings. numpy.float should be used. Why is this a list of individual numpy floats and not a single numpy array? (and also float and numpy.float should be identical from your point of view shouldn't they?)

if ptcFitType == 'ASTIERAPPROXIMATION':
ptcFunc = self.funcAstier
stringTitle = r"Var = $\frac{1}{2g^2a_{00}}(\exp (2a_{00} \mu g) - 1) + \frac{n_{00}}{g^2}$"

stringTitle = (r"Var = $\frac{1}{2g^2a_{00}}(\exp (2a_{00} \mu g) - 1) + \frac{n_{00}}{g^2}$ " +
Copy link
Member

Choose a reason for hiding this comment

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

Do not use a plus to concatenate. It's not needed.

"""
if linearizerType == 'LOOKUPTABLE':
if tableArray is not None:
linearizer = Linearizer(table=tableArray, log=log)
Copy link
Member

Choose a reason for hiding this comment

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

Would it help if the detector argument was passed in here?

@plazas plazas merged commit 57ef05f into master Apr 7, 2020
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

3 participants