Skip to content

Commit 61bd2c0

Browse files
authored
Merge pull request #241 from esheldon/rho4
add rho4 to adaptive moments
2 parents 3b4630c + 9f8f53d commit 61bd2c0

File tree

14 files changed

+142
-35
lines changed

14 files changed

+142
-35
lines changed

.github/workflows/mdet.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,12 @@ jobs:
2121
channel-priority: strict
2222
show-channel-urls: true
2323
miniforge-version: latest
24-
miniforge-variant: Mambaforge
2524

2625
- name: configure conda and install code
2726
shell: bash -l {0}
2827
run: |
29-
mamba config --set always_yes yes
30-
mamba install --quiet \
28+
conda config --set always_yes yes
29+
conda install --quiet \
3130
pip \
3231
setuptools \
3332
numpy \
@@ -60,7 +59,7 @@ jobs:
6059
popd
6160
6261
pip uninstall ngmix -y
63-
mamba install ngmix==2.0.3 -y
62+
conda install ngmix==2.0.3 -y
6463
pushd mdet_tests
6564
python test_mdet_regression.py v2.0.3
6665
popd

.github/workflows/test.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
name: tests
1212
strategy:
1313
matrix:
14-
pyver: ["3.8", "3.9", "3.10"]
14+
pyver: ["3.9", "3.10", "3.11"]
1515

1616
runs-on: "ubuntu-latest"
1717

@@ -25,13 +25,12 @@ jobs:
2525
channel-priority: strict
2626
show-channel-urls: true
2727
miniforge-version: latest
28-
miniforge-variant: Mambaforge
2928

3029
- name: configure conda and install code
3130
shell: bash -l {0}
3231
run: |
33-
mamba config --set always_yes yes
34-
mamba install --quiet \
32+
conda config --set always_yes yes
33+
conda install --quiet \
3534
pip \
3635
setuptools \
3736
numpy \

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## v2.3.1
22

3+
### new features
4+
5+
- Add calculation of "rho4" to the adaptive moments code.
6+
37
## Bug Fixes
48

59
- The metacal psf reconvolution method 'gauss' (which uses MetacalGaussPSF)

ngmix/admom/admom.py

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,66 @@ def find_cen_admom(
167167
class AdmomResult(dict):
168168
"""
169169
Represent a fit using adaptive moments, and generate images and mixtures
170-
for the best fit
170+
for the best fit. This inherits from dict and has entries for
171+
the results of adaptive moments.
171172
172173
Parameters
173174
----------
174175
obs: observation(s)
175176
Observation, ObsList, or MultiBandObsList
176177
result: dict
177-
the basic fit result, to bad added to this object's keys
178+
the basic fit result, to be added to this object's keys
179+
180+
The entries will include, but not be limited to
181+
-----------------------------------------------
182+
flags: int
183+
flags for processing
184+
flagstr: str
185+
Explanation of flags
186+
numiter: int
187+
number of iterations in adaptive moments algorithm
188+
npix: int
189+
Number of pixels used
190+
flux_flags: int
191+
Flags for flux
192+
flux_flagstr: int
193+
Explanation of flux flags
194+
flux: float
195+
Flux estimate
196+
flux_err: float
197+
Error on flux estimate
198+
T_flags: int
199+
Flags for T
200+
T_flagstr: int
201+
Explanation of T flags
202+
T: float
203+
T for gaussian
204+
T_err: float
205+
Error on T
206+
e1: float
207+
First ellipticity parameter
208+
e1_err: float
209+
Error on first ellipticity parameter
210+
e2: float
211+
Second ellipticity parameter
212+
e2_err: float
213+
Error on second ellipticity parameter
214+
rho4_flags: int
215+
Flags for rho4
216+
rho4_flagstr: int
217+
Explanation of rho4 flags
218+
rho4: float
219+
rho4 for gaussian
220+
rho4_err: float
221+
Error on rho4
222+
pars: array
223+
Array of gaussian pars, size 6 with [v, u, e1, e2, T, flux]
224+
wsum: float
225+
Sum of weights over pixels
226+
sums: array
227+
Array of size 7, holding sums for
228+
sums_cov: array
229+
Covariance sums, shape (7, 7)
178230
"""
179231

180232
def __init__(self, obs, result):
@@ -368,7 +420,7 @@ def get_result(ares, jac_area, wgt_norm):
368420
if n == 'sums':
369421
res[n] = ares[n].copy()
370422
elif n == 'sums_cov':
371-
res[n] = ares[n].reshape((6, 6)).copy()
423+
res[n] = ares[n].reshape((7, 7)).copy()
372424
else:
373425
res[n] = ares[n]
374426
res["sums_norm"] = ares["wsum"]
@@ -378,12 +430,16 @@ def get_result(ares, jac_area, wgt_norm):
378430
res["flux_flagstr"] = ""
379431
res["T_flags"] = 0
380432
res["T_flagstr"] = ""
433+
res["rho4_flags"] = 0
434+
res["rho4_flagstr"] = ""
381435

382436
res['flux'] = np.nan
383437
res['flux_mean'] = np.nan
384438
res["flux_err"] = np.nan
385439
res["T"] = np.nan
386440
res["T_err"] = np.nan
441+
res["rho4"] = np.nan
442+
res["rho4_err"] = np.nan
387443
res["s2n"] = np.nan
388444
res["e1"] = np.nan
389445
res["e2"] = np.nan
@@ -396,6 +452,7 @@ def get_result(ares, jac_area, wgt_norm):
396452
# set things we always set if flags are ok
397453
if res['flags'] == 0:
398454
res['T'] = res['pars'][4]
455+
res['rho4'] = ares['rho4']
399456
flux_sum = res['sums'][5]
400457
res['flux_mean'] = flux_sum/res['wsum']
401458
res['pars'][5] = res['flux_mean']
@@ -420,8 +477,8 @@ def get_result(ares, jac_area, wgt_norm):
420477
else:
421478
res['flux_flags'] |= res['flags']
422479

423-
# handle flux+T only
424480
if res['flags'] == 0:
481+
# T
425482
if res['sums_cov'][4, 4] > 0 and res['sums_cov'][5, 5] > 0:
426483
if res['sums'][5] > 0:
427484
# the sums include the weight, so need factor of two to correct
@@ -437,8 +494,28 @@ def get_result(ares, jac_area, wgt_norm):
437494
res["T_flags"] |= ngmix.flags.NONPOS_FLUX
438495
else:
439496
res["T_flags"] |= ngmix.flags.NONPOS_VAR
497+
498+
# rho4
499+
if res['sums_cov'][6, 6] > 0 and res['sums_cov'][5, 5] > 0:
500+
if res['sums'][5] > 0:
501+
res['rho4'] = res['sums'][6] / res['sums'][5]
502+
# the sums include the weight, so need factor of two to correct
503+
res['rho4_err'] = 4*get_ratio_error(
504+
res['sums'][6],
505+
res['sums'][5],
506+
res['sums_cov'][6, 6],
507+
res['sums_cov'][5, 5],
508+
res['sums_cov'][6, 5],
509+
)
510+
else:
511+
# flux <= 0.0
512+
res["rho4_flags"] |= ngmix.flags.NONPOS_FLUX
513+
else:
514+
res["rho4_flags"] |= ngmix.flags.NONPOS_VAR
515+
440516
else:
441517
res['T_flags'] |= res['flags']
518+
res['rho4_flags'] |= res['flags']
442519

443520
# now handle full flags
444521
if not np.all(np.diagonal(res['sums_cov'][2:, 2:]) > 0):
@@ -486,22 +563,23 @@ def get_result(ares, jac_area, wgt_norm):
486563
res['flagstr'] = ngmix.flags.get_flags_str(res['flags'])
487564
res['flux_flagstr'] = ngmix.flags.get_flags_str(res['flux_flags'])
488565
res['T_flagstr'] = ngmix.flags.get_flags_str(res['T_flags'])
566+
res['rho4_flagstr'] = ngmix.flags.get_flags_str(res['rho4_flags'])
489567

490568
return res
491569

492570

493571
_admom_result_dtype = [
494572
('flags', 'i4'),
495573
('numiter', 'i4'),
496-
('nimage', 'i4'),
497574
('npix', 'i4'),
498575
('wsum', 'f8'),
499576

500-
('sums', 'f8', 6),
501-
('sums_cov', 'f8', (6, 6)),
577+
('sums', 'f8', 7),
578+
('sums_cov', 'f8', (7, 7)),
502579
('pars', 'f8', 6),
580+
('rho4', 'f8'),
503581
# temporary
504-
('F', 'f8', 6),
582+
('F', 'f8', 7),
505583
]
506584

507585
_admom_conf_dtype = [

ngmix/admom/admom_nb.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def admom(confarray, wt, pixels, resarray):
8686
res['pars'][3] = 2.0*wt['irc'][0]
8787
res['pars'][4] = wt['icc'][0] + wt['irr'][0]
8888
res['pars'][5] = 1.0
89+
res['rho4'] = res['sums'][6] / res['sums'][5]
8990

9091
break
9192

@@ -151,19 +152,26 @@ def admom_momsums(wt, pixels, res):
151152
wdata = weight*pixel['val']
152153
w2 = weight*weight
153154

155+
chi2 = (
156+
wt["dcc"][0] * vmod * vmod
157+
+ wt["drr"][0] * umod * umod
158+
- 2.0 * wt["drc"][0] * vmod * umod
159+
)
160+
154161
F[0] = pixel['v']
155162
F[1] = pixel['u']
156163
F[2] = umod*umod - vmod*vmod
157164
F[3] = 2*vmod*umod
158165
F[4] = umod*umod + vmod*vmod
159166
F[5] = 1.0
167+
F[6] = chi2 * chi2
160168

161169
res['wsum'] += weight
162170
res['npix'] += 1
163171

164-
for i in range(6):
172+
for i in range(7):
165173
res['sums'][i] += wdata*F[i]
166-
for j in range(6):
174+
for j in range(7):
167175
res['sums_cov'][i, j] += w2*var*F[i]*F[j]
168176

169177

@@ -228,8 +236,8 @@ def clear_result(res):
228236
res['sums'][:] = 0.0
229237
res['sums_cov'][:, :] = 0.0
230238
res['pars'][:] = np.nan
239+
res['rho4'] = np.nan
231240

232241
# res['flags']=0
233242
# res['numiter']=0
234-
# res['nimage']=0
235243
# res['F'][:]=0.0

ngmix/fitting/leastsqbound.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ def wDfun(x, *args): # wrapped Dfun
538538
retval[1]['ipvt'] - 1)).T
539539
cov_x = None
540540
if info in [1, 2, 3, 4]:
541-
from numpy.dual import inv
541+
from numpy.linalg import inv
542542
from numpy.linalg import LinAlgError
543543
perm = take(eye(n), retval[1]['ipvt'] - 1, 0)
544544
r = triu(transpose(retval[1]['fjac'])[:n, :])

ngmix/gmix/gmix_nb.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,18 @@ def g1g2_to_e1e2(g1, g2):
672672
@njit
673673
def get_weighted_sums(wt, pixels, res, maxrad):
674674
"""
675-
do sums for calculating the weighted moments
675+
Do sums for calculating the weighted moments.
676+
677+
Parameters
678+
----------
679+
wt: array
680+
The gaussian mixture with dtype ngmix.gmix.gmix._gauss2d_dtype
681+
pixels: array
682+
Array of pixels
683+
res: array
684+
The result array
685+
maxrad: float
686+
Maximum radius in u, v coordinates
676687
"""
677688

678689
maxrad2 = maxrad ** 2

ngmix/tests/_fakemeds.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def make_fake_meds(
3434
import fitsio
3535

3636
if cutout_types is None:
37-
cutout_types = copy.deepcopy(CUTOUT_TYPES)
37+
cutout_types = copy.deepcopy(CUTOUT_TYPES) # pragma: no cover
3838

3939
with_psf = 'psf' in cutout_types
4040

ngmix/tests/test_admom.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,22 @@ def test_admom(g1_true, g2_true, wcs_g1, wcs_g2):
2727
).shear(
2828
g1=g1_true, g2=g2_true
2929
).withFlux(
30-
400)
30+
400,
31+
)
3132
im = obj.drawImage(
3233
nx=image_size,
3334
ny=image_size,
3435
wcs=gs_wcs,
35-
method='no_pixel').array
36+
method='no_pixel',
37+
).array
3638
noise = np.sqrt(np.sum(im**2)) / 1e18
3739
wgt = np.ones_like(im) / noise**2
3840
scale = np.sqrt(gs_wcs.pixelArea())
3941

4042
g1arr = []
4143
g2arr = []
4244
Tarr = []
45+
rho4arr = []
4346
for _ in range(50):
4447
shift = rng.uniform(low=-scale/2, high=scale/2, size=2)
4548
xy = gs_wcs.toImage(galsim.PositionD(shift))
@@ -75,6 +78,7 @@ def test_admom(g1_true, g2_true, wcs_g1, wcs_g2):
7578
g1arr.append(_g1)
7679
g2arr.append(_g2)
7780
Tarr.append(_T)
81+
rho4arr.append(res['rho4'])
7882

7983
fim = res.make_image()
8084
assert fim.shape == im.shape
@@ -94,6 +98,9 @@ def test_admom(g1_true, g2_true, wcs_g1, wcs_g2):
9498
if g1_true == 0 and g2_true == 0:
9599
T = np.mean(Tarr)
96100
assert np.abs(T - fwhm_to_T(fwhm)) < 1e-6
101+
rho4_mean = np.mean(rho4arr)
102+
# gaussians have rho4 of 2.0
103+
assert np.abs(rho4_mean - 2) < 1e-5
97104

98105
with pytest.raises(ValueError):
99106
ngmix.admom.run_admom(None, None)

ngmix/tests/test_em.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ def test_em_2gauss(noise):
145145
f1 = pars[0]
146146
f2 = pars[6]
147147
if f1 > f2:
148-
indices = [1, 0]
148+
indices = [1, 0] # pragma: no cover
149149
else:
150-
indices = [0, 1]
150+
indices = [0, 1] # pragma: no cover
151151

152152
# only check pars for no noise
153153
if noise == 0.0:
@@ -213,9 +213,9 @@ def test_em_2gauss_withpsf(noise):
213213
f1 = pars[0]
214214
f2 = pars[6]
215215
if f1 > f2:
216-
indices = [1, 0]
216+
indices = [1, 0] # pragma: no cover
217217
else:
218-
indices = [0, 1]
218+
indices = [0, 1] # pragma: no cover
219219

220220
# only check pars for no noise
221221
if noise == 0.0:

0 commit comments

Comments
 (0)