-
Notifications
You must be signed in to change notification settings - Fork 78
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
Use effective focal length to compute src-dep parameters #1131
Conversation
lstchain/reco/dl1_to_dl2.py
Outdated
tel_id = config["allowed_tels"][0] if "allowed_tels" in config else 1 | ||
effective_focal_length = subarray_info.tel[tel_id].optics.effective_focal_length | ||
except OSError: | ||
print("subarray table is not readable because of the version inompatibility.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should use logging system, not prints
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #1131 +/- ##
==========================================
- Coverage 73.88% 73.79% -0.09%
==========================================
Files 125 124 -1
Lines 12569 12577 +8
==========================================
- Hits 9286 9281 -5
- Misses 3283 3296 +13
☔ View full report in Codecov by Sentry. |
@SeiyaNozaki I am not 100% sure this is correct. However, if you use the effective focal length for computing the image parameters, then it is like having no aberration in the reco params (e.g. reco direction). Hence the expected source position (to be used as reference for the src-dep parameters computations) should be calculated with the nominal focal length, right? |
Could you have a look at this, @SeiyaNozaki? |
Just let me summarize the current parameterization and how we should correct aberration effect. If I understand correctly, hillas parameters are computed in camera frame (unit: m) in ctapipe. When computing parameters related MC true gamma-ray position (including cta-lstchain/lstchain/reco/r0_to_dl1.py Line 583 in c9e4c4f
cta-lstchain/lstchain/reco/r0_to_dl1.py Lines 805 to 810 in c9e4c4f
cta-lstchain/lstchain/reco/dl1_to_dl2.py Lines 769 to 771 in c9e4c4f
Am I correct...? |
in lstchain ctapipe supports both, computing in telescope frame (degrees, with configuration if effective or equivalent focal length should be used for the transformation) and camera frame. Since version 0.13, computing them in telescope frame is the default for the We actually plan to remove computation of hillas parameters (and related image parameters) in camera frame in one of the upcoming releases, see: |
I think the preferred solution here would but to just switch to computation in telescope frame for everything, not piece-by-piece applying effective focal length corrections to different parts of the code. |
what do you think @moralejo ? It could be a big change, but we may need to apply this change at some point. |
Ok, so they are in meters, and measured "on the camera" (i.e. the effect of aberration is present, e.g. centroids are slightly further out than they would for ideal optics with the "equivalent focal length" of 28 m)
cta-lstchain/lstchain/reco/r0_to_dl1.py Line 788 in c9e4c4f
I think there is a problem there. You pass to the function the equivalent focal length. This is used to calculate the true source position on the camera (in m). That is the position for ideal optics (28 m focal), but the computed image parameters are affected by aberration. Either we calculate the true source position modified by aberration, OR we correct the aberration in the image parameters (in this case just the centroid position). The way it is now, the disp_dx, disp_dy, disp_norm will come from aberration-affected (centroid_x, centroid_y) and aberration_free (source_position_x, source_position_y). Probably the effect is not large for the source-INdependent analysis, because the RF would "learn" to estimate the source position (for ideal optics) from the aberration-affected images. |
If you want to use the parameters in camera frame (=aberration-affected) then, for calculating src-dep params, one should use the "true source position" also affected by aberration (=computed using the effective focal length). But this is not what we do now. |
I prefer a slightly different point of view, which in the end has the same interpretation however. The centroids in the camera are where they are, independent of the frame, i.e. the pixel values don't change. Where the aberration comes in is the question, to which point on the sky a pixel corresponds to. And the effective focal length is the more correct answer here.
Which means using the effective focal length for the transformation from AltAz through TelescopeFrame into CameraFrame
Better than correcting the image parameters after the fact would be already computing them so they are correct, which is what computing them in the In
and then just use that geometry for the computation of all image parameters.
|
Seems the cleanest solution, yes, if the aberration correction is applied (i.e. effective focal length is always used) when transforming the image parameters from camera to telescope frame. Still, I think it is better to finish this PR with just the needed corrections, right? Or do you have time @SeiyaNozaki to attempt the |
Technically, we don't transform the image parameters. We transform the pixel coordinates into |
Yes, I agree.
Seems simple enough... Would it then be ok to make that part of this PR? BTW, I think all this still allows running dl1_to_dl2 on existing DL1 files (from v0.9), right? (eff. focal length is hard-coded) |
Starting from the images yes, the parameters will change though. |
Ah, right, no problem if we re-do the DL1ab part... Current DL1b:
If we go for the change, DL1b would be like:
I think we should go for this change before the next reprocessing (from raw) of the full sample, but I hesitate to go for it straightaway. Perhaps it is better to make sure, with as few changes as possible, that the source-dependent analysis is properly done, to check if the discrepancies we see with source-independent may be related to this aberration issue. |
I think its even worse... length and width are transformed by hand into degrees using the equivalent focal length, the rest of the image parameters is left untouched and is in meters or the related units. |
Let me summarize my understanding of the current code in this PR: cta-lstchain/lstchain/reco/dl1_to_dl2.py Lines 789 to 792 in 8543db8
Note that the focal length passed as an argument to get_expected_source_pos is not used at all for MC gammas (only for MC protons). The pre-calculated values data['src_x'] (and src_y) are used for gammas - and they were computed with the equivalent focal length (i.e. 28 m), in r0_to_dl1: cta-lstchain/lstchain/reco/r0_to_dl1.py Lines 805 to 810 in c9e4c4f
Now, this source position computed with f=28 m, i.e. assuming perfect optics, is used to calculate the source-dependent parameters (from image parameters in camera frame, i.e. "affected by aberration"): cta-lstchain/lstchain/reco/dl1_to_dl2.py Line 731 in 8543db8
This is what is not correct in my opinion. |
That is for source-dependent analysis. For source-independent the target disp values have the same problem, so that should be corrected as well. |
Okay, I agree with @moralejo Strictly speaking, cta-lstchain/lstchain/reco/dl1_to_dl2.py Line 534 in 8543db8
So I want just to update all disp parameters (including |
Sorry, I don't understand what you mean. If we recalculate (src_x, src_y) with effective focal length then everything is in camera frame, and all source-dep parameters will be correct, right? |
As far as I could see, all calls to apply_models use the equivalent focal length, 28 m: cta-lstchain/lstchain/reco/dl1_to_dl2.py Line 533 in c9e4c4f
This means that the conversion from reco event direction in camera frame to Alt Az is done ignoring the effect of aberration. This is not correct, but may be partly compensated by the fact that the RF was trained with the target direction (on camera) computed also with the equivalent focal length - so the RF could somehow "learn" to go from images with aberration to reco directions without it. We should however fix it everywhere, probably it is more clear if done in this PR. For consistency we should also change the stored values of src_x, src_y in the MC DL1 files. As of now they are also computed with equivalent f. They will anyway not be used in the pipeline if we go for the changes above - so that we can run dl1-to-d2 on existing DL1 files. |
ok! So we need to compute I will implement so. |
Sorry please forget it... I just wanted to say I want to recalculate not only src_x, src_y, but also all |
…ut of aberration effect
lstchain/reco/dl1_to_dl2.py
Outdated
@@ -794,11 +806,11 @@ def get_expected_source_pos(data, data_type, config, effective_focal_length=29.3 | |||
# For proton MC, nominal source position is one written in config file | |||
if data_type == 'mc_proton': | |||
expected_src_pos = utils.sky_to_camera( | |||
u.Quantity(data['mc_alt_tel'].values + config['mc_nominal_source_x_deg'], u.deg, copy=False), | |||
u.Quantity(data['mc_az_tel'].values + config['mc_nominal_source_y_deg'], u.deg, copy=False), | |||
u.Quantity(data['mc_alt_tel'].values + np.deg2rad(config['mc_nominal_source_x_deg']), u.rad, copy=False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am confused about this.... you add something called "nominal source_{x,y}" to something called az/alt?
This seems wrong, at least if the operation is correct, than the names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameter is already there, it specifies the relative position (0.4 deg on x-axis by default) to compute expected source position for proton MC.
cta-lstchain/lstchain/data/lstchain_src_dep_config.json
Lines 62 to 63 in c9e4c4f
"mc_nominal_source_x_deg": 0.4, | |
"mc_nominal_source_y_deg": 0.0, |
Just I found the bug, though it didn't affect the final result much
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(0.4 deg on x-axis by default)
What x-axis? In which coordinate system?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, indeed it may be confusing... It assumes in AltAz coordinates (0.4 deg).. This parameter was introduced here:
#247 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, indeed it may be confusing... It assumes in AltAz coordinates (0.4 deg).. This parameter was introduced here: #247 (comment)
u.Quantity(data['mc_az_tel'].values + np.deg2rad(config['mc_nominal_source_y_deg']), u.rad, copy=False),
It is not correct, camera frame's x is "along the altitude axis", but y is definitely not the azimuth axis....
Also, why do you need this? mc_nominal_source_x_deg and mc_nominal_source_y_deg are already the position on the camera (well, in degrees and without aberration) w.r.t. which you want the src-dep reco for protons.
You just have to transform it to meters
expected_src_pos_y_m = np.tan(np.deg2rad(mc_nominal_source_y_deg)) * effective_focal_length
expected_src_pos_x_m = np.tan(np.deg2rad(mc_nominal_source_x_deg)) * effective_focal_length
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just resolved the conflict resulting from the azimuth range change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expected_src_pos_y_m = np.tan(np.deg2rad(mc_nominal_source_y_deg)) * effective_focal_length
expected_src_pos_x_m = np.tan(np.deg2rad(mc_nominal_source_x_deg)) * effective_focal_length
We have the ctapipe coordinate systems for this.
The source position is given in AltAz, correct? or where does this mc_nominal_source_{x,y}_deg
come from?
Then:
source_pos = SkyCoord(alt=..., az=.., frame=AltAz())
pointing = SkyCoord(alt=..., az=..., frame=AltAz())
camera_frame = CameraFrame(telescope_pointing=pointing, focal_length=effective_focal_length)
source_camera = source_pos.transform_to(camera_frame)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the "fake position" for the proton analysis is provided in "camera coordinates" x, y, but in degrees and without aberration. So this converts it to true camera coordinates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then it's:
source_pos = SkyCoord(fov_lon=..., fov_lat=.., frame=TelescopeFrame())
camera_frame = CameraFrame(focal_length=effective_focal_length)
source_camera = source_pos.transform_to(camera_frame)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then it's:
source_pos = SkyCoord(fov_lon=..., fov_lat=.., frame=TelescopeFrame()) camera_frame = CameraFrame(focal_length=effective_focal_length) source_camera = source_pos.transform_to(camera_frame)
Yes, and I think fov_lon = -mc_nominal_source_y_deg and fov_lat = mc_nominal_source_x_deg
It does not matter much, however, because the direction of the "nominal" position chosen for protons is not critical I think.
print("subarray table is not readable because of the version inompatibility.") | ||
print("Use the effective focal lentgh for the standard LST optics") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typos: inompatibility, lentgh
Also, better "I will use the effective..." (otherwise it seems it is asking the user for some change )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"The effective focal length for the standard LST optics will be used"
src_dep_df = pd.concat(get_source_dependent_parameters( | ||
dl1_params, config, effective_focal_length=effective_focal_length), axis=1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I already commented about this. In
cta-lstchain/lstchain/reco/dl1_to_dl2.py
Line 801 in 500d7b2
def get_expected_source_pos(data, data_type, config, effective_focal_length=29.30565 * u.m): |
for gamma mc the returned nominal position on the camera is (I think) obtained with nominal focal length (pre-calculated):
cta-lstchain/lstchain/reco/dl1_to_dl2.py
Lines 812 to 814 in 500d7b2
if data_type == 'mc_gamma': | |
expected_src_pos_x_m = data['src_x'].values | |
expected_src_pos_y_m = data['src_y'].values |
Wait, it seems the values src_x, src_y finally used in building the models and in applying them are not directly those from dl1 files, but are recalculated with effective_focal_length, so I think it is probably working.
On the other hand, lstchain_add_source_dependent_parameters.py will keep the src_x, src_y that are found in the dl1 file (calculated with "equivalent f" for existing v0.9 files).
I think that what is misleading is the behaviour of get_expected_source_pos:
get_expected_source_pos(data, data_type, config, effective_focal_length=29.30565 * u.m)
I would expect the line above to always recalculate the source position using the focal length that is passed. But for MC gammas it just returns whatever is already stored in "data"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src_x
and src_y
is updated using effective focal length here (I thought this was done before get_expected_source_pos
function, but it is not the case... I will update the code)
cta-lstchain/lstchain/reco/dl1_to_dl2.py
Line 629 in 500d7b2
dl2 = update_disp_with_effective_focal_length(dl2, effective_focal_length = effective_focal_length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said, I think you have to update get_expected_source_pos so that it recalculates the position, not just propagates...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, it is true. Then I will modify codes to always recalculate the source position inside this function.
This function is only used for source-dep analysis. But, it would be better to recalculate the source position somewhere else also for the source-indep analysis addressing this comment, correct?
#1131 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, it is true. Then I will modify codes to always recalculate the source position inside this function. This function is only used for source-dep analysis. But, it would be better to recalculate the source position somewhere else also for the source-indep analysis addressing this comment, correct? #1131 (comment)
Yes, for source-indep we need that the target for direction RF (true source position) is also in "true camera coordinates", meaning that it contains the effect of aberration (just like the shower images).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see.
For lstchain_add_source_dependent_parameters.py
, I'd even remove this script since source-dep parameters are also computed during dl1_to_dl2 step if src-dep parameters don't exist.
This script overwrites the existing DL1 data to add source-dependent data frame, so it doesn't make sense for the current data analysis scheme since we analyze the common DL1 data produced by OSA.
Looks fine to me. If I understood correctly, the source-independent analysis is also corrected, by using as target in build_models the true gamma direction in camera coordinates computed with effective focal length. Then, after applying the disp RF, the direction is converted to Alt Az using again effective focal length. |
Related to #1048
This PR allows to using the effective focal length (instead of the equivalent focal length:28 m) to compute source-dep parameters. Due to the version incompatibility, it raises an error when reading subarray table using lstchain v0.10 + DL1 data processed by lstchain v0.9. So, if it fails to read subarray table to get the effective focal length, it just uses the standard LST effective focal length.