Skip to content

Commit fa34dc4

Browse files
authored
Merge pull request #58 from esheldon/wpixels
Wpixels
2 parents dba6286 + 8588275 commit fa34dc4

File tree

13 files changed

+2324
-1282
lines changed

13 files changed

+2324
-1282
lines changed

ngmix/__init__.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
__version__="v1.2"
22

33
from . import gmix
4-
from .gmix import GMix
5-
from .gmix import GMixModel
6-
from .gmix import GMixCoellip
4+
from .gmix import (
5+
GMix,
6+
GMixModel,
7+
GMixBDF,
8+
GMixCoellip,
9+
10+
GMixList,
11+
MultiBandGMixList,
12+
)
713

814
from . import gmix_ndim
915
from .gmix_ndim import GMixND
@@ -25,7 +31,7 @@
2531
from .gexceptions import GMixRangeError, GMixFatalError, GMixMaxIterEM
2632

2733
from . import fitting
28-
from .fitting import print_pars
34+
from .fitting import print_pars, format_pars
2935
from . import simplex
3036

3137
from . import galsimfit

ngmix/bootstrap.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2693,10 +2693,57 @@ def _get_lm_fitter_class(self):
26932693
from .fitting import LMComposite
26942694
return LMComposite
26952695

2696+
class BDRunner(MaxRunner):
2697+
"""
2698+
wrapper to generate guesses and run the BD fitter a few times
2699+
"""
2700+
def __init__(self,
2701+
obs,
2702+
max_pars,
2703+
guesser,
2704+
prior=None):
2705+
self.obs=obs
2706+
2707+
self.max_pars=max_pars
2708+
2709+
self.method=max_pars.get('method','lm')
2710+
if self.method == 'lm':
2711+
self.send_pars=max_pars['lm_pars']
2712+
else:
2713+
self.send_pars=max_pars
2714+
2715+
self.prior=prior
2716+
2717+
self.guesser=guesser
2718+
2719+
def _go_lm(self, ntry=1):
2720+
fitclass=self._get_lm_fitter_class()
2721+
2722+
for i in xrange(ntry):
2723+
guess=self.guesser()
2724+
fitter=fitclass(
2725+
self.obs,
2726+
lm_pars=self.send_pars,
2727+
prior=self.prior,
2728+
)
2729+
2730+
fitter.go(guess)
2731+
2732+
res=fitter.get_result()
2733+
if res['flags']==0:
2734+
break
2735+
2736+
res['ntry'] = i+1
2737+
self.fitter=fitter
2738+
2739+
def _get_lm_fitter_class(self):
2740+
from .fitting import LMBD
2741+
return LMBD
2742+
26962743

26972744
class BDFRunner(MaxRunner):
26982745
"""
2699-
wrapper to generate guesses and run the psf fitter a few times
2746+
wrapper to generate guesses and run the BDF fitter a few times
27002747
"""
27012748
def __init__(self,
27022749
obs,

ngmix/fitting.py

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,7 @@ def _set_totpix(self):
180180
totpix=0
181181
for obs_list in self.obs:
182182
for obs in obs_list:
183-
shape=obs.image.shape
184-
totpix += shape[0]*shape[1]
183+
totpix += obs.pixels.size
185184

186185
self.totpix=totpix
187186

@@ -849,8 +848,7 @@ def _set_totpix(self):
849848

850849
totpix=0
851850
for obs in self.obs:
852-
shape=obs.image.shape
853-
totpix += shape[0]*shape[1]
851+
totpix += obs.pixels.size
854852

855853
self.totpix=totpix
856854

@@ -1674,13 +1672,17 @@ def go(self, guess):
16741672

16751673
self._make_lists()
16761674

1675+
bounds = self._get_bounds()
1676+
16771677
result = run_leastsq(
16781678
self._calc_fdiff,
16791679
guess,
16801680
self.n_prior_pars,
1681+
bounds=bounds,
16811682
**self.lm_pars
16821683
)
16831684

1685+
16841686
result['model'] = self.model_name
16851687
if result['flags']==0:
16861688
result['g'] = result['pars'][2:2+2].copy()
@@ -1692,6 +1694,15 @@ def go(self, guess):
16921694

16931695
self._result=result
16941696

1697+
def _get_bounds(self):
1698+
"""
1699+
get bounds on parameters
1700+
"""
1701+
bounds=None
1702+
if self.prior is not None:
1703+
if hasattr(self.prior,'bounds'):
1704+
bounds=self.prior.bounds
1705+
return bounds
16951706

16961707
run_max=go
16971708
run_lm=go
@@ -1728,7 +1739,7 @@ def _setup_data(self, guess):
17281739
self._init_gmix_all(guess)
17291740
except ZeroDivisionError:
17301741
raise GMixRangeError("got zero division")
1731-
1742+
17321743
def get_band_pars(self, pars_in, band):
17331744
"""
17341745
Get linear pars for the specified band
@@ -1896,6 +1907,77 @@ def _make_model(self, band_pars):
18961907
gm0=gmix.GMixCM(self.fracdev, self.TdByTe, band_pars)
18971908
return gm0
18981909

1910+
class LMBD(LMSimple):
1911+
"""
1912+
exp+dev model with Td/Te and fracdev free
1913+
"""
1914+
def __init__(self, obs, **keys):
1915+
super(LMBD,self).__init__(obs, 'bd', **keys)
1916+
1917+
self._band_pars=zeros(8)
1918+
1919+
def _set_n_prior_pars(self):
1920+
# center1 + center2 + shape + T + TdByTe + fracdev + fluxes
1921+
if self.prior is None:
1922+
self.n_prior_pars=0
1923+
else:
1924+
self.n_prior_pars=1 + 1 + 1 + 1 + 1 + 1 + self.nband
1925+
1926+
def get_gmix(self, band=0):
1927+
"""
1928+
Get a gaussian mixture at the "best" parameter set, which
1929+
definition depends on the sub-class
1930+
"""
1931+
res=self.get_result()
1932+
pars=self.get_band_pars(res['pars'], band)
1933+
return self._make_model(pars)
1934+
1935+
def get_band_pars(self, pars_in, band):
1936+
"""
1937+
Get linear pars for the specified band
1938+
"""
1939+
1940+
pars=self._band_pars
1941+
1942+
pars[0:7] = pars_in[0:7]
1943+
pars[7] = pars_in[7+band]
1944+
1945+
return pars
1946+
1947+
1948+
def _make_model(self, band_pars):
1949+
"""
1950+
incoming parameters are
1951+
[c1,c2,g1,g2,T,TdByTe,fracdev,F]
1952+
"""
1953+
return gmix.GMixModel(band_pars,'bd')
1954+
1955+
def _set_flux(self, res):
1956+
if self.nband==1:
1957+
res['flux'] = res['pars'][7]
1958+
res['flux_err'] = sqrt(res['pars_cov'][7,7])
1959+
else:
1960+
res['flux'] = res['pars'][7:]
1961+
res['flux_cov'] = res['pars_cov'][7:, 7:]
1962+
res['flux_err'] = sqrt(diag(res['flux_cov']))
1963+
1964+
'''
1965+
def _setup_data(self, guess):
1966+
super(LMBD,self)._setup_data(guess)
1967+
1968+
import images
1969+
gm = self._gmix_all[0][0]
1970+
print('gm:',gm)
1971+
im = gm.make_image(
1972+
self.obs[0][0].image.shape,
1973+
jacobian=self.obs[0][0].jacobian,
1974+
)
1975+
print(im.std())
1976+
images.multiview(im)
1977+
stop
1978+
'''
1979+
1980+
18991981
class LMBDF(LMSimple):
19001982
"""
19011983
exp+dev model with Tdev/Texp=1 but fracdev free
@@ -1979,7 +2061,8 @@ def run_leastsq(func, guess, n_prior_pars, **keys):
19792061
xtol:
19802062
Relative error desired in solution. 1.0e-6
19812063
"""
1982-
from scipy.optimize import leastsq
2064+
#from scipy.optimize import leastsq
2065+
from .leastsqbound import leastsqbound as leastsq
19832066

19842067
npars=guess.size
19852068
k_space=keys.pop('k_space',False)
@@ -3363,6 +3446,15 @@ def print_pars(pars, stream=stdout, fmt='%8.3g',front=None):
33633446
if pars is None:
33643447
stream.write('%s\n' % None)
33653448
else:
3366-
fmt = ' '.join( [fmt+' ']*len(pars) )
3367-
stream.write(fmt % tuple(pars))
3449+
#fmt = ' '.join( [fmt+' ']*len(pars) )
3450+
#stream.write(fmt % tuple(pars))
3451+
s = format_pars(pars, fmt=fmt)
3452+
stream.write(s)
33683453
stream.write('\n')
3454+
3455+
def format_pars(pars, fmt='%8.3g'):
3456+
"""
3457+
make a nice string of the pars with no line breaks
3458+
"""
3459+
fmt = ' '.join( [fmt+' ']*len(pars) )
3460+
return fmt % tuple(pars)

ngmix/gmix.py

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@
3535
# this is for backward compatibility
3636
from .gmix_ndim import GMixND
3737

38-
def make_gmix_model(pars, model):
38+
def make_gmix_model(pars, model, **kw):
3939
"""
4040
get a gaussian mixture model for the given model
4141
"""
4242

43+
model = get_model_num(model)
4344
if model==GMIX_COELLIP:
4445
return GMixCoellip(pars)
46+
elif model==GMIX_BDF:
47+
return GMixBDF(pars=pars, **kw)
4548
elif model==GMIX_FULL:
4649
return GMix(pars=pars)
4750
else:
@@ -831,6 +834,10 @@ class GMixModel(GMix):
831834
"""
832835
def __init__(self, pars, model):
833836

837+
assert model != 'bdf','use GMixBDF for bdf model'
838+
self._do_init(pars, model)
839+
840+
def _do_init(self, pars, model):
834841
self._model = _gmix_model_dict[model]
835842
self._model_name = _gmix_string_dict[self._model]
836843

@@ -928,17 +935,34 @@ def __repr__(self):
928935
class GMixBDF(GMixModel):
929936
"""
930937
Gaussian mixture representing a bulge+disk with
931-
fixed size ratio Td/Te=1
938+
fixed size ratio
939+
940+
Parameters
941+
----------
942+
pars: sequence
943+
[c1,c2,g1,g2,T,flux]
944+
TdByTe: number, optional
945+
Optionally set TdByTe. Defaults to 1.0
946+
947+
Notes: a value of 1.0 is not the most common value for real world
948+
galaxies. It is more typically ~0.3 when fitting to COSMOS galaxies.
949+
But 1.0 provides much more stable fits generally and does not reduce
950+
accuracy much.
932951
"""
933-
def __init__(self, pars):
934-
super(GMixBDF,self).__init__(pars,'bdf')
952+
def __init__(self, pars=None, TdByTe=1.0):
953+
assert pars is not None,'send pars='
954+
assert TdByTe is not None,'send TdByTe='
955+
956+
self._TdByTe = float(TdByTe)
957+
super(GMixBDF,self)._do_init(pars,'bdf')
935958

936959
def copy(self):
937960
"""
938961
Get a new GMix with the same parameters
939962
"""
940963
return GMixBDF(
941-
self._pars,
964+
pars=self._pars.copy(),
965+
TdByTe=self._TdByTe,
942966
)
943967

944968
def _fill(self, pars):
@@ -958,12 +982,14 @@ def _fill(self, pars):
958982
self._fill_func(
959983
gm,
960984
self._pars,
985+
self._TdByTe,
961986
)
962987

963988

964989
def __repr__(self):
965990
rep=super(GMixBDF,self).__repr__()
966991
rep = [
992+
'TdByTe: %g' % self._TdByTe,
967993
rep,
968994
]
969995
return '\n'.join(rep)
@@ -1060,6 +1086,8 @@ def copy(self):
10601086
GMIX_SERSIC=8
10611087
GMIX_CM=9
10621088

1089+
GMIX_BD=10
1090+
10631091
_gmix_model_dict={
10641092
'full': GMIX_FULL,
10651093
GMIX_FULL: GMIX_FULL,
@@ -1073,6 +1101,10 @@ def copy(self):
10731101
GMIX_DEV: GMIX_DEV,
10741102
'bdc': GMIX_BDC,
10751103
GMIX_BDC: GMIX_BDC,
1104+
1105+
'bd': GMIX_BD,
1106+
GMIX_BD: GMIX_BD,
1107+
10761108
'bdf': GMIX_BDF,
10771109
GMIX_BDF: GMIX_BDF,
10781110

@@ -1099,6 +1131,10 @@ def copy(self):
10991131
'dev':'dev',
11001132
GMIX_BDC:'bdc',
11011133
'bdc':'bdc',
1134+
1135+
GMIX_BD:'bd',
1136+
'bd':'bd',
1137+
11021138
GMIX_BDF:'bdf',
11031139
'bdf':'bdf',
11041140

@@ -1120,10 +1156,12 @@ def copy(self):
11201156
GMIX_DEV:6,
11211157

11221158
GMIX_CM:6,
1159+
1160+
GMIX_BD:8,
1161+
11231162
GMIX_BDF:7,
11241163

11251164
GMIX_BDC:8,
1126-
GMIX_BDF:7,
11271165
GMIX_SERSIC:7,
11281166
}
11291167

@@ -1138,10 +1176,10 @@ def copy(self):
11381176
'dev':10,
11391177

11401178
GMIX_CM:16,
1179+
GMIX_BD:16,
11411180
GMIX_BDF:16,
11421181

11431182
GMIX_BDC:16,
1144-
GMIX_BDF:16,
11451183
GMIX_SERSIC:4,
11461184

11471185
'em1':1,

0 commit comments

Comments
 (0)