22
33This module computes the PSFs from a PSFEx model at several galaxy positions.
44
5- :Authors: Morgan Schmitz, Axel Guinot, Martin Kilbinger
5+ :Authors: Morgan Schmitz, Axel Guinot, Martin Kilbinger, Sacha Guerrini
66
77"""
88
1212import numpy as np
1313from astropy .io import fits
1414from sqlitedict import SqliteDict
15+ import scipy .linalg as alg
1516
1617from shapepipe .pipeline import file_io
1718
@@ -319,13 +320,56 @@ def _get_psfshapes(self):
319320 hsm .FindAdaptiveMom (Image (psf ), strict = False ) for psf in self .interp_PSFs
320321 ]
321322
323+ #Compute the list of pq indexes
324+ pqlist = [
325+ [p , 4 - p ] for p in range (0 , 5 )
326+ ]
327+
328+ #Compute the 4th order moments (Code taken from PSFHOME)
329+ for psf , moms in zip (self .interp_PSFs , psf_moms ):
330+
331+ #Compute the normalisation of the image
332+ y , x = np .mgrid [:psf .shape [0 ], :psf .shape [1 ]]+ 1
333+
334+ M = np .zeros ((2 , 2 ))
335+ e1 = moms .observed_shape .e1
336+ e2 = moms .observed_shape .e2
337+ sigma4 = moms .moments_sigma ** 4
338+ c = (1 + e1 ) / (1 - e1 )
339+ M [1 , 1 ] = np .sqrt (sigma4 / (c - 0.25 * e2 ** 2 * (1 + c )** 2 ))
340+ M [0 , 0 ] = c * M [1 , 1 ]
341+ M [0 , 1 ] = 0.5 * e2 * (M [1 , 1 ] + M [0 , 0 ])
342+ M [1 , 0 ] = M [0 , 1 ]
343+
344+ pos = np .array ([x - moms .moments_centroid .x , y - moms .moments_centroid .y ])
345+ inv_M = np .linalg .inv (M )
346+ sqrt_inv_M = alg .sqrtm (inv_M )
347+
348+ std_pos = np .einsum ('ij,jqp->iqp' ,sqrt_inv_M ,pos )
349+ weight = np .exp (- 0.5 * np .einsum ('ijk,ijk->jk' ,std_pos ,std_pos ))
350+
351+ std_x , std_y = std_pos [0 ],std_pos [1 ]
352+
353+ normalization = np .sum (psf * weight )
354+ image_weight = weight * psf
355+
356+ #Compute the 4th moment for each index
357+ moms .fourth_order_moments = {}
358+ for p ,q in pqlist :
359+ moms .fourth_order_moments .update ({str (p )+ str (q ): np .sum (image_weight * std_x ** p * std_y ** q )/ normalization })
360+
361+ moms .fourth_moment_1 = moms .fourth_order_moments ['40' ] - moms .fourth_order_moments ['04' ]
362+ moms .fourth_moment_2 = 2 * (moms .fourth_order_moments ['13' ] + moms .fourth_order_moments ['31' ])
363+
322364 self .psf_shapes = np .array (
323365 [
324366 [
325367 moms .observed_shape .g1 ,
326368 moms .observed_shape .g2 ,
327369 moms .moments_sigma ,
328370 int (bool (moms .error_message )),
371+ moms .fourth_moment_1 ,
372+ moms .fourth_moment_2 ,
329373 ]
330374 for moms in psf_moms
331375 ]
@@ -350,6 +394,8 @@ def _write_output(self):
350394 "E2_PSF_HSM" : self .psf_shapes [:, 1 ],
351395 "SIGMA_PSF_HSM" : self .psf_shapes [:, 2 ],
352396 "FLAG_PSF_HSM" : self .psf_shapes [:, 3 ].astype (int ),
397+ "M_4_PSF_1" : self .psf_shapes [:, 4 ],
398+ "M_4_PSF_2" : self .psf_shapes [:, 5 ],
353399 }
354400 else :
355401 data = {"VIGNET" : self .interp_PSFs }
@@ -434,13 +480,58 @@ def _get_starshapes(self, star_vign):
434480 for star , mask in zip (star_vign , masks )
435481 ]
436482
483+ #Compute the list of pq indexes
484+ pqlist = [
485+ [p , 4 - p ] for p in range (0 , 5 )
486+ ]
487+
488+ #Compute the 4th order moments (Code taken from PSFHOME)
489+ for star , mask , moms in zip (star_vign , masks , star_moms ):
490+
491+ star [mask == 1 ] = 0
492+
493+ #Compute the normalisation of the image
494+ y , x = np .mgrid [:star .shape [0 ], :star .shape [1 ]]+ 1
495+
496+ M = np .zeros ((2 , 2 ))
497+ e1 = moms .observed_shape .e1
498+ e2 = moms .observed_shape .e2
499+ sigma4 = moms .moments_sigma ** 4
500+ c = (1 + e1 ) / (1 - e1 )
501+ M [1 , 1 ] = np .sqrt (sigma4 / (c - 0.25 * e2 ** 2 * (1 + c )** 2 ))
502+ M [0 , 0 ] = c * M [1 , 1 ]
503+ M [0 , 1 ] = 0.5 * e2 * (M [1 , 1 ] + M [0 , 0 ])
504+ M [1 , 0 ] = M [0 , 1 ]
505+
506+ pos = np .array ([x - moms .moments_centroid .x , y - moms .moments_centroid .y ])
507+ inv_M = np .linalg .inv (M )
508+ sqrt_inv_M = alg .sqrtm (inv_M )
509+
510+ std_pos = np .einsum ('ij,jqp->iqp' ,sqrt_inv_M ,pos )
511+ weight = np .exp (- 0.5 * np .einsum ('ijk,ijk->jk' ,std_pos ,std_pos ))
512+
513+ std_x , std_y = std_pos [0 ],std_pos [1 ]
514+
515+ normalization = np .sum (star * weight )
516+ image_weight = weight * star
517+
518+ #Compute the 4th moment for each index
519+ moms .fourth_order_moments = {}
520+ for p ,q in pqlist :
521+ moms .fourth_order_moments .update ({str (p )+ str (q ): np .sum (image_weight * std_x ** p * std_y ** q )/ normalization })
522+
523+ moms .fourth_moment_1 = moms .fourth_order_moments ['40' ] - moms .fourth_order_moments ['04' ]
524+ moms .fourth_moment_2 = 2 * (moms .fourth_order_moments ['13' ] + moms .fourth_order_moments ['31' ])
525+
437526 self .star_shapes = np .array (
438527 [
439528 [
440529 moms .observed_shape .g1 ,
441530 moms .observed_shape .g2 ,
442531 moms .moments_sigma ,
443532 int (bool (moms .error_message )),
533+ moms .fourth_moment_1 ,
534+ moms .fourth_moment_2
444535 ]
445536 for moms in star_moms
446537 ]
@@ -503,10 +594,14 @@ def _write_output_validation(self, star_dict, psfex_cat_dict):
503594 "E2_PSF_HSM" : self .psf_shapes [:, 1 ],
504595 "SIGMA_PSF_HSM" : self .psf_shapes [:, 2 ],
505596 "FLAG_PSF_HSM" : self .psf_shapes [:, 3 ].astype (int ),
597+ "M_4_PSF_1" : self .psf_shapes [:, 4 ],
598+ "M_4_PSF_2" : self .psf_shapes [:, 5 ],
506599 "E1_STAR_HSM" : self .star_shapes [:, 0 ],
507600 "E2_STAR_HSM" : self .star_shapes [:, 1 ],
508601 "SIGMA_STAR_HSM" : self .star_shapes [:, 2 ],
509602 "FLAG_STAR_HSM" : self .star_shapes [:, 3 ].astype (int ),
603+ "M_4_STAR_1" : self .star_shapes [:, 4 ],
604+ "M_4_STAR_2" : self .star_shapes [:, 5 ],
510605 }
511606 data = {** data , ** star_dict }
512607
0 commit comments