add impactpoint_intensity_fitter.py#2814
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Analysis Details2 IssuesCoverage and DuplicationsProject ID: cta-observatory_ctapipe_AY52EYhuvuGcMFidNyUs |
|
If there is an issue in the intensity fitter, why add a second implementation instead of fixing it? |
|
I fixed the problems and bugs I found so far. It does help, but the resolution is still not enough. The point is very simple : I think the key point here is that we perform the fit with fewer parameters, and therefore achieve better resolution. I will separate the impact point reconstruction from the intensity fitter. First, we need to achieve a better fit. If we succeed, we will also learn how to improve the existing one. |
|
Note that the current intensity fit keeps the ring center fixed (opposed to just using it as an initial guess). Maybe with the chord bug fixed, we can lift this restriction and the fit will perform better if it is allowed to adjust x/y? |
…ng the impact point.
…om_muon_ring sceletons
…ry sensitive to outliers.
mexanick
left a comment
There was a problem hiding this comment.
Overall, this PR needs significant improvements before it can be merged. At the moment it does not meet our project’s quality standards:
– There is extensive duplicated code instead of reuse, which will make maintenance harder.
– Documentation is largely missing, making it difficult to understand intent and usage.
– Tests are essentially absent (the current placeholder test is insufficient).
– Several PEP8/style conventions are not followed (e.g., single-letter/cryptic variable names, commented-out code, etc).
| @@ -0,0 +1,558 @@ | |||
| """ | |||
There was a problem hiding this comment.
I don't think creation of a new module is justified here. The new fitter class returns the same container as the MuonIntensityFitter in the ctapipe.image.muon.intensity_fitter, therefore it should be also implemented there.
There was a problem hiding this comment.
It’s not a new module in my opinion — we need to completely remove the old fitter. The new one has a clearer logic. It is easy to follow and in addition fully vectorized that is why this optimization can be removed.
| ] | ||
|
|
||
|
|
||
| def chord_length(radius, rho, phi0, phi): |
There was a problem hiding this comment.
This function is an almost exact copy-paste of the chord_length of ctapipe.image.muon.intensity_fitter. Please reuse the code instead of copying it, and do not strip vectorization and other performance optimizations. Besides, in case of the API update, the documentation shall be updated too. A new argument (phi0) was introduced, that breaks the order of arguments and lacks description.
There was a problem hiding this comment.
It is far from being an exact copy. This function has two main modifications: first, it uses modulo
2pi, and therefore we remove the limits on the fitting parameter. Second, we explicitly include phi0 (defines the direction with respect to the mirror of the impact point) in the function instead of hiding it somewhere in the fitting procedure this makes it much easier to read.
There was a problem hiding this comment.
If this is a general improvement, improve the function. Do not copy and leave a "suboptimal" slightly different version elsewhere.
I'm still not sure where this pull request is going and why a separate fitter is needed at all as opposed to freezing the efficiency and then re-fitting it with the impact frozen.
There was a problem hiding this comment.
The current algorithm is inefficient, with many values stuck at the limits or default settings. An initial estimate produced 30% more fitted events, and the proposed method is straightforward and easy to follow. We also decouple the impact point fitting from the optical efficiency.
There was a problem hiding this comment.
Then improve the current implementation, please.
There was a problem hiding this comment.
I have already implemented a simple and easy-to-debug method, with decoupled impact point width and optical efficiency measurements.
There was a problem hiding this comment.
I a parallel structure. If this new method doesn't have disadvantages, there is no point in this duplication. Just improve the existing one please
There was a problem hiding this comment.
You can also enable one or the other approach by adding configuration options to MuonIntensityFitter if you think it's valuable to keep both.
There was a problem hiding this comment.
Do you mean ‘replace’? Yes, that can be done very quickly. Or do you mean improving the current likelihood? Because the main improvement, in my view, comes from fitting only the phi distribution with only 18 bins in angle.
There was a problem hiding this comment.
You can also enable one or the other approach by adding configuration options to
MuonIntensityFitterif you think it's valuable to keep both.
In principle, no — we do not need it.
| return chord_length(radius, rho, 0, phi - phi0) | ||
|
|
||
|
|
||
| def gauss_pedestal(x, A, mu, sigma, pedestal): |
There was a problem hiding this comment.
Is this function used to describe the ring width? Please elaborate more the fitting approach.
There was a problem hiding this comment.
Previously, the ring width was fitted with a 2D Gaussian, now we are doing the same in 1D. This makes it simpler and easier to read and interpret.
There was a problem hiding this comment.
No, the ring width is described using a 1d normal distribution:
There was a problem hiding this comment.
@maxnoe It has radial symmetry, but the overall fit is done in 2D. https://github.com/cta-observatory/ctapipe/blob/b2221d5d12bb153c6e0bc0914c3d33ffdaf29bdf/src/ctapipe/image/muon/intensity_fitter.py#L527C1-L527C65
There was a problem hiding this comment.
I'm not sure what your point is. The existing likelihood function transforms into polar coordinates as soon as possible and continues from there.
No 2d gaussian fit is performed as you wrote here:
Previously, the ring width was fitted with a 2D Gaussian,
There was a problem hiding this comment.
The ring width could be fitted in 1D, whereas it is currently fitted effectively in 2D.
There was a problem hiding this comment.
I don't understand your line of argument here. The ring width is a parameter in a likelihood which is described by a 1D probability distribution.
It's not 2d
There was a problem hiding this comment.
The likelihood fit itself is in 2D.
There was a problem hiding this comment.
And why do you think this is an issue? How else can you take the ring center location into account for the image prediction?
There was a problem hiding this comment.
Just like in the 1D fit of the phi distribution.
| ) | ||
|
|
||
| # Predicted total number of Cherenkov photons falling on the mirror | ||
| pred_total_Cher_phot = ( |
There was a problem hiding this comment.
Why do you re-write this? There's a well-defined function image_prediction_no_units that provides you with this. Also, I believe the difference of normalization here is the reason why you have a different final number. As it is correctly noted in the documentation of image_prediction_no_units, since we are measuring the throughput relative to the simulation, the overall normalization doesn't matter as it cancels out.
There was a problem hiding this comment.
This function has issues and errors:
-The expected measured number of signal events does not depend on the pixel FoV, but this function does. The new function fixes this issue.
-There is an analytical formula for the trivial case (rho=0 and no shadowing), which should be included in the tests. The current function gives the wrong result and new function fixes this issue.
| ) | ||
| fit.errordef = Minuit.LEAST_SQUARES | ||
| # | ||
| fit.errors["A"] = 10 |
There was a problem hiding this comment.
How these values are obtained and what units they represent?
There was a problem hiding this comment.
This value defines the initial step of the fit. Usually, we set it much smaller and should be changed to an smaller number. Minuit works with scalars only, you cannot define values in units like meters, for example.
|
|
||
| self.intensity_fitter = MuonIntensityFitter(subarray=subarray, parent=self) | ||
| # self.intensity_fitter = MuonIntensityFitter(subarray=subarray, parent=self) | ||
| self.intensity_fitter = MuonImpactpointIntensityFitter( |
There was a problem hiding this comment.
If you're leaving both options, it should be possible to select one of the fitters.
There was a problem hiding this comment.
This is clear form very fest comment: #2814 (comment)
And discussion and motivation of the issue.
| @@ -0,0 +1,34 @@ | |||
| import astropy.units as u | |||
There was a problem hiding this comment.
Please provide a proper testing of the code you've added.
There was a problem hiding this comment.
Since I discovered new issues and problems in the code (the lat one today), we need to work through it in more detail. Yes, we definitely need to add more tests.
|
|
||
| weights = (phi_y > 0).astype(int) | ||
|
|
||
| phi_x = ((np.roll(hist_phi[1], 1) + hist_phi[1]) / 2.0)[1:] |
There was a problem hiding this comment.
this a very complicated way to say 0.5 * (edges[:-1] + edges[1:])
|
| impact_x=rho * np.cos(Quantity(fit2.values["phi0"], u.rad)), | ||
| impact_y=rho * np.sin(Quantity(fit2.values["phi0"], u.rad)), | ||
| chord_fit_ampl=fit2.values["amplitude"], | ||
| phi_bin_0=phi_y[0], |
There was a problem hiding this comment.
You can just put the array into the container
There was a problem hiding this comment.
Yes, I know. We decided to split this MR into parts, so I just pushed the code to switch the branches. Please ignore this draft MR, until it’s moved out of draft. Also can this MR can be completely deleted i will let you know. I just want to keep the history of changes for current development.





An important error has been found and fixed (in the Chord calculation).
It shows an improvement in the resolution and provides more symmetric distributions.
With the current method, we achieve a 1.7 m resolution on the impact point (from simulation),
whereas ARTEMIS achieved 0.75 m.
We need to implement a new method to reconstruct the impact point.
I will separate the impact point reconstruction from the intensity fitter.
First provides the impact point with known precision.
Second provides the reconstructed and expected intensity and optical throughput.
The intensity fitter will use all available information about the muon to predict
expected intensity.