Skip to content

DM-51599: Run crosstalk on CBP data / update and modernize CT code #355

Open
czwa wants to merge 8 commits intomainfrom
tickets/DM-51599
Open

DM-51599: Run crosstalk on CBP data / update and modernize CT code #355
czwa wants to merge 8 commits intomainfrom
tickets/DM-51599

Conversation

@czwa
Copy link
Contributor

@czwa czwa commented Jan 14, 2026

No description provided.

@czwa czwa requested a review from erykoff January 14, 2026 22:23
Copy link
Contributor

@erykoff erykoff left a comment

Choose a reason for hiding this comment

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

I'm wondering if the units are all necessary, but I do see there are contracts to keep things in sync. I would think it could be inferred from the data though?

cpCrosstalkExtract:
class: lsst.cp.pipe.CrosstalkExtractTask
config:
growMaskRadius: 20
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these just be in the parent cpCrosstalkLSST.yaml? Or these are so specific for the LSSTCam analysis?

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 measured growMaskRadius only on LSSTCam, and I suspect the value for LATISS would be different (but I haven't compared PSF wings between the two).

if np.sum(mask) == 0:
continue

newMask = np.where(np.bitwise_and(mask, detected), maskBit, 0)
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be mask & detected which I find easier to read than np.bitwise_and().

outputFluxes=ddict2dict(outputFluxes)
)

def _flipMask(self, maskArray, sourceAmp, targetAmp):
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we already have this code in ip_isr? Does it need to be rewritten, or can it be reused?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The ip_isr version expects afw objects, and this uses numpy. It was different enough that I thought the copy-rewrite was worth it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you rename this flipMaskArray then?

if config.fluxOrder == 0:
self.inputs.discard("inputFluxes")
# if config.fluxOrder == 0 and False:
# self.inputs.discard("inputFluxes")
Copy link
Contributor

Choose a reason for hiding this comment

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

If these shouldn't be here, please remove.

myfluxes = np.ones_like(values)

if len(values) != len(myfluxes):
self.log.warning(f"Flux and ratio length disagree after first filter: {len(values)} {len(myfluxes)}") # noqa E501
Copy link
Contributor

Choose a reason for hiding this comment

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

self.log.warning(
    f"Flux and ratio length disagree after first filter: {len(values)} {len(myfluxes)}",
)

values = values[good]
myfluxes = myfluxes[good]
if len(values) != len(myfluxes):
self.log.warning(f"Flux and ratio length disagree after second filter: {len(values)} {len(myfluxes)}") # noqa E501
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

# filter those.
pass

itl_c0 = np.array(itl_c0)
Copy link
Contributor

Choose a reason for hiding this comment

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

All np.asarray()


Parameters
----------
matrix0 : `np.array`, (Ndet, Namp, Namp)
Copy link
Contributor

Choose a reason for hiding this comment

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

These are all np.ndarray

@czwa czwa force-pushed the tickets/DM-51599 branch from fe6697e to ce85add Compare January 23, 2026 20:42
)
growMaskRadius = Field(
dtype=int,
default=0,
Copy link
Contributor

Choose a reason for hiding this comment

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

I know you said above that you haven't measured this on anything but LSSTCam with CBP, but I still think having this as something non-zero as the default would make sense. Just set this to 20 here and delete the other overrides and we'll figure it out in the future if we need to?

outputFluxes=ddict2dict(outputFluxes)
)

def _flipMask(self, maskArray, sourceAmp, targetAmp):
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you rename this flipMaskArray then?

dtype=int,
default=0,
doc="Polynomial order in source flux to fit crosstalk.",
doc="Order of source flux fit to crosstalk. 0=simple linear; 1=first order non-linear.",
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm getting confused as to why this isn't 1 and 2. What am I missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the order of the fit done to ratio(source_flux) = target / source_flux. This removes one factor of the source_flux, so a 0-order fit is just a constant crosstalk ratio, and a 1-order fit is a linear fit of an "average" crosstalk ratio with a first-order source_flux correction. I agree the nomenclature is confusing.

values = np.array(ratios[ordering[tt]][ordering[ss]])
values = values[np.abs(values) < 1.0] # Discard unreasonable values
values = np.asarray(ratios[ordering[tt]][ordering[ss]])
good_values = np.abs(values) < 1.0 # Discard unreasonable values
Copy link
Contributor

Choose a reason for hiding this comment

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

What makes this unreasonable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This check is designed to remove ratios that have a target location with an actual star there. This translates to excluding all measured ratios that have absolute value greater than 1, such that target_flux > source_flux.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment this in the code?

@czwa czwa force-pushed the tickets/DM-51599 branch 2 times, most recently from 032d196 to f61fbf3 Compare March 13, 2026 22:52
@czwa czwa force-pushed the tickets/DM-51599 branch from f61fbf3 to ba09639 Compare March 16, 2026 22:27
Copy link
Contributor

@erykoff erykoff left a comment

Choose a reason for hiding this comment

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

A small comment, otherwise looks good. I also looked and I think that the filtering works even when limited to linear xtalk (e.g. it's looking for bad outliers with < and > and that should work).

values = np.array(ratios[ordering[tt]][ordering[ss]])
values = values[np.abs(values) < 1.0] # Discard unreasonable values
values = np.asarray(ratios[ordering[tt]][ordering[ss]])
good_values = np.abs(values) < 1.0 # Discard unreasonable values
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment this in the code?

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.

2 participants