Skip to content

Commit f30fe7d

Browse files
committed
Add computation of the 4th order moments for the star and PSF in the psfex_interp module.
1 parent e0a22f6 commit f30fe7d

File tree

1 file changed

+96
-1
lines changed

1 file changed

+96
-1
lines changed

src/shapepipe/modules/psfex_interp_package/psfex_interp.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
This 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

@@ -12,6 +12,7 @@
1212
import numpy as np
1313
from astropy.io import fits
1414
from sqlitedict import SqliteDict
15+
import scipy.linalg as alg
1516

1617
from 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

Comments
 (0)