public software.sextractor

[/] [trunk/] [src/] [profit.c] - Blame information for rev 309

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 233 bertin
/*
2
*                               profit.c
3 42 bertin
*
4 233 bertin
* Fit a range of galaxy models to an image.
5 42 bertin
*
6 233 bertin
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7 42 bertin
*
8 233 bertin
*       This file part of:      SExtractor
9 42 bertin
*
10 305 bertin
*       Copyright:              (C) 2006-2013 Emmanuel Bertin -- IAP/CNRS/UPMC
11 42 bertin
*
12 233 bertin
*       License:                GNU General Public License
13
*
14
*       SExtractor is free software: you can redistribute it and/or modify
15
*       it under the terms of the GNU General Public License as published by
16
*       the Free Software Foundation, either version 3 of the License, or
17
*       (at your option) any later version.
18
*       SExtractor is distributed in the hope that it will be useful,
19
*       but WITHOUT ANY WARRANTY; without even the implied warranty of
20
*       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
*       GNU General Public License for more details.
22
*       You should have received a copy of the GNU General Public License
23
*       along with SExtractor. If not, see <http://www.gnu.org/licenses/>.
24
*
25 307 bertin
*       Last modified:          05/04/2013
26 233 bertin
*
27
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
28 42 bertin
 
29
#ifdef HAVE_CONFIG_H
30
#include        "config.h"
31
#endif
32
 
33 206 bertin
#ifndef HAVE_MATHIMF_H
34
#define _GNU_SOURCE
35
#endif
36
 
37 201 bertin
#include        <math.h>
38 42 bertin
#include        <stdio.h>
39
#include        <stdlib.h>
40
#include        <string.h>
41
 
42
#include        "define.h"
43
#include        "globals.h"
44
#include        "prefs.h"
45
#include        "fits/fitscat.h"
46 228 bertin
#include        "levmar/levmar.h"
47 50 bertin
#include        "fft.h"
48 123 bertin
#include        "fitswcs.h"
49 42 bertin
#include        "check.h"
50 229 bertin
#include        "image.h"
51 141 bertin
#include        "pattern.h"
52 50 bertin
#include        "psf.h"
53 42 bertin
#include        "profit.h"
54
 
55 207 bertin
static double   prof_gammainc(double x, double a),
56
                prof_gamma(double x);
57 201 bertin
static float    prof_interpolate(profstruct *prof, float *posin);
58
static float    interpolate_pix(float *posin, float *pix, int *naxisn,
59 52 bertin
                interpenum interptype);
60 50 bertin
 
61 201 bertin
static void     make_kernel(float pos, float *kernel, interpenum interptype);
62 50 bertin
 
63 42 bertin
/*------------------------------- variables ---------------------------------*/
64
 
65 209 bertin
const int       interp_kernwidth[5]={1,2,4,6,8};
66
 
67 233 bertin
const int       flux_flag[PARAM_NPARAM] = {0,
68
                                        1,0,0,
69 209 bertin
                                        1,0,0,0,0,
70
                                        1,0,0,0,
71
                                        1,0,0,0,0,0,0,0,
72
                                        1,0,0,
73
                                        1,0,0,
74
                                        1,0,0
75
                                        };
76
 
77 235 bertin
/* "Local" global variables for debugging purposes */
78 145 bertin
int theniter, the_gal;
79 48 bertin
static picstruct        *the_field, *the_wfield;
80 284 bertin
profitstruct            *theprofit,*thedprofit, *thepprofit, *theqprofit;
81 48 bertin
 
82 46 bertin
/****** profit_init ***********************************************************
83 244 bertin
PROTO   profitstruct profit_init(psfstruct *psf, unsigned int modeltype)
84 46 bertin
PURPOSE Allocate and initialize a new profile-fitting structure.
85 244 bertin
INPUT   Pointer to PSF structure,
86
        Model type.
87 46 bertin
OUTPUT  A pointer to an allocated profit structure.
88 117 bertin
NOTES   -.
89 42 bertin
AUTHOR  E. Bertin (IAP)
90 244 bertin
VERSION 22/04/2011
91 42 bertin
 ***/
92 244 bertin
profitstruct    *profit_init(psfstruct *psf, unsigned int modeltype)
93 42 bertin
  {
94 46 bertin
   profitstruct         *profit;
95 244 bertin
   int                  t, nmodels;
96 42 bertin
 
97 49 bertin
  QCALLOC(profit, profitstruct, 1);
98 58 bertin
  profit->psf = psf;
99 244 bertin
  QMALLOC(profit->prof, profstruct *, MODEL_NMAX);
100
  nmodels = 0;
101
  for (t=1; t<(1<<MODEL_NMAX); t<<=1)
102
    if (modeltype&t)
103
      profit->prof[nmodels++] = prof_init(profit, t);
104 221 bertin
/* Allocate memory for the complete model */
105
  QMALLOC16(profit->modpix, float, PROFIT_MAXMODSIZE*PROFIT_MAXMODSIZE);
106
  QMALLOC16(profit->modpix2, float, PROFIT_MAXMODSIZE*PROFIT_MAXMODSIZE);
107
  QMALLOC16(profit->cmodpix, float, PROFIT_MAXMODSIZE*PROFIT_MAXMODSIZE);
108
  QMALLOC16(profit->psfpix, float, PROFIT_MAXMODSIZE*PROFIT_MAXMODSIZE);
109
  QMALLOC16(profit->objpix, PIXTYPE, PROFIT_MAXOBJSIZE*PROFIT_MAXOBJSIZE);
110
  QMALLOC16(profit->objweight, PIXTYPE, PROFIT_MAXOBJSIZE*PROFIT_MAXOBJSIZE);
111
  QMALLOC16(profit->lmodpix, PIXTYPE, PROFIT_MAXOBJSIZE*PROFIT_MAXOBJSIZE);
112
  QMALLOC16(profit->lmodpix2, PIXTYPE, PROFIT_MAXOBJSIZE*PROFIT_MAXOBJSIZE);
113
  QMALLOC16(profit->resi, float, PROFIT_MAXOBJSIZE*PROFIT_MAXOBJSIZE);
114 305 bertin
  QMALLOC16(profit->presi, float, profit->nparam);
115 211 bertin
  QMALLOC16(profit->covar, float, profit->nparam*profit->nparam);
116 244 bertin
  profit->nprof = nmodels;
117 207 bertin
  profit->fluxfac = 1.0;        /* Default */
118 50 bertin
 
119 46 bertin
  return profit;
120 42 bertin
  }
121
 
122
 
123 46 bertin
/****** profit_end ************************************************************
124 42 bertin
PROTO   void prof_end(profstruct *prof)
125 46 bertin
PURPOSE End (deallocate) a profile-fitting structure.
126 42 bertin
INPUT   Prof structure.
127
OUTPUT  -.
128 117 bertin
NOTES   -.
129 42 bertin
AUTHOR  E. Bertin (IAP)
130 297 bertin
VERSION 12/07/2012
131 42 bertin
 ***/
132 46 bertin
void    profit_end(profitstruct *profit)
133 42 bertin
  {
134 49 bertin
   int  p;
135
 
136
  for (p=0; p<profit->nprof; p++)
137
    prof_end(profit->prof[p]);
138 221 bertin
  free(profit->modpix);
139
  free(profit->modpix2);
140
  free(profit->cmodpix);
141
  free(profit->psfpix);
142
  free(profit->lmodpix);
143
  free(profit->lmodpix2);
144
  free(profit->objpix);
145
  free(profit->objweight);
146
  free(profit->resi);
147 305 bertin
  free(profit->presi);
148 49 bertin
  free(profit->prof);
149 123 bertin
  free(profit->covar);
150 297 bertin
  QFFTWF_FREE(profit->psfdft);
151 46 bertin
  free(profit);
152 42 bertin
 
153
  return;
154
  }
155
 
156
 
157 65 bertin
/****** profit_fit ************************************************************
158
PROTO   void profit_fit(profitstruct *profit, picstruct *field,
159
                picstruct *wfield, objstruct *obj, obj2struct *obj2)
160 46 bertin
PURPOSE Fit profile(s) convolved with the PSF to a detected object.
161 42 bertin
INPUT   Array of profile structures,
162
        Number of profiles,
163 52 bertin
        Pointer to the profile-fitting structure,
164 42 bertin
        Pointer to the field,
165
        Pointer to the field weight,
166
        Pointer to the obj.
167 46 bertin
OUTPUT  Pointer to an allocated fit structure (containing details about the
168
        fit).
169 48 bertin
NOTES   It is a modified version of the lm_minimize() of lmfit.
170 46 bertin
AUTHOR  E. Bertin (IAP)
171 307 bertin
VERSION 05/04/2013
172 46 bertin
 ***/
173 65 bertin
void    profit_fit(profitstruct *profit,
174 52 bertin
                picstruct *field, picstruct *wfield,
175 50 bertin
                objstruct *obj, obj2struct *obj2)
176 46 bertin
  {
177 244 bertin
    profitstruct        *pprofit, *qprofit;
178 221 bertin
    patternstruct       *pattern;
179 52 bertin
    psfstruct           *psf;
180 50 bertin
    checkstruct         *check;
181 244 bertin
    double              emx2,emy2,emxy, a , cp,sp, cn, bn, n,
182 292 bertin
                        sump,sumq, sumpw2,sumqw2,sumpqw, sump0,sumq0, err;
183 244 bertin
    PIXTYPE             valp,valq,sig2;
184 221 bertin
    float               param0[PARAM_NPARAM], param1[PARAM_NPARAM],
185
                        param[PARAM_NPARAM],
186
                        **list,
187 209 bertin
                        *cov,
188 292 bertin
                        psf_fwhm, dchi2, aspect, chi2;
189 209 bertin
    int                 *index,
190
                        i,j,p, nparam, nparam2, ncomp, nprof;
191 46 bertin
 
192 128 bertin
  nparam = profit->nparam;
193 208 bertin
  nparam2 = nparam*nparam;
194 194 bertin
  nprof = profit->nprof;
195 294 bertin
 
196 52 bertin
  if (profit->psfdft)
197 297 bertin
    QFFTWF_FREE(profit->psfdft);
198 52 bertin
 
199 297 bertin
 
200 52 bertin
  psf = profit->psf;
201 118 bertin
  profit->pixstep = psf->pixstep;
202 211 bertin
  obj2->prof_flag = 0;
203 52 bertin
 
204
/* Create pixmaps at image resolution */
205 211 bertin
  profit->ix = (int)(obj->mx + 0.49999);/* internal convention: 1st pix = 0 */
206
  profit->iy = (int)(obj->my + 0.49999);/* internal convention: 1st pix = 0 */
207 51 bertin
  psf_fwhm = psf->masksize[0]*psf->pixstep;
208 233 bertin
  profit->objnaxisn[0] = (((int)((obj->xmax-obj->xmin+1) + psf_fwhm + 0.499)
209 75 bertin
                *1.2)/2)*2 + 1;
210 233 bertin
  profit->objnaxisn[1] = (((int)((obj->ymax-obj->ymin+1) + psf_fwhm + 0.499)
211 75 bertin
                *1.2)/2)*2 + 1;
212 117 bertin
  if (profit->objnaxisn[1]<profit->objnaxisn[0])
213
    profit->objnaxisn[1] = profit->objnaxisn[0];
214
  else
215
    profit->objnaxisn[0] = profit->objnaxisn[1];
216 211 bertin
  if (profit->objnaxisn[0]>PROFIT_MAXOBJSIZE)
217
    {
218 212 bertin
    profit->subsamp = ceil((float)profit->objnaxisn[0]/PROFIT_MAXOBJSIZE);
219
    profit->objnaxisn[1] = (profit->objnaxisn[0] /= (int)profit->subsamp);
220 211 bertin
    obj2->prof_flag |= PROFLAG_OBJSUB;
221
    }
222
  else
223 212 bertin
    profit->subsamp = 1.0;
224 221 bertin
  profit->nobjpix = profit->objnaxisn[0]*profit->objnaxisn[1];
225 117 bertin
 
226 305 bertin
/* Create pixmap at model resolution */
227
  profit->modnaxisn[0] =
228
        ((int)(profit->objnaxisn[0]*profit->subsamp/profit->pixstep
229
                +0.4999)/2+1)*2;
230
  profit->modnaxisn[1] =
231
        ((int)(profit->objnaxisn[1]*profit->subsamp/profit->pixstep
232
                +0.4999)/2+1)*2;
233
  if (profit->modnaxisn[1] < profit->modnaxisn[0])
234
    profit->modnaxisn[1] = profit->modnaxisn[0];
235
  else
236
    profit->modnaxisn[0] = profit->modnaxisn[1];
237
  if (profit->modnaxisn[0]>PROFIT_MAXMODSIZE)
238
    {
239
    profit->pixstep = (double)profit->modnaxisn[0] / PROFIT_MAXMODSIZE;
240
    profit->modnaxisn[0] = profit->modnaxisn[1] = PROFIT_MAXMODSIZE;
241
    obj2->prof_flag |= PROFLAG_MODSUB;
242
    }
243
  profit->nmodpix = profit->modnaxisn[0]*profit->modnaxisn[1];
244
 
245 78 bertin
/* Use (dirty) global variables to interface with lmfit */
246
  the_field = field;
247
  the_wfield = wfield;
248
  theprofit = profit;
249 146 bertin
  profit->obj = obj;
250
  profit->obj2 = obj2;
251 78 bertin
 
252 305 bertin
/* Compute the local PSF */
253
  profit_psf(profit);
254
 
255 146 bertin
  profit->nresi = profit_copyobjpix(profit, field, wfield);
256 305 bertin
  profit->npresi = 0;
257 211 bertin
/* Check if the number of constraints exceeds the number of free parameters */
258 128 bertin
  if (profit->nresi < nparam)
259 49 bertin
    {
260 176 bertin
    if (FLAG(obj2.prof_vector))
261
      for (p=0; p<nparam; p++)
262
        obj2->prof_vector[p] = 0.0;
263 208 bertin
    if (FLAG(obj2.prof_errvector))
264
      for (p=0; p<nparam; p++)
265
        obj2->prof_errvector[p] = 0.0;
266
    if (FLAG(obj2.prof_errmatrix))
267
      for (p=0; p<nparam2; p++)
268
        obj2->prof_errmatrix[p] = 0.0;
269 50 bertin
    obj2->prof_niter = 0;
270 211 bertin
    obj2->prof_flag |= PROFLAG_NOTCONST;
271 50 bertin
    return;
272 49 bertin
    }
273 48 bertin
 
274 50 bertin
/* Set initial guesses and boundaries */
275 284 bertin
  profit->guesssigbkg = profit->sigma = obj->sigbkg;
276
  profit->guessdx = obj->mx - (int)(obj->mx+0.49999);
277
  profit->guessdy = obj->my - (int)(obj->my+0.49999);
278 246 bertin
  if ((profit->guessflux = obj2->flux_auto) <= 0.0)
279
    profit->guessflux = 0.0;
280
  if ((profit->guessfluxmax = 10.0*obj2->fluxerr_auto) <= profit->guessflux)
281
    profit->guessfluxmax = profit->guessflux;
282
  if (profit->guessfluxmax <= 0.0)
283
    profit->guessfluxmax = 1.0;
284 284 bertin
  if ((profit->guessradius = 0.5*psf->fwhm) < obj2->hl_radius)
285
    profit->guessradius = obj2->hl_radius;
286
  profit->guessaspect = obj->b/obj->a;
287
  profit->guessposang = obj->theta;
288 115 bertin
 
289 146 bertin
  profit_resetparams(profit);
290 50 bertin
 
291 123 bertin
/* Actual minimisation */
292 209 bertin
  fft_reset();
293 211 bertin
the_gal++;
294 221 bertin
 
295 235 bertin
/*
296
char str[1024];
297
sprintf(str, "obj_%04d.fits", the_gal);
298
catstruct *bcat;
299
float *bpix, *opix,*lmodpix,*objpix;
300
bcat=read_cat("base.fits");
301
QMALLOC(bpix, float, field->npix);
302
QFSEEK(bcat->file, bcat->tab->bodypos, SEEK_SET, bcat->filename);
303
read_body(bcat->tab, bpix, field->npix);
304
free_cat(&bcat,1);
305
bcat=read_cat(str);
306
QMALLOC(opix, float, profit->nobjpix);
307
QFSEEK(bcat->file, bcat->tab->bodypos, SEEK_SET, bcat->filename);
308
read_body(bcat->tab, opix, profit->nobjpix);
309
free_cat(&bcat,1);
310
addfrombig(bpix, field->width, field->height,
311
                profit->objpix, profit->objnaxisn[0],profit->objnaxisn[1],
312
                profit->ix,profit->iy, -1.0);
313
objpix = profit->objpix;
314
lmodpix = opix;
315
for (i=profit->nobjpix; i--;)
316
*(objpix++) += *(lmodpix++);
317
free(bpix);
318
free(opix);
319
*/
320 79 bertin
  profit->niter = profit_minimize(profit, PROFIT_MAXITER);
321 221 bertin
/*
322 235 bertin
profit_residuals(profit,field,wfield, 0.0, profit->paraminit, NULL);
323
check=initcheck(str, CHECK_OTHER,1);
324
check->width = profit->objnaxisn[0];
325
check->height = profit->objnaxisn[1];
326
reinitcheck(field,check);
327
memcpy(check->pix, profit->lmodpix, profit->nobjpix*sizeof(float));
328
reendcheck(field,check);
329
endcheck(check);
330
 
331 221 bertin
  chi2 = profit->chi2;
332
  for (p=0; p<nparam; p++)
333
    param1[p] = profit->paraminit[p];
334
  profit_resetparams(profit);
335
  for (p=0; p<nparam; p++)
336
    profit->paraminit[p] = param1[p] + (profit->paraminit[p]<param1[p]?1.0:-1.0)
337
                        * sqrt(profit->covar[p*(nparam+1)]);
338 200 bertin
 
339 221 bertin
  profit->niter = profit_minimize(profit, PROFIT_MAXITER);
340
  if (chi2<profit->chi2)
341
    for (p=0; p<nparam; p++)
342
      profit->paraminit[p] = param1[p];
343
 
344
list = profit->paramlist;
345
index = profit->paramindex;
346
for (i=0; i<PARAM_NPARAM; i++)
347
if (list[i] && i!= PARAM_SPHEROID_ASPECT && i!=PARAM_SPHEROID_POSANG)
348
profit->freeparam_flag[index[i]] = 0;
349
profit->niter = profit_minimize(profit, PROFIT_MAXITER);
350
*/
351 284 bertin
 
352 246 bertin
  if (profit->nlimmin)
353
    obj2->prof_flag |= PROFLAG_MINLIM;
354
  if (profit->nlimmax)
355
    obj2->prof_flag |= PROFLAG_MAXLIM;
356
 
357 128 bertin
  for (p=0; p<nparam; p++)
358
    profit->paramerr[p]= sqrt(profit->covar[p*(nparam+1)]);
359 126 bertin
 
360 50 bertin
/* CHECK-Images */
361 221 bertin
  if ((check = prefs.check[CHECK_PROFILES]))
362
    {
363
    profit_residuals(profit,field,wfield, 0.0, profit->paraminit, NULL);
364 305 bertin
    if (profit->subsamp>1.0)
365
      addcheck_resample(check, profit->lmodpix,
366
                profit->objnaxisn[0],profit->objnaxisn[1],
367
                profit->ix,profit->iy, 1.0/profit->subsamp,
368
                1.0/(profit->subsamp*profit->subsamp));
369
    else
370
      addcheck(check, profit->lmodpix,
371
                profit->objnaxisn[0],profit->objnaxisn[1],
372 221 bertin
                profit->ix,profit->iy, 1.0);
373
    }
374 235 bertin
 
375 50 bertin
  if ((check = prefs.check[CHECK_SUBPROFILES]))
376 51 bertin
    {
377 221 bertin
    profit_residuals(profit,field,wfield, 0.0, profit->paraminit, NULL);
378 305 bertin
    if (profit->subsamp>1.0)
379
      addcheck_resample(check, profit->lmodpix,
380
                profit->objnaxisn[0],profit->objnaxisn[1],
381
                profit->ix,profit->iy, 1.0/profit->subsamp,
382
                -1.0/(profit->subsamp*profit->subsamp));
383
    else
384
      addcheck(check, profit->lmodpix,
385
                profit->objnaxisn[0],profit->objnaxisn[1],
386 145 bertin
                profit->ix,profit->iy, -1.0);
387 51 bertin
    }
388 221 bertin
  if ((check = prefs.check[CHECK_SPHEROIDS]))
389 51 bertin
    {
390 221 bertin
/*-- Set to 0 flux components that do not belong to spheroids */
391
    for (p=0; p<profit->nparam; p++)
392
      param[p] = profit->paraminit[p];
393
    list = profit->paramlist;
394
    index = profit->paramindex;
395
    for (i=0; i<PARAM_NPARAM; i++)
396
      if (list[i] && flux_flag[i] && i!= PARAM_SPHEROID_FLUX)
397
        param[index[i]] = 0.0;
398
    profit_residuals(profit,field,wfield, 0.0, param, NULL);
399 307 bertin
    if (profit->subsamp>1.0)
400
      addcheck_resample(check, profit->lmodpix,
401
                profit->objnaxisn[0],profit->objnaxisn[1],
402
                profit->ix,profit->iy, 1.0/profit->subsamp,
403
                1.0/(profit->subsamp*profit->subsamp));
404
    else
405
      addcheck(check, profit->lmodpix,
406
                profit->objnaxisn[0],profit->objnaxisn[1],
407 145 bertin
                profit->ix,profit->iy, 1.0);
408 51 bertin
    }
409 221 bertin
  if ((check = prefs.check[CHECK_SUBSPHEROIDS]))
410
    {
411
/*-- Set to 0 flux components that do not belong to spheroids */
412
    for (p=0; p<profit->nparam; p++)
413
      param[p] = profit->paraminit[p];
414
    list = profit->paramlist;
415
    index = profit->paramindex;
416
    for (i=0; i<PARAM_NPARAM; i++)
417
      if (list[i] && flux_flag[i] && i!= PARAM_SPHEROID_FLUX)
418
        param[index[i]] = 0.0;
419
    profit_residuals(profit,field,wfield, 0.0, param, NULL);
420 307 bertin
    if (profit->subsamp>1.0)
421
      addcheck_resample(check, profit->lmodpix,
422
                profit->objnaxisn[0],profit->objnaxisn[1],
423
                profit->ix,profit->iy, 1.0/profit->subsamp,
424
                -1.0/(profit->subsamp*profit->subsamp));
425
    else
426
      addcheck(check, profit->lmodpix,
427
                profit->objnaxisn[0],profit->objnaxisn[1],
428 221 bertin
                profit->ix,profit->iy, -1.0);
429
    }
430
  if ((check = prefs.check[CHECK_DISKS]))
431
    {
432
/*-- Set to 0 flux components that do not belong to disks */
433
    for (p=0; p<profit->nparam; p++)
434
      param[p] = profit->paraminit[p];
435
    list = profit->paramlist;
436
    index = profit->paramindex;
437
    for (i=0; i<PARAM_NPARAM; i++)
438
      if (list[i] && flux_flag[i] && i!= PARAM_DISK_FLUX)
439
        param[index[i]] = 0.0;
440
    profit_residuals(profit,field,wfield, 0.0, param, NULL);
441 307 bertin
    if (profit->subsamp>1.0)
442
      addcheck_resample(check, profit->lmodpix,
443
                profit->objnaxisn[0],profit->objnaxisn[1],
444
                profit->ix,profit->iy, 1.0/profit->subsamp,
445
                1.0/(profit->subsamp*profit->subsamp));
446
    else
447
      addcheck(check, profit->lmodpix,
448
                profit->objnaxisn[0],profit->objnaxisn[1],
449 221 bertin
                profit->ix,profit->iy, 1.0);
450
    }
451
  if ((check = prefs.check[CHECK_SUBDISKS]))
452
    {
453
/*-- Set to 0 flux components that do not belong to disks */
454
    for (p=0; p<profit->nparam; p++)
455
      param[p] = profit->paraminit[p];
456
    list = profit->paramlist;
457
    index = profit->paramindex;
458
    for (i=0; i<PARAM_NPARAM; i++)
459
      if (list[i] && flux_flag[i] && i!= PARAM_DISK_FLUX)
460
        param[index[i]] = 0.0;
461
    profit_residuals(profit,field,wfield, 0.0, param, NULL);
462 307 bertin
    if (profit->subsamp>1.0)
463
      addcheck_resample(check, profit->lmodpix,
464
                profit->objnaxisn[0],profit->objnaxisn[1],
465
                profit->ix,profit->iy, 1.0/profit->subsamp,
466
                -1.0/(profit->subsamp*profit->subsamp));
467
    else
468
      addcheck(check, profit->lmodpix,
469
                profit->objnaxisn[0],profit->objnaxisn[1],
470 221 bertin
                profit->ix,profit->iy, -1.0);
471
    }
472 235 bertin
 
473 221 bertin
/* Compute compressed residuals */
474
  profit_residuals(profit,field,wfield, 10.0, profit->paraminit,profit->resi);
475
 
476 73 bertin
/* Fill measurement parameters */
477 69 bertin
  if (FLAG(obj2.prof_vector))
478
    {
479 128 bertin
    for (p=0; p<nparam; p++)
480 221 bertin
      obj2->prof_vector[p]= profit->paraminit[p];
481 69 bertin
    }
482 127 bertin
  if (FLAG(obj2.prof_errvector))
483
    {
484 128 bertin
    for (p=0; p<nparam; p++)
485
      obj2->prof_errvector[p]= profit->paramerr[p];
486 127 bertin
    }
487 208 bertin
  if (FLAG(obj2.prof_errmatrix))
488
    {
489
    for (p=0; p<nparam2; p++)
490
      obj2->prof_errmatrix[p]= profit->covar[p];
491
    }
492 89 bertin
 
493 79 bertin
  obj2->prof_niter = profit->niter;
494 73 bertin
  obj2->flux_prof = profit->flux;
495 194 bertin
  if (FLAG(obj2.fluxerr_prof))
496
    {
497
    err = 0.0;
498 209 bertin
    cov = profit->covar;
499
    index = profit->paramindex;
500
    list = profit->paramlist;
501
    for (i=0; i<PARAM_NPARAM; i++)
502
      if (flux_flag[i] && list[i])
503
        {
504
        cov = profit->covar + nparam*index[i];
505
        for (j=0; j<PARAM_NPARAM; j++)
506
          if (flux_flag[j] && list[j])
507
            err += cov[index[j]];
508
        }
509 194 bertin
    obj2->fluxerr_prof = err>0.0? sqrt(err): 0.0;
510
    }
511
 
512 180 bertin
  obj2->prof_chi2 = (profit->nresi > profit->nparam)?
513
                profit->chi2 / (profit->nresi - profit->nparam) : 0.0;
514
 
515 244 bertin
/* Position */
516 131 bertin
  if (FLAG(obj2.x_prof))
517
    {
518
    i = profit->paramindex[PARAM_X];
519
    j = profit->paramindex[PARAM_Y];
520 145 bertin
/*-- Model coordinates follow the FITS convention (first pixel at 1,1) */
521 179 bertin
    if (profit->paramlist[PARAM_X])
522
      {
523 217 bertin
      obj2->x_prof = (double)profit->ix + *profit->paramlist[PARAM_X] + 1.0;
524 179 bertin
      obj2->poserrmx2_prof = emx2 = profit->covar[i*(nparam+1)];
525
      }
526
    else
527
      emx2 = 0.0;
528
    if (profit->paramlist[PARAM_Y])
529
      {
530 217 bertin
      obj2->y_prof = (double)profit->iy + *profit->paramlist[PARAM_Y] + 1.0;
531 179 bertin
      obj2->poserrmy2_prof = emy2 = profit->covar[j*(nparam+1)];
532
      }
533
    else
534
      emy2 = 0.0;
535
    if (profit->paramlist[PARAM_X] && profit->paramlist[PARAM_Y])
536
      obj2->poserrmxy_prof = emxy = profit->covar[i+j*nparam];
537
    else
538
      emxy = 0.0;
539 131 bertin
 
540 135 bertin
/*-- Error ellipse parameters */
541
    if (FLAG(obj2.poserra_prof))
542
      {
543
       double   pmx2,pmy2,temp,theta;
544 131 bertin
 
545 135 bertin
      if (fabs(temp=emx2-emy2) > 0.0)
546
        theta = atan2(2.0 * emxy,temp) / 2.0;
547
      else
548
        theta = PI/4.0;
549 131 bertin
 
550 135 bertin
      temp = sqrt(0.25*temp*temp+ emxy*emxy);
551
      pmy2 = pmx2 = 0.5*(emx2+emy2);
552
      pmx2+=temp;
553
      pmy2-=temp;
554 131 bertin
 
555 290 bertin
      obj2->poserra_prof = (float)sqrt(pmx2>0.0? pmx2 : 0.0);
556
      obj2->poserrb_prof = (float)sqrt(pmy2>0.0? pmy2 : 0.0);
557 201 bertin
      obj2->poserrtheta_prof = (float)(theta/DEG);
558 135 bertin
      }
559 131 bertin
 
560 135 bertin
    if (FLAG(obj2.poserrcxx_prof))
561
      {
562
       double   temp;
563 131 bertin
 
564 135 bertin
      obj2->poserrcxx_prof = (float)(emy2/(temp=emx2*emy2-emxy*emxy));
565
      obj2->poserrcyy_prof = (float)(emx2/temp);
566
      obj2->poserrcxy_prof = (float)(-2*emxy/temp);
567
      }
568 131 bertin
    }
569
 
570 244 bertin
/* Equivalent noise area */
571
  if (FLAG(obj2.prof_noisearea))
572
    obj2->prof_noisearea = profit_noisearea(profit);
573
 
574
/* Second order moments and ellipticities */
575
  if (FLAG(obj2.prof_mx2))
576
    profit_moments(profit, obj2);
577
 
578
/* Second order moments of the convolved model (used by other parameters) */
579
  if (FLAG(obj2.prof_convmx2))
580
    profit_convmoments(profit, obj2);
581
 
582
/* "Hybrid" magnitudes */
583 235 bertin
  if (FLAG(obj2.fluxcor_prof))
584
    {
585
    profit_residuals(profit,field,wfield, 0.0, profit->paraminit, NULL);
586
    profit_fluxcor(profit, obj, obj2);
587
    }
588
 
589 221 bertin
/* Do measurements on the rasterised model (surface brightnesses) */
590 264 bertin
  if (FLAG(obj2.fluxeff_prof))
591 221 bertin
    profit_surface(profit, obj2);
592 207 bertin
 
593 233 bertin
/* Background offset */
594
  if (FLAG(obj2.prof_offset_flux))
595
    {
596
    obj2->prof_offset_flux = *profit->paramlist[PARAM_BACK];
597
    obj2->prof_offset_fluxerr=profit->paramerr[profit->paramindex[PARAM_BACK]];
598
    }
599
 
600
/* Point source */
601
  if (FLAG(obj2.prof_dirac_flux))
602
    {
603
    obj2->prof_dirac_flux = *profit->paramlist[PARAM_DIRAC_FLUX];
604
    obj2->prof_dirac_fluxerr =
605
                profit->paramerr[profit->paramindex[PARAM_DIRAC_FLUX]];
606
    }
607
 
608 207 bertin
/* Spheroid */
609 115 bertin
  if (FLAG(obj2.prof_spheroid_flux))
610
    {
611 218 bertin
    if ((aspect = *profit->paramlist[PARAM_SPHEROID_ASPECT]) > 1.0)
612
      {
613
      *profit->paramlist[PARAM_SPHEROID_REFF] *= aspect;
614
      profit->paramerr[profit->paramindex[PARAM_SPHEROID_REFF]] *= aspect;
615
      profit->paramerr[profit->paramindex[PARAM_SPHEROID_ASPECT]]
616
                        /= (aspect*aspect);
617
      *profit->paramlist[PARAM_SPHEROID_ASPECT] = 1.0 / aspect;
618
      *profit->paramlist[PARAM_SPHEROID_POSANG] += 90.0;
619
      }
620 115 bertin
    obj2->prof_spheroid_flux = *profit->paramlist[PARAM_SPHEROID_FLUX];
621 128 bertin
    obj2->prof_spheroid_fluxerr =
622
                profit->paramerr[profit->paramindex[PARAM_SPHEROID_FLUX]];
623 115 bertin
    obj2->prof_spheroid_reff = *profit->paramlist[PARAM_SPHEROID_REFF];
624 128 bertin
    obj2->prof_spheroid_refferr =
625
                profit->paramerr[profit->paramindex[PARAM_SPHEROID_REFF]];
626 115 bertin
    obj2->prof_spheroid_aspect = *profit->paramlist[PARAM_SPHEROID_ASPECT];
627 128 bertin
    obj2->prof_spheroid_aspecterr =
628
                profit->paramerr[profit->paramindex[PARAM_SPHEROID_ASPECT]];
629 123 bertin
    obj2->prof_spheroid_theta =
630
                        fmod_m90_p90(*profit->paramlist[PARAM_SPHEROID_POSANG]);
631 128 bertin
    obj2->prof_spheroid_thetaerr =
632
                profit->paramerr[profit->paramindex[PARAM_SPHEROID_POSANG]];
633 115 bertin
    if (FLAG(obj2.prof_spheroid_sersicn))
634 128 bertin
      {
635 116 bertin
      obj2->prof_spheroid_sersicn = *profit->paramlist[PARAM_SPHEROID_SERSICN];
636 128 bertin
      obj2->prof_spheroid_sersicnerr =
637
                profit->paramerr[profit->paramindex[PARAM_SPHEROID_SERSICN]];
638
      }
639 206 bertin
    else
640
      obj2->prof_spheroid_sersicn = 4.0;
641
    if (FLAG(obj2.prof_spheroid_peak))
642
      {
643
      n = obj2->prof_spheroid_sersicn;
644 207 bertin
      bn = 2.0*n - 1.0/3.0 + 4.0/(405.0*n) + 46.0/(25515.0*n*n)
645 206 bertin
                + 131.0/(1148175*n*n*n);        /* Ciotti & Bertin 1999 */
646 207 bertin
      cn = n * prof_gamma(2.0*n) * pow(bn, -2.0*n);
647 206 bertin
      obj2->prof_spheroid_peak = obj2->prof_spheroid_reff>0.0?
648 264 bertin
        obj2->prof_spheroid_flux
649 207 bertin
                / (2.0 * PI * cn
650 206 bertin
                * obj2->prof_spheroid_reff*obj2->prof_spheroid_reff
651 207 bertin
                * obj2->prof_spheroid_aspect)
652 206 bertin
        : 0.0;
653
      if (FLAG(obj2.prof_spheroid_fluxeff))
654 207 bertin
        obj2->prof_spheroid_fluxeff = obj2->prof_spheroid_peak * exp(-bn);
655
      if (FLAG(obj2.prof_spheroid_fluxmean))
656
        obj2->prof_spheroid_fluxmean = obj2->prof_spheroid_peak * cn;
657 206 bertin
      }
658 115 bertin
    }
659 50 bertin
 
660 132 bertin
/* Disk */
661 115 bertin
  if (FLAG(obj2.prof_disk_flux))
662
    {
663 218 bertin
    if ((aspect = *profit->paramlist[PARAM_DISK_ASPECT]) > 1.0)
664
      {
665
      *profit->paramlist[PARAM_DISK_SCALE] *= aspect;
666
      profit->paramerr[profit->paramindex[PARAM_DISK_SCALE]] *= aspect;
667
      profit->paramerr[profit->paramindex[PARAM_DISK_ASPECT]]
668
                        /= (aspect*aspect);
669
      *profit->paramlist[PARAM_DISK_ASPECT] = 1.0 / aspect;
670
      *profit->paramlist[PARAM_DISK_POSANG] += 90.0;
671
      }
672 115 bertin
    obj2->prof_disk_flux = *profit->paramlist[PARAM_DISK_FLUX];
673 128 bertin
    obj2->prof_disk_fluxerr =
674
                profit->paramerr[profit->paramindex[PARAM_DISK_FLUX]];
675 115 bertin
    obj2->prof_disk_scale = *profit->paramlist[PARAM_DISK_SCALE];
676 128 bertin
    obj2->prof_disk_scaleerr =
677
                profit->paramerr[profit->paramindex[PARAM_DISK_SCALE]];
678 115 bertin
    obj2->prof_disk_aspect = *profit->paramlist[PARAM_DISK_ASPECT];
679 128 bertin
    obj2->prof_disk_aspecterr =
680
                profit->paramerr[profit->paramindex[PARAM_DISK_ASPECT]];
681 123 bertin
    obj2->prof_disk_theta = fmod_m90_p90(*profit->paramlist[PARAM_DISK_POSANG]);
682 128 bertin
    obj2->prof_disk_thetaerr =
683
                profit->paramerr[profit->paramindex[PARAM_DISK_POSANG]];
684 132 bertin
    if (FLAG(obj2.prof_disk_inclination))
685
      {
686
      obj2->prof_disk_inclination = acos(obj2->prof_disk_aspect) / DEG;
687
      if (FLAG(obj2.prof_disk_inclinationerr))
688
        {
689
        a = sqrt(1.0-obj2->prof_disk_aspect*obj2->prof_disk_aspect);
690
        obj2->prof_disk_inclinationerr = obj2->prof_disk_aspecterr
691
                                        /(a>0.1? a : 0.1)/DEG;
692
        }
693
      }
694 142 bertin
 
695 206 bertin
    if (FLAG(obj2.prof_disk_peak))
696
      {
697
      obj2->prof_disk_peak = obj2->prof_disk_scale>0.0?
698 264 bertin
        obj2->prof_disk_flux
699 206 bertin
        / (2.0 * PI * obj2->prof_disk_scale*obj2->prof_disk_scale
700
                * obj2->prof_disk_aspect)
701
        : 0.0;
702
      if (FLAG(obj2.prof_disk_fluxeff))
703 207 bertin
        obj2->prof_disk_fluxeff = obj2->prof_disk_peak * 0.186682; /* e^-(b_n)*/
704
      if (FLAG(obj2.prof_disk_fluxmean))
705
        obj2->prof_disk_fluxmean = obj2->prof_disk_peak * 0.355007;/* b_n^(-2)*/
706 206 bertin
      }
707
 
708 143 bertin
/* Disk pattern */
709 147 bertin
    if (prefs.pattern_flag)
710 143 bertin
      {
711 180 bertin
      profit_residuals(profit,field,wfield, PROFIT_DYNPARAM,
712 221 bertin
                        profit->paraminit,profit->resi);
713 171 bertin
      pattern = pattern_init(profit, prefs.pattern_type,
714 147 bertin
                prefs.prof_disk_patternncomp);
715 143 bertin
      pattern_fit(pattern, profit);
716 152 bertin
      if (FLAG(obj2.prof_disk_patternspiral))
717
        obj2->prof_disk_patternspiral = pattern_spiral(pattern);
718 147 bertin
      if (FLAG(obj2.prof_disk_patternvector))
719
        {
720
        ncomp = pattern->size[2];
721
        for (p=0; p<ncomp; p++)
722
          obj2->prof_disk_patternvector[p] = (float)pattern->coeff[p];
723
        }
724
      if (FLAG(obj2.prof_disk_patternmodvector))
725
        {
726
        ncomp = pattern->ncomp*pattern->nfreq;
727
        for (p=0; p<ncomp; p++)
728
          obj2->prof_disk_patternmodvector[p] = (float)pattern->mcoeff[p];
729
        }
730
      if (FLAG(obj2.prof_disk_patternargvector))
731
        {
732
        ncomp = pattern->ncomp*pattern->nfreq;
733
        for (p=0; p<ncomp; p++)
734
          obj2->prof_disk_patternargvector[p] = (float)pattern->acoeff[p];
735
        }
736 143 bertin
      pattern_end(pattern);
737
      }
738 142 bertin
 
739 132 bertin
/* Bar */
740 116 bertin
    if (FLAG(obj2.prof_bar_flux))
741
      {
742
      obj2->prof_bar_flux = *profit->paramlist[PARAM_BAR_FLUX];
743 130 bertin
      obj2->prof_bar_fluxerr =
744
                profit->paramerr[profit->paramindex[PARAM_BAR_FLUX]];
745 116 bertin
      obj2->prof_bar_length = *profit->paramlist[PARAM_ARMS_START]
746
                                **profit->paramlist[PARAM_DISK_SCALE];
747 130 bertin
      obj2->prof_bar_lengtherr = *profit->paramlist[PARAM_ARMS_START]
748
                  * profit->paramerr[profit->paramindex[PARAM_DISK_SCALE]]
749
                + *profit->paramlist[PARAM_DISK_SCALE]
750
                  * profit->paramerr[profit->paramindex[PARAM_ARMS_START]];
751 116 bertin
      obj2->prof_bar_aspect = *profit->paramlist[PARAM_BAR_ASPECT];
752 130 bertin
      obj2->prof_bar_aspecterr =
753
                profit->paramerr[profit->paramindex[PARAM_BAR_ASPECT]];
754 123 bertin
      obj2->prof_bar_posang =
755
                        fmod_m90_p90(*profit->paramlist[PARAM_ARMS_POSANG]);
756 130 bertin
      obj2->prof_bar_posangerr =
757
                profit->paramerr[profit->paramindex[PARAM_ARMS_POSANG]];
758 123 bertin
      if (FLAG(obj2.prof_bar_theta))
759 130 bertin
        {
760
        cp = cos(obj2->prof_bar_posang*DEG);
761
        sp = sin(obj2->prof_bar_posang*DEG);
762
        a = obj2->prof_disk_aspect;
763
        obj2->prof_bar_theta = fmod_m90_p90(atan2(a*sp,cp)/DEG
764
                                + obj2->prof_disk_theta);
765
        obj2->prof_bar_thetaerr = obj2->prof_bar_posangerr*a/(cp*cp+a*a*sp*sp);
766
        }
767 132 bertin
 
768
/* Arms */
769 116 bertin
      if (FLAG(obj2.prof_arms_flux))
770
        {
771
        obj2->prof_arms_flux = *profit->paramlist[PARAM_ARMS_FLUX];
772 130 bertin
        obj2->prof_arms_fluxerr =
773
                profit->paramerr[profit->paramindex[PARAM_ARMS_FLUX]];
774 132 bertin
        obj2->prof_arms_pitch =
775
                fmod_m90_p90(*profit->paramlist[PARAM_ARMS_PITCH]);
776 130 bertin
        obj2->prof_arms_pitcherr =
777
                profit->paramerr[profit->paramindex[PARAM_ARMS_PITCH]];
778 116 bertin
        obj2->prof_arms_start = *profit->paramlist[PARAM_ARMS_START]
779
                                **profit->paramlist[PARAM_DISK_SCALE];
780 130 bertin
        obj2->prof_arms_starterr = *profit->paramlist[PARAM_ARMS_START]
781
                  * profit->paramerr[profit->paramindex[PARAM_DISK_SCALE]]
782
                + *profit->paramlist[PARAM_DISK_SCALE]
783
                  * profit->paramerr[profit->paramindex[PARAM_ARMS_START]];
784 116 bertin
        obj2->prof_arms_quadfrac = *profit->paramlist[PARAM_ARMS_QUADFRAC];
785 130 bertin
        obj2->prof_arms_quadfracerr =
786
                profit->paramerr[profit->paramindex[PARAM_ARMS_QUADFRAC]];
787 123 bertin
        obj2->prof_arms_posang =
788
                        fmod_m90_p90(*profit->paramlist[PARAM_ARMS_POSANG]);
789 130 bertin
        obj2->prof_arms_posangerr =
790
                profit->paramerr[profit->paramindex[PARAM_ARMS_POSANG]];
791 116 bertin
        }
792
      }
793 115 bertin
    }
794
 
795 207 bertin
/* Star/galaxy classification */
796 208 bertin
  if (FLAG(obj2.prof_class_star) || FLAG(obj2.prof_concentration))
797 179 bertin
    {
798 290 bertin
    profit_residuals(profit,field,wfield, PROFIT_DYNPARAM, profit->paraminit,
799
        FLAG(obj2.prof_class_star) ? profit->resi : NULL);
800 244 bertin
    pprofit = thepprofit;
801
    nparam = pprofit->nparam;
802
    if (pprofit->psfdft)
803 297 bertin
      QFFTWF_FREE(pprofit->psfdft);
804 244 bertin
    psf = pprofit->psf;
805
    pprofit->pixstep = profit->pixstep;
806 284 bertin
    pprofit->guesssigbkg = profit->guesssigbkg;
807
    pprofit->guessdx = profit->guessdx;
808
    pprofit->guessdy = profit->guessdy;
809 246 bertin
    pprofit->guessflux = profit->guessflux;
810
    pprofit->guessfluxmax = profit->guessfluxmax;
811 284 bertin
    pprofit->guessradius = profit->guessradius;
812
    pprofit->guessaspect = profit->guessaspect;
813
    pprofit->guessposang = profit->guessposang;
814 244 bertin
    pprofit->ix = profit->ix;
815
    pprofit->iy = profit->iy;
816
    pprofit->objnaxisn[0] = profit->objnaxisn[0];
817
    pprofit->objnaxisn[1] = profit->objnaxisn[1];
818
    pprofit->subsamp = profit->subsamp;
819
    pprofit->nobjpix = profit->nobjpix;
820
    pprofit->obj = obj;
821
    pprofit->obj2 = obj2;
822
    pprofit->nresi = profit_copyobjpix(pprofit, field, wfield);
823
    pprofit->modnaxisn[0] = profit->modnaxisn[0];
824
    pprofit->modnaxisn[1] = profit->modnaxisn[1];
825
    pprofit->nmodpix = profit->nmodpix;
826
    profit_psf(pprofit);
827
    pprofit->sigma = obj->sigbkg;
828
    profit_resetparams(pprofit);
829 179 bertin
    if (profit->paramlist[PARAM_X] && profit->paramlist[PARAM_Y])
830
      {
831 244 bertin
      pprofit->paraminit[pprofit->paramindex[PARAM_X]] = *profit->paramlist[PARAM_X];
832
      pprofit->paraminit[pprofit->paramindex[PARAM_Y]] = *profit->paramlist[PARAM_Y];
833 179 bertin
      }
834 244 bertin
    fft_reset();
835
    pprofit->paraminit[pprofit->paramindex[PARAM_DIRAC_FLUX]] = profit->flux;
836
    pprofit->niter = profit_minimize(pprofit, PROFIT_MAXITER);
837
    profit_residuals(pprofit,field,wfield, PROFIT_DYNPARAM, pprofit->paraminit,
838 290 bertin
                        FLAG(obj2.prof_class_star)? pprofit->resi : NULL);
839 244 bertin
    qprofit = theqprofit;
840
    nparam = qprofit->nparam;
841
    if (qprofit->psfdft)
842 297 bertin
      QFFTWF_FREE(qprofit->psfdft);
843 244 bertin
    qprofit->pixstep = profit->pixstep;
844 284 bertin
    qprofit->guesssigbkg = profit->guesssigbkg;
845
    qprofit->guessdx = profit->guessdx;
846
    qprofit->guessdy = profit->guessdy;
847 246 bertin
    qprofit->guessflux = profit->guessflux;
848
    qprofit->guessfluxmax = profit->guessfluxmax;
849 284 bertin
    qprofit->guessradius = profit->guessradius;
850
    qprofit->guessaspect = profit->guessaspect;
851
    qprofit->guessposang = profit->guessposang;
852 244 bertin
    qprofit->ix = profit->ix;
853
    qprofit->iy = profit->iy;
854
    qprofit->objnaxisn[0] = profit->objnaxisn[0];
855
    qprofit->objnaxisn[1] = profit->objnaxisn[1];
856
    qprofit->subsamp = profit->subsamp;
857
    qprofit->nobjpix = profit->nobjpix;
858
    qprofit->obj = obj;
859
    qprofit->obj2 = obj2;
860
    qprofit->nresi = profit_copyobjpix(qprofit, field, wfield);
861
    qprofit->modnaxisn[0] = profit->modnaxisn[0];
862
    qprofit->modnaxisn[1] = profit->modnaxisn[1];
863
    qprofit->nmodpix = profit->nmodpix;
864
    profit_psf(qprofit);
865
    qprofit->sigma = obj->sigbkg;
866
    profit_resetparams(qprofit);
867
    fft_reset();
868 246 bertin
    qprofit->paraminit[qprofit->paramindex[PARAM_X]]
869
                = pprofit->paraminit[pprofit->paramindex[PARAM_X]];
870
    qprofit->paraminit[qprofit->paramindex[PARAM_Y]]
871
                = pprofit->paraminit[pprofit->paramindex[PARAM_Y]];
872
    qprofit->paraminit[qprofit->paramindex[PARAM_DISK_FLUX]]
873
                = pprofit->paraminit[pprofit->paramindex[PARAM_DIRAC_FLUX]];
874 244 bertin
    qprofit->paraminit[qprofit->paramindex[PARAM_DISK_SCALE]] = psf->fwhm/16.0;
875
    qprofit->paraminit[qprofit->paramindex[PARAM_DISK_ASPECT]] = 1.0;
876
    qprofit->paraminit[qprofit->paramindex[PARAM_DISK_POSANG]] = 0.0;
877
    profit_residuals(qprofit,field,wfield, PROFIT_DYNPARAM, qprofit->paraminit,
878 290 bertin
                        FLAG(obj2.prof_class_star)? qprofit->resi : NULL);
879 244 bertin
    sump = sumq = sumpw2 = sumqw2 = sumpqw = sump0 = sumq0 = 0.0;
880
    for (p=0; p<pprofit->nobjpix; p++)
881
      if (pprofit->objweight[p]>0 && pprofit->objpix[p]>-BIG)
882
        {
883
        valp = pprofit->lmodpix[p];
884
        sump += (double)(valp*pprofit->objpix[p]);
885
        valq = qprofit->lmodpix[p];
886
        sumq += (double)(valq*pprofit->objpix[p]);
887
        sump0 += (double)(valp*valp);
888
        sumq0 += (double)(valp*valq);
889
        sig2 = 1.0f/(pprofit->objweight[p]*pprofit->objweight[p]);
890
        sumpw2 += valp*valp*sig2;
891
        sumqw2 += valq*valq*sig2;
892
        sumpqw += valp*valq*sig2;
893
        }
894
 
895 208 bertin
    if (FLAG(obj2.prof_class_star))
896
      {
897 244 bertin
      dchi2 = 0.5*(pprofit->chi2 - profit->chi2);
898 208 bertin
      obj2->prof_class_star = dchi2 < 50.0?
899 201 bertin
        (dchi2 > -50.0? 2.0/(1.0+expf(dchi2)) : 2.0) : 0.0;
900 208 bertin
      }
901
    if (FLAG(obj2.prof_concentration))
902
      {
903 244 bertin
      obj2->prof_concentration = sump>0.0? (sumq/sump - sumq0/sump0) : 1.0;
904 209 bertin
      if (FLAG(obj2.prof_concentrationerr))
905 290 bertin
        obj2->prof_concentrationerr = (sump>0.0 && (err = sumqw2*sump*sump
906
                +sumpw2*sumq*sumq-2.0*sumpqw*sump*sumq)>0.0)?
907
                        sqrt(err) / (sump*sump) : 1.0;
908 208 bertin
      }
909 179 bertin
    }
910
 
911 48 bertin
/* clean up. */
912 211 bertin
  fft_reset();
913 208 bertin
 
914 65 bertin
  return;
915
  }
916
 
917 207 bertin
 
918 284 bertin
/****** profit_dfit ***********************************************************
919
PROTO   void profit_dfit(profitstruct *profit, profitstruct *dprofit,
920
                picstruct *field, picstruct *dfield,
921
                picstruct *wfield, picstruct *dwfield,
922
                objstruct *obj, obj2struct *obj2)
923
PURPOSE Fit profile(s) convolved with the PSF to a detected object on the
924
        detection image, and use the measurement image to scale the flux.
925
INPUT   Pointer to the measurement profile-fitting structure,
926
        pointer to the detection profile-fitting structure,
927
        pointer to the measurement field,
928
        pointer to the detection field,
929
        pointer to the measurement field weight,
930
        pointer to the detection field weight,
931
        pointer to the obj.
932
OUTPUT  Pointer to an allocated fit structure (containing details about the
933
        fit).
934
NOTES   It is a modified version of the lm_minimize() of lmfit.
935
AUTHOR  E. Bertin (IAP)
936 305 bertin
VERSION 16/02/2013
937 284 bertin
 ***/
938
void    profit_dfit(profitstruct *profit, profitstruct *dprofit,
939
                picstruct *field, picstruct *dfield,
940
                picstruct *wfield, picstruct *dwfield,
941
                objstruct *obj, obj2struct *obj2)
942
  {
943
    psfstruct           *dpsf;
944
    double              emx2,emy2,emxy, a , cp,sp, cn, bn, n,
945
                        sumn,sumd;
946
    PIXTYPE             valn,vald,w2;
947
    float               param0[PARAM_NPARAM], param1[PARAM_NPARAM],
948
                        param[PARAM_NPARAM],
949
                        **list,
950
                        *cov, *pix,
951
                        psf_fwhm, dchi2, err, aspect, chi2, ffac;
952
    int                 *index,
953
                        i,j,p, nparam, nparam2, ncomp, nprof;
954
 
955
  nparam = dprofit->nparam;
956
  nparam2 = nparam*nparam;
957
  nprof = dprofit->nprof;
958
  if (dprofit->psfdft)
959 297 bertin
    QFFTWF_FREE(dprofit->psfdft);
960 284 bertin
 
961
  dpsf = dprofit->psf;
962
  dprofit->pixstep = dpsf->pixstep;
963
  obj2->dprof_flag = 0;
964
 
965
/* Create pixmaps at image resolution */
966
  dprofit->ix = (int)(obj->mx + 0.49999);/* internal convention: 1st pix = 0 */
967
  dprofit->iy = (int)(obj->my + 0.49999);/* internal convention: 1st pix = 0 */
968
  psf_fwhm = dpsf->masksize[0]*dpsf->pixstep;
969
  dprofit->objnaxisn[0] = (((int)((obj->xmax-obj->xmin+1) + psf_fwhm + 0.499)
970
                *1.2)/2)*2 + 1;
971
  dprofit->objnaxisn[1] = (((int)((obj->ymax-obj->ymin+1) + psf_fwhm + 0.499)
972
                *1.2)/2)*2 + 1;
973
  if (dprofit->objnaxisn[1]<dprofit->objnaxisn[0])
974
    dprofit->objnaxisn[1] = dprofit->objnaxisn[0];
975
  else
976
    dprofit->objnaxisn[0] = dprofit->objnaxisn[1];
977
  if (dprofit->objnaxisn[0]>PROFIT_MAXOBJSIZE)
978
    {
979
    dprofit->subsamp = ceil((float)dprofit->objnaxisn[0]/PROFIT_MAXOBJSIZE);
980
    dprofit->objnaxisn[1] = (dprofit->objnaxisn[0] /= (int)dprofit->subsamp);
981
    obj2->dprof_flag |= PROFLAG_OBJSUB;
982
    }
983
  else
984
    dprofit->subsamp = 1.0;
985
  dprofit->nobjpix = dprofit->objnaxisn[0]*dprofit->objnaxisn[1];
986
 
987
/* Use (dirty) global variables to interface with lmfit */
988
  the_field = dfield;
989
  the_wfield = dwfield;
990
  dprofit->obj = obj;
991
  dprofit->obj2 = obj2;
992
 
993
  dprofit->nresi = profit_copyobjpix(dprofit, dfield, dwfield);
994 305 bertin
 
995 284 bertin
/* Check if the number of constraints exceeds the number of free parameters */
996 305 bertin
  if (dprofit->nresi < nparam || profit->nresi < 1)
997 284 bertin
    {
998
    obj2->dprof_flag |= PROFLAG_NOTCONST;
999
    return;
1000
    }
1001
 
1002
/* Create pixmap at PSF resolution */
1003
  dprofit->modnaxisn[0] =
1004
        ((int)(dprofit->objnaxisn[0]*dprofit->subsamp/dprofit->pixstep
1005
                +0.4999)/2+1)*2;
1006
  dprofit->modnaxisn[1] =
1007
        ((int)(dprofit->objnaxisn[1]*dprofit->subsamp/dprofit->pixstep
1008
                +0.4999)/2+1)*2;
1009
  if (dprofit->modnaxisn[1] < dprofit->modnaxisn[0])
1010
    dprofit->modnaxisn[1] = dprofit->modnaxisn[0];
1011
  else
1012
    dprofit->modnaxisn[0] = dprofit->modnaxisn[1];
1013
  if (dprofit->modnaxisn[0]>PROFIT_MAXMODSIZE)
1014
    {
1015
    dprofit->pixstep = (double)dprofit->modnaxisn[0] / PROFIT_MAXMODSIZE;
1016
    dprofit->modnaxisn[0] = dprofit->modnaxisn[1] = PROFIT_MAXMODSIZE;
1017
    obj2->dprof_flag |= PROFLAG_MODSUB;
1018
    }
1019
  dprofit->nmodpix = dprofit->modnaxisn[0]*dprofit->modnaxisn[1];
1020
 
1021
/* Compute the local PSF */
1022
  profit_psf(dprofit);
1023
 
1024
/* Set initial guesses and boundaries */
1025
  dprofit->guesssigbkg = dprofit->sigma = obj->dsigbkg;
1026
  dprofit->guessdx = obj->mx - (int)(obj->mx+0.49999);
1027
  dprofit->guessdy = obj->my - (int)(obj->my+0.49999);
1028
  if ((dprofit->guessflux = obj->dflux) <= 0.0)
1029
    dprofit->guessflux = 0.0;
1030
  if ((dprofit->guessfluxmax = 10.0*obj->dnpix*obj->dsigbkg*obj->dsigbkg)
1031
                         <= dprofit->guessflux)
1032
    dprofit->guessfluxmax = dprofit->guessflux;
1033
  if (dprofit->guessfluxmax <= 0.0)
1034
    dprofit->guessfluxmax = 1.0;
1035 305 bertin
  if ((dprofit->guessradius = sqrtf(obj->a*obj->b)*1.17)<0.5*dpsf->fwhm)
1036
    dprofit->guessradius = 0.5*dpsf->fwhm;
1037 284 bertin
  dprofit->guessaspect = obj->b/obj->a;
1038
  dprofit->guessposang = obj->theta;
1039
 
1040
  profit_resetparams(dprofit);
1041
 
1042
/* Actual minimisation */
1043
  fft_reset();
1044
 
1045
  dprofit->niter = profit_minimize(dprofit, PROFIT_MAXITER);
1046
 
1047
  if (dprofit->nlimmin)
1048
    obj2->dprof_flag |= PROFLAG_MINLIM;
1049
  if (dprofit->nlimmax)
1050
    obj2->dprof_flag |= PROFLAG_MAXLIM;
1051
 
1052
  for (p=0; p<nparam; p++)
1053
    dprofit->paramerr[p]= sqrt(dprofit->covar[p*(nparam+1)]);
1054
 
1055
  obj2->dprof_niter = dprofit->niter;
1056
 
1057
/* Now inject fitted parameters into the measurement model */
1058
  fft_reset();
1059
  profit_residuals(profit,field,wfield, 0.0, dprofit->paraminit, NULL);
1060
 
1061
/* Compute flux correction */
1062
  sumn = sumd = 0.0;
1063
  for (p=0; p<profit->nobjpix; p++)
1064
    if (profit->objweight[p]>0 && profit->objpix[p]>-BIG)
1065
      {
1066
      w2 = profit->objweight[p]*profit->objweight[p] * profit->lmodpix[p];
1067
      sumn += (double)(w2*profit->objpix[p]);
1068
      sumd += (double)(w2*profit->lmodpix[p]);
1069
      }
1070
 
1071
  ffac = (float)(sumn/sumd);
1072
  obj2->flux_dprof = sumd!=0.0? dprofit->flux*ffac: 0.0f;
1073 305 bertin
  obj2->fluxerr_dprof = sumd!=0.0? dprofit->flux/sqrtf((float)sumd): 0.0f;
1074 284 bertin
 
1075
  if (FLAG(obj2.dprof_chi2))
1076
    {
1077
/*-- Compute reduced chi2 on measurement image */
1078
    pix = profit->lmodpix;
1079
    for (p=profit->nobjpix; p--;)
1080
      *(pix++) *= ffac;
1081
    profit_compresi(profit, 0.0, profit->resi);
1082
    obj2->dprof_chi2 = (profit->nresi > dprofit->nparam)?
1083
                profit->chi2 / (profit->nresi - dprofit->nparam) : 0.0;
1084
    }
1085
 
1086
/* clean up. */
1087
  fft_reset();
1088
 
1089
  return;
1090
  }
1091
 
1092
 
1093 244 bertin
/****** profit_noisearea ******************************************************
1094
PROTO   float profit_noisearea(profitstruct *profit)
1095
PURPOSE Return the equivalent noise area (see King 1983) of a model.
1096
INPUT   Profile-fitting structure,
1097
OUTPUT  Equivalent noise area, in pixels.
1098
NOTES   -.
1099
AUTHOR  E. Bertin (IAP)
1100
VERSION 19/10/2010
1101
 ***/
1102
float   profit_noisearea(profitstruct *profit)
1103
  {
1104
   double       dval, flux,flux2;
1105
   PIXTYPE      *pix;
1106
   int          p;
1107
 
1108
  flux = flux2 = 0.0;
1109
  pix = profit->lmodpix;
1110
  for (p=profit->nobjpix; p--;)
1111
    {
1112
    dval = (double)*(pix++);
1113
    flux += dval;
1114
    flux2 += dval*dval;
1115
    }
1116
 
1117
  return (float)(flux2>0.0? flux*flux / flux2 : 0.0);
1118
  }
1119
 
1120
 
1121 235 bertin
/****** profit_fluxcor ******************************************************
1122 244 bertin
PROTO   void profit_fluxcor(profitstruct *profit, objstruct *obj,
1123 235 bertin
                        obj2struct *obj2)
1124
PURPOSE Integrate the flux within an ellipse and complete it with the wings of
1125
                the fitted model.
1126
INPUT           Profile-fitting structure,
1127
                pointer to the obj structure,
1128
                pointer to the obj2 structure.
1129
OUTPUT  Model-corrected flux.
1130
NOTES   -.
1131
AUTHOR  E. Bertin (IAP)
1132 244 bertin
VERSION 12/04/2011
1133 235 bertin
 ***/
1134
void    profit_fluxcor(profitstruct *profit, objstruct *obj, obj2struct *obj2)
1135
  {
1136 244 bertin
    checkstruct         *check;
1137
    double              mx,my, dx,dy, cx2,cy2,cxy, klim,klim2, tvobj,sigtvobj,
1138
                        tvm,tvmin,tvmout, r1,v1;
1139
    PIXTYPE             *objpix,*objpixt,*objweight,*objweightt, *lmodpix,
1140 235 bertin
                        pix, weight,var;
1141 244 bertin
    int                 x,y, x2,y2, pos, w,h, area, corrflag;
1142 235 bertin
 
1143 244 bertin
 
1144 235 bertin
  corrflag = (prefs.mask_type==MASK_CORRECT);
1145
  w = profit->objnaxisn[0];
1146
  h = profit->objnaxisn[1];
1147
  mx = (float)(w/2);
1148
  my = (float)(h/2);
1149
  if (FLAG(obj2.x_prof))
1150
    {
1151
    if (profit->paramlist[PARAM_X])
1152
      mx += *profit->paramlist[PARAM_X];
1153
    if (profit->paramlist[PARAM_Y])
1154
      my += *profit->paramlist[PARAM_Y];
1155
    }
1156 244 bertin
 
1157 235 bertin
  if (obj2->kronfactor>0.0)
1158
    {
1159
    cx2 = obj->cxx;
1160
    cy2 = obj->cyy;
1161
    cxy = obj->cxy;
1162 244 bertin
    klim2 = 0.64*obj2->kronfactor*obj2->kronfactor;
1163 235 bertin
    }
1164
  else
1165
/*-- ...if not, use the circular aperture provided by the user */
1166
    {
1167
    cx2 = cy2 = 1.0;
1168
    cxy = 0.0;
1169
    klim2 = (prefs.autoaper[1]/2.0)*(prefs.autoaper[1]/2.0);
1170
    }
1171 244 bertin
/*
1172
  cx2 = obj2->prof_convcxx;
1173
  cy2 = obj2->prof_convcyy;
1174
  cxy = obj2->prof_convcxy;
1175 235 bertin
 
1176 244 bertin
  lmodpix = profit->lmodpix;
1177
  r1 = v1 = 0.0;
1178
  for (y=0; y<h; y++)
1179
    {
1180
    dy = y - my;
1181
    for (x=0; x<w; x++)
1182
      {
1183
      dx = x - mx;
1184
      pix = *(lmodpix++);
1185
      r1 += sqrt(cx2*dx*dx + cy2*dy*dy + cxy*dx*dy)*pix;
1186
      v1 += pix;
1187
      }
1188
    }
1189
 
1190
  klim = r1/v1*2.0;
1191
  klim2 = klim*klim;
1192
 
1193
if ((check = prefs.check[CHECK_APERTURES]))
1194
sexellips(check->pix, check->width, check->height,
1195
obj2->x_prof-1.0, obj2->y_prof-1.0, klim*obj2->prof_conva,klim*obj2->prof_convb,
1196
obj2->prof_convtheta, check->overlay, 0);
1197
*/
1198
 
1199 235 bertin
  area = 0;
1200
  tvmin = tvmout = tvobj = sigtvobj = 0.0;
1201
  lmodpix = profit->lmodpix;
1202
  objpixt = objpix = profit->objpix;
1203
  objweightt = objweight = profit->objweight;
1204
  for (y=0; y<h; y++)
1205
    {
1206
    for (x=0; x<w; x++, objpixt++,objweightt++)
1207
      {
1208
      dx = x - mx;
1209
      dy = y - my;
1210
      if ((cx2*dx*dx + cy2*dy*dy + cxy*dx*dy) <= klim2)
1211
        {
1212
        area++;
1213
/*------ Here begin tests for pixel and/or weight overflows. Things are a */
1214
/*------ bit intricated to have it running as fast as possible in the most */
1215
/*------ common cases */
1216
        if ((weight=*objweightt)<=0.0)
1217
          {
1218
          if (corrflag
1219
                && (x2=(int)(2*mx+0.49999-x))>=0 && x2<w
1220
                && (y2=(int)(2*my+0.49999-y))>=0 && y2<h
1221
                && (weight=objweight[pos = y2*w + x2])>0.0)
1222
            {
1223
            pix = objpix[pos];
1224
            var = 1.0/(weight*weight);
1225
            }
1226
          else
1227
            pix = var = 0.0;
1228
          }
1229
        else
1230
          {
1231
          pix = *objpixt;
1232
          var = 1.0/(weight*weight);
1233
          }
1234
        tvobj += pix;
1235
        sigtvobj += var;
1236 244 bertin
        tvmin += *(lmodpix++);
1237
//        *(lmodpix++) = pix;
1238 235 bertin
        }
1239
      else
1240
        tvmout += *(lmodpix++);
1241
      }
1242
    }
1243
 
1244
//  tv -= area*bkg;
1245
 
1246
  tvm = tvmin + tvmout;
1247
  if (tvm != 0.0)
1248
    {
1249
    obj2->fluxcor_prof = tvobj+obj2->flux_prof*tvmout/tvm;
1250
    obj2->fluxcorerr_prof = sqrt(sigtvobj
1251
                        +obj2->fluxerr_prof*obj2->fluxerr_prof*tvmout/tvm);
1252
    }
1253
  else
1254
    {
1255
    obj2->fluxcor_prof = tvobj;
1256
    obj2->fluxcorerr_prof = sqrt(sigtvobj);
1257
    }
1258
 
1259 244 bertin
/*
1260
  if ((check = prefs.check[CHECK_OTHER]))
1261
    addcheck(check, profit->lmodpix, w, h, profit->ix,profit->iy, 1.0);
1262
*/
1263 235 bertin
  return;
1264
  }
1265
 
1266
 
1267 207 bertin
/****i* prof_gammainc *********************************************************
1268
PROTO   double prof_gammainc(double x, double a)
1269 233 bertin
PURPOSE Returns the incomplete Gamma function (based on algorithm described in
1270
        Numerical Recipes in C, chap. 6.1).
1271 207 bertin
INPUT   A double,
1272
        upper integration limit.
1273
OUTPUT  Incomplete Gamma function.
1274
NOTES   -.
1275
AUTHOR  E. Bertin (IAP)
1276 233 bertin
VERSION 08/10/2010
1277 207 bertin
*/
1278
static double   prof_gammainc (double x, double a)
1279
 
1280
  {
1281
   double       b,c,d,h, xn,xp, del,sum;
1282
   int          i;
1283
 
1284
  if (a < 0.0 || x <= 0.0)
1285
    return 0.0;
1286
 
1287
  if (a < (x+1.0))
1288
    {
1289
/*-- Use the series representation */
1290
    xp = x;
1291
    del = sum = 1.0/x;
1292
    for (i=100;i--;)    /* Iterate to convergence */
1293
      {
1294
      sum += (del *= a/(++xp));
1295
      if (fabs(del) < fabs(sum)*3e-7)
1296
        return sum*exp(-a+x*log(a)) / prof_gamma(x);
1297
      }
1298
    }
1299
  else
1300
    {
1301
/*-- Use the continued fraction representation and take its complement */
1302
    b = a + 1.0 - x;
1303
    c = 1e30;
1304
    h = d = 1.0/b;
1305
    for (i=1; i<=100; i++)      /* Iterate to convergence */
1306
      {
1307
      xn = -i*(i-x);
1308
      b += 2.0;
1309
      if (fabs(d=xn*d+b) < 1e-30)
1310
        d = 1e-30;
1311
      if (fabs(c=b+xn/c) < 1e-30)
1312
        c = 1e-30;
1313
      del= c * (d = 1.0/d);
1314
      h *= del;
1315
      if (fabs(del-1.0) < 3e-7)
1316
        return 1.0 - exp(-a+x*log(a))*h / prof_gamma(x);
1317
      }
1318
    }
1319
  error(EXIT_FAILURE, "*Error*: out of bounds in ",
1320
                "prof_gammainc()");
1321
  return 0.0;
1322
  }
1323
 
1324
 
1325 206 bertin
/****i* prof_gamma ************************************************************
1326 207 bertin
PROTO   double prof_gamma(double xx)
1327 233 bertin
PURPOSE Returns the Gamma function (based on algorithm described in Numerical
1328
        Recipes in C, chap 6.1).
1329 206 bertin
INPUT   A double.
1330
OUTPUT  Gamma function.
1331
NOTES   -.
1332
AUTHOR  E. Bertin (IAP)
1333 233 bertin
VERSION 11/09/2009
1334 206 bertin
*/
1335
static double   prof_gamma(double xx)
1336 65 bertin
 
1337 206 bertin
  {
1338
   double               x,tmp,ser;
1339
   static double        cof[6]={76.18009173,-86.50532033,24.01409822,
1340
                        -1.231739516,0.120858003e-2,-0.536382e-5};
1341
   int                  j;
1342
 
1343
  tmp=(x=xx-1.0)+5.5;
1344
  tmp -= (x+0.5)*log(tmp);
1345
  ser=1.0;
1346
  for (j=0;j<6;j++)
1347
    ser += cof[j]/(x+=1.0);
1348
 
1349
  return 2.50662827465*ser*exp(-tmp);
1350
  }
1351
 
1352
 
1353 207 bertin
/****** profit_minradius ******************************************************
1354
PROTO   float profit_minradius(profitstruct *profit, float refffac)
1355
PURPOSE Returns the minimum disk radius that guarantees that each and
1356
        every model component fits within some margin in that disk.
1357
INPUT   Profit structure pointer,
1358
        margin in units of (r/r_eff)^(1/n)).
1359
OUTPUT  Radius (in pixels).
1360
NOTES   -.
1361
AUTHOR  E. Bertin (IAP)
1362 233 bertin
VERSION 08/10/2010
1363 207 bertin
*/
1364
float   profit_minradius(profitstruct *profit, float refffac)
1365
 
1366
  {
1367
   double       r,reff,rmax;
1368
   int          p;
1369
 
1370
  rmax = reff = 0.0;
1371
  for (p=0; p<profit->nprof; p++)
1372
    {
1373
    switch (profit->prof[p]->code)
1374
      {
1375 244 bertin
      case MODEL_BACK:
1376
      case MODEL_DIRAC:
1377 233 bertin
        reff = 0.0;
1378
      break;
1379 244 bertin
      case MODEL_SERSIC:
1380 207 bertin
        reff = *profit->paramlist[PARAM_SPHEROID_REFF];
1381 233 bertin
        break;
1382 244 bertin
      case MODEL_DEVAUCOULEURS:
1383 207 bertin
        reff = *profit->paramlist[PARAM_SPHEROID_REFF];
1384 233 bertin
        break;
1385 244 bertin
      case MODEL_EXPONENTIAL:
1386 207 bertin
        reff = *profit->paramlist[PARAM_DISK_SCALE]*1.67835;
1387 233 bertin
        break;
1388 207 bertin
      default:
1389
        error(EXIT_FAILURE, "*Internal Error*: Unknown profile parameter in ",
1390
                "profit_minradius()");
1391 233 bertin
        break;
1392 207 bertin
      }
1393
    r = reff*(double)refffac;
1394
    if (r>rmax)
1395
      rmax = r;
1396
    }
1397
 
1398
  return (float)rmax;
1399
  }
1400
 
1401
 
1402 118 bertin
/****** profit_psf ************************************************************
1403
PROTO   void    profit_psf(profitstruct *profit)
1404
PURPOSE Build the local PSF at a given resolution.
1405
INPUT   Profile-fitting structure.
1406
OUTPUT  -.
1407
NOTES   -.
1408
AUTHOR  E. Bertin (IAP)
1409 305 bertin
VERSION 13/02/2013
1410 118 bertin
 ***/
1411
void    profit_psf(profitstruct *profit)
1412
  {
1413 201 bertin
   double       flux;
1414
   float        posin[2], posout[2], dnaxisn[2],
1415 118 bertin
                *pixout,
1416 201 bertin
                xcout,ycout, xcin,ycin, invpixstep, norm;
1417 118 bertin
   int          d,i;
1418
 
1419
  psf = profit->psf;
1420
  psf_build(psf);
1421
 
1422 201 bertin
  xcout = (float)(profit->modnaxisn[0]/2) + 1.0; /* FITS convention */
1423
  ycout = (float)(profit->modnaxisn[1]/2) + 1.0;        /* FITS convention */
1424 118 bertin
  xcin = (psf->masksize[0]/2) + 1.0;                     /* FITS convention */
1425
  ycin = (psf->masksize[1]/2) + 1.0;                    /* FITS convention */
1426
  invpixstep = profit->pixstep / psf->pixstep;
1427
 
1428
/* Initialize multi-dimensional counters */
1429
  for (d=0; d<2; d++)
1430
    {
1431
    posout[d] = 1.0;                                    /* FITS convention */
1432
    dnaxisn[d] = profit->modnaxisn[d]+0.5;
1433
    }
1434
 
1435
/* Remap each pixel */
1436
  pixout = profit->psfpix;
1437
  flux = 0.0;
1438
  for (i=profit->modnaxisn[0]*profit->modnaxisn[1]; i--;)
1439
    {
1440
    posin[0] = (posout[0] - xcout)*invpixstep + xcin;
1441
    posin[1] = (posout[1] - ycout)*invpixstep + ycin;
1442
    flux += ((*(pixout++) = interpolate_pix(posin, psf->maskloc,
1443
                psf->masksize, INTERP_LANCZOS3)));
1444
    for (d=0; d<2; d++)
1445
      if ((posout[d]+=1.0) < dnaxisn[d])
1446
        break;
1447
      else
1448
        posout[d] = 1.0;
1449
    }
1450
 
1451 164 bertin
/* Normalize PSF flux (just in case...) */
1452 305 bertin
  flux *= profit->pixstep*profit->pixstep / (profit->subsamp*profit->subsamp);
1453 221 bertin
  if (fabs(flux) <= 0.0)
1454
    error(EXIT_FAILURE, "*Error*: PSF model is empty or negative: ", psf->name);
1455 164 bertin
 
1456 221 bertin
  norm = 1.0/flux;
1457
  pixout = profit->psfpix;
1458
  for (i=profit->modnaxisn[0]*profit->modnaxisn[1]; i--;)
1459
    *(pixout++) *= norm;
1460
 
1461 118 bertin
  return;
1462
  }
1463
 
1464
 
1465 65 bertin
/****** profit_minimize *******************************************************
1466
PROTO   void profit_minimize(profitstruct *profit)
1467
PURPOSE Provide a function returning residuals to lmfit.
1468
INPUT   Pointer to the profit structure involved in the fit,
1469
        maximum number of iterations.
1470
OUTPUT  Number of iterations used.
1471
NOTES   -.
1472
AUTHOR  E. Bertin (IAP)
1473 305 bertin
VERSION 15/01/2013
1474 65 bertin
 ***/
1475
int     profit_minimize(profitstruct *profit, int niter)
1476
  {
1477 246 bertin
   double       lm_opts[5], info[LM_INFO_SZ],
1478
                dcovar[PARAM_NPARAM*PARAM_NPARAM], dparam[PARAM_NPARAM];
1479
   int          nfree;
1480 65 bertin
 
1481 221 bertin
  profit->iter = 0;
1482
  memset(dcovar, 0, profit->nparam*profit->nparam*sizeof(double));
1483 65 bertin
 
1484 72 bertin
/* Perform fit */
1485 241 bertin
  lm_opts[0] = 1.0e-3;           /* Initial mu */
1486 243 bertin
  lm_opts[1] = 1.0e-6;          /* ||J^T e||_inf stopping factor */
1487
  lm_opts[2] = 1.0e-6;          /* |Dp||_2 stopping factor */
1488
  lm_opts[3] = 1.0e-6;          /* ||e||_2 stopping factor */
1489 241 bertin
  lm_opts[4] = 1.0e-4;          /* Jacobian step */
1490 65 bertin
 
1491 246 bertin
  nfree = profit_boundtounbound(profit, profit->paraminit, dparam,
1492
                                PARAM_ALLPARAMS);
1493 65 bertin
 
1494 305 bertin
  niter = dlevmar_dif(profit_evaluate, dparam, NULL, nfree,
1495
                        profit->nresi + profit->npresi,
1496 246 bertin
                        niter, lm_opts, info, NULL, dcovar, profit);
1497 65 bertin
 
1498 221 bertin
  profit_unboundtobound(profit, dparam, profit->paraminit, PARAM_ALLPARAMS);
1499 52 bertin
 
1500 221 bertin
/* Convert covariance matrix to bounded space */
1501
  profit_covarunboundtobound(profit, dcovar, profit->covar);
1502
 
1503 72 bertin
  return niter;
1504 46 bertin
  }
1505
 
1506 48 bertin
 
1507
/****** profit_printout *******************************************************
1508 201 bertin
PROTO   void profit_printout(int n_par, float* par, int m_dat, float* fvec,
1509 48 bertin
                void *data, int iflag, int iter, int nfev )
1510
PURPOSE Provide a function to print out results to lmfit.
1511
INPUT   Number of fitted parameters,
1512
        pointer to the vector of parameters,
1513
        number of data points,
1514
        pointer to the vector of residuals (output),
1515
        pointer to the data structure (unused),
1516
 
1517
        outer loop counter,
1518
        number of calls to evaluate().
1519
OUTPUT  -.
1520
NOTES   Input arguments are there only for compatibility purposes (unused)
1521
AUTHOR  E. Bertin (IAP)
1522 145 bertin
VERSION 17/09/2008
1523 48 bertin
 ***/
1524 201 bertin
void    profit_printout(int n_par, float* par, int m_dat, float* fvec,
1525 48 bertin
                void *data, int iflag, int iter, int nfev )
1526
  {
1527 77 bertin
   checkstruct  *check;
1528
   profitstruct *profit;
1529
   char         filename[256];
1530
   static int   itero;
1531
 
1532
  profit = (profitstruct *)data;
1533
 
1534 116 bertin
  if (0 && (iter!=itero || iter<0))
1535 77 bertin
    {
1536
    if (iter<0)
1537
      itero++;
1538
    else
1539
      itero = iter;
1540
    sprintf(filename, "check_%d_%04d.fits", the_gal, itero);
1541
    check=initcheck(filename, CHECK_PROFILES, 0);
1542
    reinitcheck(the_field, check);
1543
    addcheck(check, profit->lmodpix, profit->objnaxisn[0],profit->objnaxisn[1],
1544 145 bertin
                profit->ix,profit->iy, 1.0);
1545 66 bertin
 
1546 77 bertin
    reendcheck(the_field, check);
1547
    endcheck(check);
1548
    }
1549
 
1550 48 bertin
  return;
1551
  }
1552
 
1553
 
1554 102 bertin
/****** profit_evaluate ******************************************************
1555 221 bertin
PROTO   void profit_evaluate(double *par, double *fvec, int m, int n,
1556
                        void *adata)
1557 73 bertin
PURPOSE Provide a function returning residuals to levmar.
1558 57 bertin
INPUT   Pointer to the vector of parameters,
1559 73 bertin
        pointer to the vector of residuals (output),
1560
        number of model parameters,
1561 57 bertin
        number of data points,
1562 221 bertin
        pointer to a data structure (we use it for the profit structure here).
1563 57 bertin
OUTPUT  -.
1564 221 bertin
NOTES   -.
1565 57 bertin
AUTHOR  E. Bertin (IAP)
1566 305 bertin
VERSION 16/01/2013
1567 57 bertin
 ***/
1568 221 bertin
void    profit_evaluate(double *dpar, double *fvec, int m, int n, void *adata)
1569 57 bertin
  {
1570 221 bertin
   profitstruct         *profit;
1571
   profstruct           **prof;
1572 305 bertin
   double               *dpar0, *dresi, *fvect;
1573 221 bertin
   float                *modpixt, *profpixt, *resi,
1574
                        tparam, val;
1575
   PIXTYPE              *lmodpixt,*lmodpix2t, *objpix,*weight,
1576
                        wval;
1577
   int                  c,f,i,p,q, fd,pd, jflag,sflag, nprof;
1578 57 bertin
 
1579
  profit = (profitstruct *)adata;
1580 221 bertin
 
1581
/* Detect "Jacobian-related" calls */
1582
  jflag = pd = fd = 0;
1583
  dpar0 = profit->dparam;
1584
  if (profit->iter)
1585
    {
1586
    f = q = 0;
1587
    for (p=0; p<profit->nparam; p++)
1588
      {
1589
      if (dpar[f] - dpar0[f] != 0.0)
1590
        {
1591
        pd = p;
1592
        fd = f;
1593
        q++;
1594
        }
1595 246 bertin
      if (profit->parfittype[p]!=PARFIT_FIXED)
1596 221 bertin
        f++;
1597
      }
1598
    if (f>0 && q==1)
1599
      jflag = 1;
1600
    }
1601 241 bertin
jflag = 0;       /* Temporarily deactivated (until problems are fixed) */
1602 244 bertin
  if (jflag && !(profit->nprof==1 && profit->prof[0]->code == MODEL_DIRAC))
1603 221 bertin
    {
1604
    prof = profit->prof;
1605
    nprof = profit->nprof;
1606
 
1607
/*-- "Jacobian call" */
1608
    tparam = profit->param[pd];
1609
    profit_unboundtobound(profit, &dpar[fd], &profit->param[pd], pd);
1610
    sflag = 1;
1611
    switch(profit->paramrevindex[pd])
1612
      {
1613 233 bertin
      case PARAM_BACK:
1614
        lmodpixt = profit->lmodpix;
1615
        lmodpix2t = profit->lmodpix2;
1616
        val = (profit->param[pd] - tparam);
1617
        for (i=profit->nobjpix;i--;)
1618
          *(lmodpix2t++) = val;
1619
        break;
1620 221 bertin
      case PARAM_X:
1621
      case PARAM_Y:
1622
        profit_resample(profit, profit->cmodpix, profit->lmodpix2, 1.0);
1623
        lmodpixt = profit->lmodpix;
1624
        lmodpix2t = profit->lmodpix2;
1625
        for (i=profit->nobjpix;i--;)
1626
          *(lmodpix2t++) -= *(lmodpixt++);
1627
        break;
1628 233 bertin
      case PARAM_DIRAC_FLUX:
1629 221 bertin
      case PARAM_SPHEROID_FLUX:
1630
      case PARAM_DISK_FLUX:
1631
      case PARAM_ARMS_FLUX:
1632
      case PARAM_BAR_FLUX:
1633
        if (nprof==1 && tparam != 0.0)
1634
          {
1635
          lmodpixt = profit->lmodpix;
1636
          lmodpix2t = profit->lmodpix2;
1637
          val = (profit->param[pd] - tparam) / tparam;
1638
          for (i=profit->nobjpix;i--;)
1639
            *(lmodpix2t++) = val**(lmodpixt++);
1640
          }
1641
        else
1642
          {
1643
          for (c=0; c<nprof; c++)
1644
            if (prof[c]->flux == &profit->param[pd])
1645
              break;
1646
          memcpy(profit->modpix, prof[c]->pix, profit->nmodpix*sizeof(float));
1647
          profit_convolve(profit, profit->modpix);
1648
          profit_resample(profit, profit->modpix, profit->lmodpix2,
1649
                profit->param[pd] - tparam);
1650
          }
1651
        break;
1652
      case PARAM_SPHEROID_REFF:
1653
      case PARAM_SPHEROID_ASPECT:
1654
      case PARAM_SPHEROID_POSANG:
1655
      case PARAM_SPHEROID_SERSICN:
1656
        sflag = 0;                       /* We are in the same switch */
1657
        for (c=0; c<nprof; c++)
1658 244 bertin
          if (prof[c]->code == MODEL_SERSIC
1659
                || prof[c]->code == MODEL_DEVAUCOULEURS)
1660 221 bertin
            break;
1661
      case PARAM_DISK_SCALE:
1662
      case PARAM_DISK_ASPECT:
1663
      case PARAM_DISK_POSANG:
1664
        if (sflag)
1665
          for (c=0; c<nprof; c++)
1666 244 bertin
            if (prof[c]->code == MODEL_EXPONENTIAL)
1667 221 bertin
              break;
1668
        sflag = 0;
1669
      case PARAM_ARMS_QUADFRAC:
1670
      case PARAM_ARMS_SCALE:
1671
      case PARAM_ARMS_START:
1672
      case PARAM_ARMS_POSANG:
1673
      case PARAM_ARMS_PITCH:
1674
      case PARAM_ARMS_PITCHVAR:
1675
      case PARAM_ARMS_WIDTH:
1676
        if (sflag)
1677
          for (c=0; c<nprof; c++)
1678 244 bertin
            if (prof[c]->code == MODEL_ARMS)
1679 221 bertin
              break;
1680
        sflag = 0;
1681
      case PARAM_BAR_ASPECT:
1682
      case PARAM_BAR_POSANG:
1683
        if (sflag)
1684
          for (c=0; c<nprof; c++)
1685 244 bertin
            if (prof[c]->code == MODEL_ARMS)
1686 221 bertin
              break;
1687
        modpixt = profit->modpix;
1688
        profpixt = prof[c]->pix;
1689
        val = -*prof[c]->flux;
1690
        for (i=profit->nmodpix;i--;)
1691
          *(modpixt++) = val**(profpixt++);
1692
        memcpy(profit->modpix2, prof[c]->pix, profit->nmodpix*sizeof(float));
1693
        prof_add(profit, prof[c], 0);
1694
        memcpy(prof[c]->pix, profit->modpix2, profit->nmodpix*sizeof(float));
1695
        profit_convolve(profit, profit->modpix);
1696
        profit_resample(profit, profit->modpix, profit->lmodpix2, 1.0);
1697
        break;
1698
      default:
1699
        error(EXIT_FAILURE, "*Internal Error*: ",
1700
                        "unknown parameter index in profit_jacobian()");
1701
        break;
1702
      }
1703
    objpix = profit->objpix;
1704
    weight = profit->objweight;
1705
    lmodpixt = profit->lmodpix;
1706
    lmodpix2t = profit->lmodpix2;
1707
    resi = profit->resi;
1708
    dresi = fvec;
1709
    if (PROFIT_DYNPARAM > 0.0)
1710
      for (i=profit->nobjpix;i--; lmodpixt++, lmodpix2t++)
1711
        {
1712
        val = *(objpix++);
1713
        if ((wval=*(weight++))>0.0)
1714
          *(dresi++) = *(resi++) + *lmodpix2t
1715
                * wval/(1.0+wval*fabs(*lmodpixt - val)/PROFIT_DYNPARAM);
1716
        }
1717
    else
1718
      for (i=profit->nobjpix;i--; lmodpix2t++)
1719
        if ((wval=*(weight++))>0.0)
1720
          *(dresi++) = *(resi++) + *lmodpix2t * wval;
1721
    }
1722
  else
1723
    {
1724
/*-- "Regular call" */
1725
    for (p=0; p<profit->nparam; p++)
1726
      dpar0[p] = dpar[p];
1727
    profit_unboundtobound(profit, dpar, profit->param, PARAM_ALLPARAMS);
1728
 
1729
    profit_residuals(profit, the_field, the_wfield, PROFIT_DYNPARAM,
1730
        profit->param, profit->resi);
1731
 
1732 305 bertin
    profit_presiduals(profit, dpar, profit->presi);
1733
 
1734
    fvect = fvec;
1735 221 bertin
    for (p=0; p<profit->nresi; p++)
1736 305 bertin
      *(fvect++) = profit->resi[p];
1737
    for (p=0; p<profit->npresi; p++)
1738
      *(fvect++) = profit->presi[p];
1739
 
1740 221 bertin
    }
1741
 
1742
//  profit_printout(m, par, n, fvec, adata, 0, -1, 0 );
1743
  profit->iter++;
1744
 
1745 57 bertin
  return;
1746
  }
1747
 
1748
 
1749 46 bertin
/****** profit_residuals ******************************************************
1750 305 bertin
PROTO   float *profit_residuals(profitstruct *profit, picstruct *field,
1751 201 bertin
                picstruct *wfield, float dynparam, float *param, float *resi)
1752 46 bertin
PURPOSE Compute the vector of residuals between the data and the galaxy
1753
        profile model.
1754
INPUT   Profile-fitting structure,
1755 51 bertin
        pointer to the field,
1756
        pointer to the field weight,
1757 180 bertin
        dynamic compression parameter (0=no compression),
1758 305 bertin
        pointer to the model parameters
1759 51 bertin
        pointer to the computed residuals (output).
1760 42 bertin
OUTPUT  Vector of residuals.
1761 117 bertin
NOTES   -.
1762 42 bertin
AUTHOR  E. Bertin (IAP)
1763 221 bertin
VERSION 08/07/2010
1764 42 bertin
 ***/
1765 201 bertin
float   *profit_residuals(profitstruct *profit, picstruct *field,
1766
                picstruct *wfield, float dynparam, float *param, float *resi)
1767 42 bertin
  {
1768 221 bertin
   int          p, nmodpix;
1769 42 bertin
 
1770 221 bertin
  nmodpix = profit->modnaxisn[0]*profit->modnaxisn[1]*sizeof(float);
1771
  memset(profit->modpix, 0, nmodpix);
1772 51 bertin
  for (p=0; p<profit->nparam; p++)
1773
    profit->param[p] = param[p];
1774 179 bertin
/* Simple PSF shortcut */
1775 244 bertin
  if (profit->nprof == 1 && profit->prof[0]->code == MODEL_DIRAC)
1776 208 bertin
    {
1777 180 bertin
    profit_resample(profit, profit->psfpix, profit->lmodpix,
1778
                *profit->prof[0]->flux);
1779 208 bertin
    profit->flux = *profit->prof[0]->flux;
1780
    }
1781 179 bertin
  else
1782
    {
1783 207 bertin
    profit->flux = 0.0;
1784 179 bertin
    for (p=0; p<profit->nprof; p++)
1785 221 bertin
      profit->flux += prof_add(profit, profit->prof[p], 0);
1786
    memcpy(profit->cmodpix, profit->modpix, profit->nmodpix*sizeof(float));
1787
    profit_convolve(profit, profit->cmodpix);
1788
    profit_resample(profit, profit->cmodpix, profit->lmodpix, 1.0);
1789 179 bertin
    }
1790 42 bertin
 
1791 221 bertin
  if (resi)
1792
    profit_compresi(profit, dynparam, resi);
1793
 
1794 51 bertin
  return resi;
1795 42 bertin
  }
1796
 
1797
 
1798 305 bertin
/****** profit_presiduals *****************************************************
1799
PROTO   float *profit_presiduals(profitstruct *profit, float *param,
1800
                float *presi)
1801
PURPOSE Compute the vector of prior "residuals" for the model parameters.
1802
INPUT   Profile-fitting structure,
1803
        pointer to the (unbound) model parameters,
1804
        pointer to the computed prior "residuals" (output).
1805
OUTPUT  Vector of residuals.
1806
NOTES   -.
1807
AUTHOR  E. Bertin (IAP)
1808
VERSION 15/01/2013
1809
 ***/
1810
float   *profit_presiduals(profitstruct *profit, double *dparam, float *presi)
1811
  {
1812
   float        *presit;
1813
   int          p;
1814
 
1815
  presit = presi;
1816
  for (p=0; p<profit->nparam; p++)
1817
    if (profit->dparampsig[p]>0.0)
1818
      *(presit++) = (float)((dparam[p] - profit->dparampcen[p])
1819
                                / profit->dparampsig[p]);
1820
 
1821
  return presi;
1822
  }
1823
 
1824
 
1825 47 bertin
/****** profit_compresi ******************************************************
1826 284 bertin
PROTO   float *profit_compresi(profitstruct *profit, float dynparam,
1827 201 bertin
                        float *resi)
1828 47 bertin
PURPOSE Compute the vector of residuals between the data and the galaxy
1829
        profile model.
1830
INPUT   Profile-fitting structure,
1831 180 bertin
        dynamic-compression parameter (0=no compression),
1832 51 bertin
        vector of residuals (output).
1833 47 bertin
OUTPUT  Vector of residuals.
1834 117 bertin
NOTES   -.
1835 47 bertin
AUTHOR  E. Bertin (IAP)
1836 201 bertin
VERSION 07/09/2009
1837 47 bertin
 ***/
1838 201 bertin
float   *profit_compresi(profitstruct *profit, float dynparam, float *resi)
1839 47 bertin
  {
1840 201 bertin
   double       error;
1841
   float        *resit;
1842 50 bertin
   PIXTYPE      *objpix, *objweight, *lmodpix,
1843 128 bertin
                val,val2,wval, invsig;
1844 180 bertin
   int          npix, i;
1845 50 bertin
 
1846
/* Compute vector of residuals */
1847 51 bertin
  resit = resi;
1848 50 bertin
  objpix = profit->objpix;
1849
  objweight = profit->objweight;
1850
  lmodpix = profit->lmodpix;
1851 79 bertin
  error = 0.0;
1852 180 bertin
  npix = profit->objnaxisn[0]*profit->objnaxisn[1];
1853
  if (dynparam > 0.0)
1854 88 bertin
    {
1855 180 bertin
    invsig = (PIXTYPE)(1.0/dynparam);
1856
    for (i=npix; i--; lmodpix++)
1857 117 bertin
      {
1858
      val = *(objpix++);
1859
      if ((wval=*(objweight++))>0.0)
1860 88 bertin
        {
1861 221 bertin
        val2 = (*lmodpix - val)*wval*invsig;
1862 201 bertin
        val2 = val2>0.0? logf(1.0+val2) : -logf(1.0-val2);
1863 180 bertin
        *(resit++) = val2*dynparam;
1864 88 bertin
        error += val2*val2;
1865
        }
1866 117 bertin
      }
1867 180 bertin
    profit->chi2 = dynparam*dynparam*error;
1868 88 bertin
    }
1869 180 bertin
  else
1870
    {
1871
    for (i=npix; i--; lmodpix++)
1872
      {
1873
      val = *(objpix++);
1874
      if ((wval=*(objweight++))>0.0)
1875
        {
1876 221 bertin
        val2 = (*lmodpix - val)*wval;
1877 180 bertin
        *(resit++) = val2;
1878
        error += val2*val2;
1879
        }
1880
      }
1881
    profit->chi2 = error;
1882
    }
1883 50 bertin
 
1884 51 bertin
  return resi;
1885 50 bertin
  }
1886
 
1887
 
1888
/****** profit_resample ******************************************************
1889 221 bertin
PROTO   int     prof_resample(profitstruct *profit, float *inpix,
1890
                PIXTYPE *outpix, float factor)
1891 50 bertin
PURPOSE Resample the current full resolution model to image resolution.
1892 221 bertin
INPUT   Profile-fitting structure,
1893
        pointer to input raster,
1894
        pointer to output raster,
1895
        multiplicating factor.
1896
OUTPUT  RETURN_ERROR if the rasters don't overlap, RETURN_OK otherwise.
1897 117 bertin
NOTES   -.
1898 50 bertin
AUTHOR  E. Bertin (IAP)
1899 309 bertin
VERSION 24/04/2013
1900 50 bertin
 ***/
1901 221 bertin
int     profit_resample(profitstruct *profit, float *inpix, PIXTYPE *outpix,
1902 201 bertin
        float factor)
1903 50 bertin
  {
1904 221 bertin
   PIXTYPE      *pixout,*pixout0;
1905
   float        *pixin,*pixin0, *mask,*maskt, *pixinout, *dpixin,*dpixin0,
1906
                *dpixout,*dpixout0, *dx,*dy,
1907
                xcin,xcout,ycin,ycout, xsin,ysin, xin,yin, x,y, dxm,dym, val,
1908 302 bertin
                invpixstep, norm, fluxnorm;
1909 221 bertin
   int          *start,*startt, *nmask,*nmaskt,
1910
                i,j,k,n,t,
1911
                ixsout,iysout, ixout,iyout, dixout,diyout, nxout,nyout,
1912
                iysina, nyin, hmw,hmh, ix,iy, ixin,iyin;
1913 51 bertin
 
1914 221 bertin
  invpixstep = profit->subsamp/profit->pixstep;
1915
 
1916 302 bertin
  xcin = (float)(profit->modnaxisn[0]/2);
1917
  xcout = ((int)(profit->subsamp*profit->objnaxisn[0])/2 + 0.5)
1918
                / profit->subsamp - 0.5;
1919
  if ((dx=profit->paramlist[PARAM_X]))
1920 305 bertin
    xcout += *dx/profit->subsamp;
1921 221 bertin
 
1922
  xsin = xcin - xcout*invpixstep;                       /* Input start x-coord*/
1923 302 bertin
 
1924 309 bertin
  if ((int)xsin >= profit->modnaxisn[0] || !finitef(xsin))
1925 221 bertin
    return RETURN_ERROR;
1926
  ixsout = 0;                            /* Int. part of output start x-coord */
1927
  if (xsin<0.0)
1928
    {
1929
    dixout = (int)(1.0-xsin/invpixstep);
1930
/*-- Simply leave here if the images do not overlap in x */
1931
    if (dixout >= profit->objnaxisn[0])
1932
      return RETURN_ERROR;
1933
    ixsout += dixout;
1934
    xsin += dixout*invpixstep;
1935
    }
1936
  nxout = (int)((profit->modnaxisn[0]-xsin)/invpixstep);/* nb of interpolated
1937
                                                        input pixels along x */
1938
  if (nxout>(ixout=profit->objnaxisn[0]-ixsout))
1939
    nxout = ixout;
1940
  if (!nxout)
1941
    return RETURN_ERROR;
1942
 
1943 302 bertin
  ycin = (float)(profit->modnaxisn[1]/2);
1944
  ycout = ((int)(profit->subsamp*profit->objnaxisn[1])/2 + 0.5)
1945
                / profit->subsamp - 0.5;
1946
  if ((dy=profit->paramlist[PARAM_Y]))
1947 305 bertin
    ycout += *dy/profit->subsamp;
1948 57 bertin
 
1949 221 bertin
  ysin = ycin - ycout*invpixstep;               /* Input start y-coord*/
1950 309 bertin
  if ((int)ysin >= profit->modnaxisn[1] || !finitef(ysin))
1951 221 bertin
    return RETURN_ERROR;
1952
  iysout = 0;                            /* Int. part of output start y-coord */
1953
  if (ysin<0.0)
1954 47 bertin
    {
1955 221 bertin
    diyout = (int)(1.0-ysin/invpixstep);
1956
/*-- Simply leave here if the images do not overlap in y */
1957
    if (diyout >= profit->objnaxisn[1])
1958
      return RETURN_ERROR;
1959
    iysout += diyout;
1960
    ysin += diyout*invpixstep;
1961 47 bertin
    }
1962 221 bertin
  nyout = (int)((profit->modnaxisn[1]-ysin)/invpixstep);/* nb of interpolated
1963
                                                        input pixels along y */
1964
  if (nyout>(iyout=profit->objnaxisn[1]-iysout))
1965
    nyout = iyout;
1966
  if (!nyout)
1967
    return RETURN_ERROR;
1968 47 bertin
 
1969 221 bertin
/* Set the yrange for the x-resampling with some margin for interpolation */
1970
  iysina = (int)ysin;   /* Int. part of Input start y-coord with margin */
1971 229 bertin
  hmh = INTERPW/2 - 1;  /* Interpolant start */
1972 221 bertin
  if (iysina<0 || ((iysina -= hmh)< 0))
1973
    iysina = 0;
1974 229 bertin
  nyin = (int)(ysin+nyout*invpixstep)+INTERPW-hmh;/* Interpolated Input y size*/
1975 221 bertin
  if (nyin>profit->modnaxisn[1])                                                /* with margin */
1976
    nyin = profit->modnaxisn[1];
1977
/* Express everything relative to the effective Input start (with margin) */
1978
  nyin -= iysina;
1979
  ysin -= (float)iysina;
1980
 
1981
/* Allocate interpolant stuff for the x direction */
1982
  QMALLOC(mask, float, nxout*INTERPW);  /* Interpolation masks */
1983
  QMALLOC(nmask, int, nxout);           /* Interpolation mask sizes */
1984
  QMALLOC(start, int, nxout);           /* Int. part of Input conv starts */
1985
/* Compute the local interpolant and data starting points in x */
1986
  hmw = INTERPW/2 - 1;
1987
  xin = xsin;
1988
  maskt = mask;
1989
  nmaskt = nmask;
1990
  startt = start;
1991
  for (j=nxout; j--; xin+=invpixstep)
1992 47 bertin
    {
1993 221 bertin
    ix = (ixin=(int)xin) - hmw;
1994
    dxm = ixin - xin - hmw;     /* starting point in the interpolation func */
1995
    if (ix < 0)
1996 212 bertin
      {
1997 221 bertin
      n = INTERPW+ix;
1998
      dxm -= (float)ix;
1999
      ix = 0;
2000 212 bertin
      }
2001 221 bertin
    else
2002
      n = INTERPW;
2003
    if (n>(t=profit->modnaxisn[0]-ix))
2004
      n=t;
2005
    *(startt++) = ix;
2006
    *(nmaskt++) = n;
2007 229 bertin
    norm = 0.0;
2008 221 bertin
    for (x=dxm, i=n; i--; x+=1.0)
2009 229 bertin
      norm += (*(maskt++) = INTERPF(x));
2010
    norm = norm>0.0? 1.0/norm : 1.0;
2011
    maskt -= n;
2012
    for (i=n; i--;)
2013
      *(maskt++) *= norm;
2014 212 bertin
    }
2015 221 bertin
 
2016
  QCALLOC(pixinout, float, nxout*nyin); /* Intermediary frame-buffer */
2017
 
2018
/* Make the interpolation in x (this includes transposition) */
2019
  pixin0 = inpix + iysina*profit->modnaxisn[0];
2020
  dpixout0 = pixinout;
2021
  for (k=nyin; k--; pixin0+=profit->modnaxisn[0], dpixout0++)
2022
    {
2023
    maskt = mask;
2024
    nmaskt = nmask;
2025
    startt = start;
2026
    dpixout = dpixout0;
2027
    for (j=nxout; j--; dpixout+=nyin)
2028 212 bertin
      {
2029 221 bertin
      pixin = pixin0+*(startt++);
2030
      val = 0.0;
2031
      for (i=*(nmaskt++); i--;)
2032
        val += *(maskt++)**(pixin++);
2033
      *dpixout = val;
2034 212 bertin
      }
2035 221 bertin
    }
2036 47 bertin
 
2037 221 bertin
/* Reallocate interpolant stuff for the y direction */
2038 229 bertin
  QREALLOC(mask, float, nyout*INTERPW); /* Interpolation masks */
2039 221 bertin
  QREALLOC(nmask, int, nyout);                  /* Interpolation mask sizes */
2040
  QREALLOC(start, int, nyout);          /* Int. part of Input conv starts */
2041
 
2042
/* Compute the local interpolant and data starting points in y */
2043 229 bertin
  hmh = INTERPW/2 - 1;
2044 221 bertin
  yin = ysin;
2045
  maskt = mask;
2046
  nmaskt = nmask;
2047
  startt = start;
2048
  for (j=nyout; j--; yin+=invpixstep)
2049
    {
2050
    iy = (iyin=(int)yin) - hmh;
2051
    dym = iyin - yin - hmh;     /* starting point in the interpolation func */
2052
    if (iy < 0)
2053
      {
2054 229 bertin
      n = INTERPW+iy;
2055 221 bertin
      dym -= (float)iy;
2056
      iy = 0;
2057
      }
2058
    else
2059 229 bertin
      n = INTERPW;
2060 221 bertin
    if (n>(t=nyin-iy))
2061
      n=t;
2062
    *(startt++) = iy;
2063
    *(nmaskt++) = n;
2064 229 bertin
    norm = 0.0;
2065 221 bertin
    for (y=dym, i=n; i--; y+=1.0)
2066 229 bertin
      norm += (*(maskt++) = INTERPF(y));
2067
    norm = norm>0.0? 1.0/norm : 1.0;
2068
    maskt -= n;
2069
    for (i=n; i--;)
2070
      *(maskt++) *= norm;
2071 221 bertin
    }
2072
 
2073
/* Initialize destination buffer to zero */
2074
  memset(outpix, 0, (size_t)profit->nobjpix*sizeof(PIXTYPE));
2075
 
2076
/* Make the interpolation in y and transpose once again */
2077
  dpixin0 = pixinout;
2078
  pixout0 = outpix+ixsout+iysout*profit->objnaxisn[0];
2079
  for (k=nxout; k--; dpixin0+=nyin, pixout0++)
2080
    {
2081
    maskt = mask;
2082
    nmaskt = nmask;
2083
    startt = start;
2084
    pixout = pixout0;
2085
    for (j=nyout; j--; pixout+=profit->objnaxisn[0])
2086
      {
2087
      dpixin = dpixin0+*(startt++);
2088
      val = 0.0;
2089
      for (i=*(nmaskt++); i--;)
2090
        val += *(maskt++)**(dpixin++);
2091
       *pixout = (PIXTYPE)(factor*val);
2092
      }
2093
    }
2094
 
2095
/* Free memory */
2096
  free(pixinout);
2097
  free(mask);
2098
  free(nmask);
2099
  free(start);
2100
 
2101
  return RETURN_OK;
2102 47 bertin
  }
2103
 
2104
 
2105 46 bertin
/****** profit_convolve *******************************************************
2106 201 bertin
PROTO   void profit_convolve(profitstruct *profit, float *modpix)
2107 142 bertin
PURPOSE Convolve a model image with the local PSF.
2108
INPUT   Pointer to the profit structure,
2109
        Pointer to the image raster.
2110 46 bertin
OUTPUT  -.
2111 117 bertin
NOTES   -.
2112 46 bertin
AUTHOR  E. Bertin (IAP)
2113 142 bertin
VERSION 15/09/2008
2114 46 bertin
 ***/
2115 201 bertin
void    profit_convolve(profitstruct *profit, float *modpix)
2116 46 bertin
  {
2117 52 bertin
  if (!profit->psfdft)
2118
    profit_makedft(profit);
2119 46 bertin
 
2120 142 bertin
  fft_conv(modpix, profit->psfdft, profit->modnaxisn);
2121 52 bertin
 
2122
  return;
2123
  }
2124
 
2125
 
2126
/****** profit_makedft *******************************************************
2127
PROTO   void profit_makedft(profitstruct *profit)
2128
PURPOSE Create the Fourier transform of the descrambled PSF component.
2129
INPUT   Pointer to the profit structure.
2130
OUTPUT  -.
2131 117 bertin
NOTES   -.
2132 52 bertin
AUTHOR  E. Bertin (IAP)
2133 118 bertin
VERSION 22/04/2008
2134 52 bertin
 ***/
2135
void    profit_makedft(profitstruct *profit)
2136
  {
2137
   psfstruct    *psf;
2138 201 bertin
   float      *mask,*maskt, *ppix;
2139
   float       dx,dy, r,r2,rmin,rmin2,rmax,rmax2,rsig,invrsig2;
2140 52 bertin
   int          width,height,npix,offset, psfwidth,psfheight,psfnpix,
2141
                cpwidth, cpheight,hcpwidth,hcpheight, i,j,x,y;
2142
 
2143
  if (!(psf=profit->psf))
2144
    return;
2145
 
2146 118 bertin
  psfwidth = profit->modnaxisn[0];
2147
  psfheight = profit->modnaxisn[1];
2148 52 bertin
  psfnpix = psfwidth*psfheight;
2149
  width = profit->modnaxisn[0];
2150
  height = profit->modnaxisn[1];
2151
  npix = width*height;
2152 201 bertin
  QCALLOC(mask, float, npix);
2153 52 bertin
  cpwidth = (width>psfwidth)?psfwidth:width;
2154
  hcpwidth = cpwidth>>1;
2155
  cpwidth = hcpwidth<<1;
2156
  offset = width - cpwidth;
2157
  cpheight = (height>psfheight)?psfheight:height;
2158
  hcpheight = cpheight>>1;
2159
  cpheight = hcpheight<<1;
2160
 
2161
/* Frame and descramble the PSF data */
2162 118 bertin
  ppix = profit->psfpix + (psfheight/2)*psfwidth + psfwidth/2;
2163 52 bertin
  maskt = mask;
2164
  for (j=hcpheight; j--; ppix+=psfwidth)
2165 46 bertin
    {
2166 52 bertin
    for (i=hcpwidth; i--;)
2167
      *(maskt++) = *(ppix++);
2168
    ppix -= cpwidth;
2169
    maskt += offset;
2170
    for (i=hcpwidth; i--;)
2171
      *(maskt++) = *(ppix++);
2172 46 bertin
    }
2173
 
2174 118 bertin
  ppix = profit->psfpix + ((psfheight/2)-hcpheight)*psfwidth + psfwidth/2;
2175 52 bertin
  maskt += width*(height-cpheight);
2176
  for (j=hcpheight; j--; ppix+=psfwidth)
2177
    {
2178
    for (i=hcpwidth; i--;)
2179
      *(maskt++) = *(ppix++);
2180
    ppix -= cpwidth;
2181
    maskt += offset;
2182
    for (i=hcpwidth; i--;)
2183
      *(maskt++) = *(ppix++);
2184
    }
2185 46 bertin
 
2186 52 bertin
/* Truncate to a disk that has diameter = (box width) */
2187
  rmax = cpwidth - 1.0 - hcpwidth;
2188
  if (rmax > (r=hcpwidth))
2189
    rmax = r;
2190
  if (rmax > (r=cpheight-1.0-hcpheight))
2191
    rmax = r;
2192
  if (rmax > (r=hcpheight))
2193
    rmax = r;
2194
  if (rmax<1.0)
2195
    rmax = 1.0;
2196
  rmax2 = rmax*rmax;
2197 118 bertin
  rsig = psf->fwhm/profit->pixstep;
2198 52 bertin
  invrsig2 = 1/(2*rsig*rsig);
2199
  rmin = rmax - (3*rsig);     /* 3 sigma annulus (almost no aliasing) */
2200
  rmin2 = rmin*rmin;
2201
 
2202
  maskt = mask;
2203
  dy = 0.0;
2204
  for (y=hcpheight; y--; dy+=1.0)
2205
    {
2206
    dx = 0.0;
2207
    for (x=hcpwidth; x--; dx+=1.0, maskt++)
2208
      if ((r2=dx*dx+dy*dy)>rmin2)
2209 201 bertin
        *maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
2210 52 bertin
    dx = -hcpwidth;
2211
    maskt += offset;
2212
    for (x=hcpwidth; x--; dx+=1.0, maskt++)
2213
      if ((r2=dx*dx+dy*dy)>rmin2)
2214 201 bertin
        *maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
2215 52 bertin
    }
2216
  dy = -hcpheight;
2217
  maskt += width*(height-cpheight);
2218
  for (y=hcpheight; y--; dy+=1.0)
2219
    {
2220
    dx = 0.0;
2221
    for (x=hcpwidth; x--; dx+=1.0, maskt++)
2222
      if ((r2=dx*dx+dy*dy)>rmin2)
2223 201 bertin
        *maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
2224 52 bertin
    dx = -hcpwidth;
2225
    maskt += offset;
2226
    for (x=hcpwidth; x--; dx+=1.0, maskt++)
2227
      if ((r2=dx*dx+dy*dy)>rmin2)
2228 201 bertin
        *maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
2229 52 bertin
    }
2230
 
2231
/* Finally move to Fourier space */
2232
  profit->psfdft = fft_rtf(mask, profit->modnaxisn);
2233
 
2234
  free(mask);
2235
 
2236 46 bertin
  return;
2237
  }
2238
 
2239
 
2240 49 bertin
/****** profit_copyobjpix *****************************************************
2241
PROTO   int profit_copyobjpix(profitstruct *profit, picstruct *field,
2242 146 bertin
                        picstruct *wfield)
2243 49 bertin
PURPOSE Copy a piece of the input field image to a profit structure.
2244
INPUT   Pointer to the profit structure,
2245 50 bertin
        Pointer to the field structure,
2246 146 bertin
        Pointer to the field weight structure.
2247 49 bertin
OUTPUT  The number of valid pixels copied.
2248 117 bertin
NOTES   Global preferences are used.
2249 49 bertin
AUTHOR  E. Bertin (IAP)
2250 217 bertin
VERSION 01/12/2009
2251 49 bertin
 ***/
2252
int     profit_copyobjpix(profitstruct *profit, picstruct *field,
2253 146 bertin
                        picstruct *wfield)
2254 49 bertin
  {
2255 211 bertin
   float        dx, dy2, dr2, rad2;
2256
   PIXTYPE      *pixin,*spixin, *wpixin,*swpixin, *pixout,*wpixout,
2257
                backnoise2, invgain, satlevel, wthresh, pix,spix, wpix,swpix;
2258
   int          i,x,y, xmin,xmax,ymin,ymax, w,h,dw, npix, off, gainflag,
2259 217 bertin
                badflag, sflag, sx,sy,sn,sw, ix,iy;
2260 49 bertin
 
2261
/* First put the image background to -BIG */
2262
  pixout = profit->objpix;
2263 117 bertin
  wpixout = profit->objweight;
2264 211 bertin
  for (i=profit->objnaxisn[0]*profit->objnaxisn[1]; i--;)
2265 117 bertin
    {
2266 49 bertin
    *(pixout++) = -BIG;
2267 117 bertin
    *(wpixout++) = 0.0;
2268
    }
2269 49 bertin
 
2270
/* Don't go further if out of frame!! */
2271 145 bertin
  ix = profit->ix;
2272
  iy = profit->iy;
2273 49 bertin
  if (ix<0 || ix>=field->width || iy<field->ymin || iy>=field->ymax)
2274
    return 0;
2275
 
2276 117 bertin
  backnoise2 = field->backsig*field->backsig;
2277 212 bertin
  sn = (int)profit->subsamp;
2278 211 bertin
  sflag = (sn>1);
2279
  w = profit->objnaxisn[0]*sn;
2280
  h = profit->objnaxisn[1]*sn;
2281
  if (sflag)
2282
    backnoise2 *= (PIXTYPE)sn;
2283 117 bertin
  invgain = (field->gain > 0.0) ? 1.0/field->gain : 0.0;
2284 146 bertin
  satlevel = field->satur_level - profit->obj->bkg;
2285 117 bertin
  rad2 = h/2.0;
2286
  if (rad2 > w/2.0)
2287
    rad2 = w/2.0;
2288
  rad2 *= rad2;
2289
 
2290 49 bertin
/* Set the image boundaries */
2291 52 bertin
  pixout = profit->objpix;
2292 117 bertin
  wpixout = profit->objweight;
2293 49 bertin
  ymin = iy-h/2;
2294
  ymax = ymin + h;
2295
  if (ymin<field->ymin)
2296
    {
2297 211 bertin
    off = (field->ymin-ymin-1)/sn + 1;
2298
    pixout += off*profit->objnaxisn[0];
2299
    wpixout += off*profit->objnaxisn[0];
2300
    ymin += off*sn;
2301 49 bertin
    }
2302
  if (ymax>field->ymax)
2303 211 bertin
    ymax -= ((ymax-field->ymax-1)/sn + 1)*sn;
2304 49 bertin
 
2305
  xmin = ix-w/2;
2306
  xmax = xmin + w;
2307 211 bertin
  dw = 0;
2308 49 bertin
  if (xmax>field->width)
2309
    {
2310 211 bertin
    off = (xmax-field->width-1)/sn + 1;
2311
    dw += off;
2312
    xmax -= off*sn;
2313 49 bertin
    }
2314
  if (xmin<0)
2315
    {
2316 211 bertin
    off = (-xmin-1)/sn + 1;
2317
    pixout += off;
2318
    wpixout += off;
2319
    dw += off;
2320
    xmin += off*sn;
2321 49 bertin
    }
2322 211 bertin
/* Make sure the input frame size is a multiple of the subsampling step */
2323
  if (sflag)
2324
    {
2325
/*
2326
    if (((rem=ymax-ymin)%sn))
2327
      {
2328
      ymin += rem/2;
2329
      ymax -= (rem-rem/2);
2330
      }
2331
    if (((rem=xmax-xmin)%sn))
2332
      {
2333
      xmin += rem/2;
2334
      pixout += rem/2;
2335
      wpixout += rem/2;
2336
      dw += rem;
2337
      xmax -= (rem-rem/2);
2338
      }
2339
*/
2340
    sw = field->width;
2341
    }
2342 49 bertin
 
2343
/* Copy the right pixels to the destination */
2344
  npix = 0;
2345 117 bertin
  if (wfield)
2346 49 bertin
    {
2347 117 bertin
    wthresh = wfield->weight_thresh;
2348
    gainflag = prefs.weightgain_flag;
2349 211 bertin
    if (sflag)
2350 117 bertin
      {
2351 211 bertin
/*---- Sub-sampling case */
2352
      for (y=ymin; y<ymax; y+=sn, pixout+=dw,wpixout+=dw)
2353 117 bertin
        {
2354 211 bertin
        for (x=xmin; x<xmax; x+=sn)
2355 117 bertin
          {
2356 211 bertin
          pix = wpix = 0.0;
2357
          badflag = 0;
2358
          for (sy=0; sy<sn; sy++)
2359
            {
2360
            dy2 = (y+sy-iy);
2361
            dy2 *= dy2;
2362
            dx = (x-ix);
2363
            spixin = &PIX(field, x, y+sy);
2364
            swpixin = &PIX(wfield, x, y+sy);
2365
            for (sx=sn; sx--;)
2366
              {
2367
              dr2 = dy2 + dx*dx;
2368
              dx++;
2369
              spix = *(spixin++);
2370
              swpix = *(swpixin++);
2371
              if (dr2<rad2 && spix>-BIG && spix<satlevel && swpix<wthresh)
2372
                {
2373
                pix += spix;
2374
                wpix += swpix;
2375
                }
2376
              else
2377
                badflag=1;
2378
              }
2379
            }
2380
          *(pixout++) = pix;
2381
          if (!badflag) /* A single bad pixel ruins is all (saturation, etc.)*/
2382
            {
2383
            *(wpixout++) = 1.0 / sqrt(wpix+(pix>0.0?
2384 117 bertin
                (gainflag? pix*wpix/backnoise2:pix)*invgain : 0.0));
2385 211 bertin
            npix++;
2386
            }
2387
          else
2388
            *(wpixout++) = 0.0;
2389 117 bertin
          }
2390
        }
2391
      }
2392 211 bertin
    else
2393
      for (y=ymin; y<ymax; y++, pixout+=dw,wpixout+=dw)
2394
        {
2395
        dy2 = y-iy;
2396
        dy2 *= dy2;
2397
        pixin = &PIX(field, xmin, y);
2398
        wpixin = &PIX(wfield, xmin, y);
2399
        for (x=xmin; x<xmax; x++)
2400
          {
2401
          dx = x-ix;
2402
          dr2 = dy2 + dx*dx;
2403
          pix = *(pixin++);
2404
          wpix = *(wpixin++);
2405
          if (dr2<rad2 && pix>-BIG && pix<satlevel && wpix<wthresh)
2406
            {
2407
            *(pixout++) = pix;
2408
            *(wpixout++) = 1.0 / sqrt(wpix+(pix>0.0?
2409
                (gainflag? pix*wpix/backnoise2:pix)*invgain : 0.0));
2410
            npix++;
2411
            }
2412
          else
2413
            *(pixout++) = *(wpixout++) = 0.0;
2414
          }
2415
        }
2416 49 bertin
    }
2417 117 bertin
  else
2418 211 bertin
    {
2419
    if (sflag)
2420 117 bertin
      {
2421 211 bertin
/*---- Sub-sampling case */
2422
      for (y=ymin; y<ymax; y+=sn, pixout+=dw, wpixout+=dw)
2423 117 bertin
        {
2424 211 bertin
        for (x=xmin; x<xmax; x+=sn)
2425 117 bertin
          {
2426 211 bertin
          pix = 0.0;
2427
          badflag = 0;
2428
          for (sy=0; sy<sn; sy++)
2429
            {
2430
            dy2 = y+sy-iy;
2431
            dy2 *= dy2;
2432
            dx = x-ix;
2433
            spixin = &PIX(field, x, y+sy);
2434
            for (sx=sn; sx--;)
2435
              {
2436
              dr2 = dy2 + dx*dx;
2437
              dx++;
2438
              spix = *(spixin++);
2439
              if (dr2<rad2 && spix>-BIG && spix<satlevel)
2440
                pix += spix;
2441
              else
2442
                badflag=1;
2443
              }
2444
            }
2445
          *(pixout++) = pix;
2446
          if (!badflag) /* A single bad pixel ruins is all (saturation, etc.)*/
2447
            {
2448
            *(wpixout++) = 1.0 / sqrt(backnoise2 + (pix>0.0?pix*invgain:0.0));
2449
            npix++;
2450
            }
2451
          else
2452
            *(wpixout++) = 0.0;
2453 117 bertin
          }
2454
        }
2455
      }
2456 211 bertin
    else
2457
      for (y=ymin; y<ymax; y++, pixout+=dw,wpixout+=dw)
2458
        {
2459
        dy2 = y-iy;
2460
        dy2 *= dy2;
2461
        pixin = &PIX(field, xmin, y);
2462
        for (x=xmin; x<xmax; x++)
2463
          {
2464
          dx = x-ix;
2465
          dr2 = dy2 + dx*dx;
2466
          pix = *(pixin++);
2467
          if (dr2<rad2 && pix>-BIG && pix<satlevel)
2468
            {
2469
            *(pixout++) = pix;
2470
            *(wpixout++) = 1.0 / sqrt(backnoise2 + (pix>0.0?pix*invgain : 0.0));
2471
            npix++;
2472
            }
2473
          else
2474
            *(pixout++) = *(wpixout++) = 0.0;
2475
          }
2476
        }
2477
    }
2478 117 bertin
 
2479 49 bertin
  return npix;
2480
  }
2481
 
2482
 
2483 77 bertin
/****** profit_spiralindex ****************************************************
2484 201 bertin
PROTO   float profit_spiralindex(profitstruct *profit)
2485 77 bertin
PURPOSE Compute the spiral index of a galaxy image (positive for arms
2486
        extending counter-clockwise and negative for arms extending CW, 0 for
2487
        no spiral pattern).
2488 146 bertin
INPUT   Profile-fitting structure.
2489 77 bertin
OUTPUT  Vector of residuals.
2490 117 bertin
NOTES   -.
2491 77 bertin
AUTHOR  E. Bertin (IAP)
2492 297 bertin
VERSION 12/07/2012
2493 77 bertin
 ***/
2494 201 bertin
float profit_spiralindex(profitstruct *profit)
2495 77 bertin
  {
2496 146 bertin
   objstruct    *obj;
2497
   obj2struct   *obj2;
2498 201 bertin
   float        *dx,*dy, *fdx,*fdy, *gdx,*gdy, *gdxt,*gdyt, *pix,
2499 77 bertin
                fwhm, invtwosigma2, hw,hh, ohw,ohh, x,y,xstart, tx,ty,txstart,
2500 78 bertin
                gx,gy, r2, spirindex, invsig, val, sep;
2501
   PIXTYPE      *fpix;
2502 77 bertin
   int          i,j, npix;
2503 78 bertin
 
2504 77 bertin
  npix = profit->objnaxisn[0]*profit->objnaxisn[1];
2505
 
2506 146 bertin
  obj = profit->obj;
2507
  obj2 = profit->obj2;
2508 77 bertin
/* Compute simple derivative vectors at a fraction of the object scale */
2509 246 bertin
  fwhm = profit->guessradius * 2.0 / 4.0;
2510 77 bertin
  if (fwhm < 2.0)
2511
    fwhm = 2.0;
2512 78 bertin
  sep = 2.0;
2513 77 bertin
 
2514
  invtwosigma2 = -(2.35*2.35/(2.0*fwhm*fwhm));
2515 201 bertin
  hw = (float)(profit->objnaxisn[0]/2);
2516 77 bertin
  ohw = profit->objnaxisn[0] - hw;
2517 201 bertin
  hh = (float)(profit->objnaxisn[1]/2);
2518 77 bertin
  ohh = profit->objnaxisn[1] - hh;
2519
  txstart = -hw;
2520
  ty = -hh;
2521 201 bertin
  QMALLOC(dx, float, npix);
2522 77 bertin
  pix = dx;
2523
  for (j=profit->objnaxisn[1]; j--; ty+=1.0)
2524
    {
2525
    tx = txstart;
2526
    y = ty < -0.5? ty + hh : ty - ohh;
2527
    for (i=profit->objnaxisn[0]; i--; tx+=1.0)
2528
      {
2529
      x = tx < -0.5? tx + hw : tx - ohw;
2530 78 bertin
      *(pix++) = exp(invtwosigma2*((x+sep)*(x+sep)+y*y))
2531
                - exp(invtwosigma2*((x-sep)*(x-sep)+y*y));
2532 77 bertin
      }
2533
    }
2534 201 bertin
  QMALLOC(dy, float, npix);
2535 77 bertin
  pix = dy;
2536
  ty = -hh;
2537
  for (j=profit->objnaxisn[1]; j--; ty+=1.0)
2538
    {
2539
    tx = txstart;
2540
    y = ty < -0.5? ty + hh : ty - ohh;
2541
    for (i=profit->objnaxisn[0]; i--; tx+=1.0)
2542
      {
2543
      x = tx < -0.5? tx + hw : tx - ohw;
2544 78 bertin
      *(pix++) = exp(invtwosigma2*(x*x+(y+sep)*(y+sep)))
2545
                - exp(invtwosigma2*(x*x+(y-sep)*(y-sep)));
2546 77 bertin
      }
2547
    }
2548
 
2549 201 bertin
  QMALLOC(gdx, float, npix);
2550 77 bertin
  gdxt = gdx;
2551 78 bertin
  fpix = profit->objpix;
2552
  invsig = npix/profit->sigma;
2553
  for (i=npix; i--; fpix++)
2554 77 bertin
    {
2555 78 bertin
    val = *fpix > -1e29? *fpix*invsig : 0.0;
2556
    *(gdxt++) = (val>0.0? log(1.0+val) : -log(1.0-val));
2557 77 bertin
    }
2558 123 bertin
  gdy = NULL;                   /* to avoid gcc -Wall warnings */
2559 201 bertin
  QMEMCPY(gdx, gdy, float, npix);
2560 77 bertin
  fdx = fft_rtf(dx, profit->objnaxisn);
2561
  fft_conv(gdx, fdx, profit->objnaxisn);
2562
  fdy = fft_rtf(dy, profit->objnaxisn);
2563
  fft_conv(gdy, fdy, profit->objnaxisn);
2564
 
2565
/* Compute estimator */
2566 246 bertin
  invtwosigma2 = -1.18*1.18 / (2.0*profit->guessradius*profit->guessradius);
2567 146 bertin
  xstart = -hw - obj->mx + (int)(obj->mx+0.49999);
2568 78 bertin
  y = -hh -  obj->my + (int)(obj->my+0.49999);;
2569 77 bertin
  spirindex = 0.0;
2570
  gdxt = gdx;
2571
  gdyt = gdy;
2572
  for (j=profit->objnaxisn[1]; j--; y+=1.0)
2573
    {
2574
    x = xstart;
2575
    for (i=profit->objnaxisn[0]; i--; x+=1.0)
2576
      {
2577
      gx = *(gdxt++);
2578
      gy = *(gdyt++);
2579
      if ((r2=x*x+y*y)>0.0)
2580 78 bertin
        spirindex += (x*y*(gx*gx-gy*gy)+gx*gy*(y*y-x*x))/r2
2581 77 bertin
                        * exp(invtwosigma2*r2);
2582
      }
2583
    }
2584
 
2585
  free(dx);
2586
  free(dy);
2587 297 bertin
  QFFTWF_FREE(fdx);
2588
  QFFTWF_FREE(fdy);
2589 77 bertin
  free(gdx);
2590
  free(gdy);
2591
 
2592
  return spirindex;
2593
  }
2594
 
2595
 
2596 89 bertin
/****** profit_moments ****************************************************
2597 207 bertin
PROTO   void profit_moments(profitstruct *profit, obj2struct *obj2)
2598 89 bertin
PURPOSE Compute the 2nd order moments from the unconvolved object model.
2599 207 bertin
INPUT   Profile-fitting structure,
2600
        Pointer to obj2 structure.
2601 89 bertin
OUTPUT  -.
2602 117 bertin
NOTES   -.
2603 89 bertin
AUTHOR  E. Bertin (IAP)
2604 244 bertin
VERSION 22/04/2011
2605 89 bertin
 ***/
2606 207 bertin
void     profit_moments(profitstruct *profit, obj2struct *obj2)
2607 89 bertin
  {
2608 221 bertin
   profstruct   *prof;
2609 226 bertin
   double       dpdmx2[6], cov[4],
2610
                *jac,*jact, *pjac,*pjact, *dcovar,*dcovart,
2611
                *dmx2,*dmy2,*dmxy,
2612
                m0,invm0, mx2,my2,mxy, den,invden,
2613
                temp, temp2,invtemp2,invstemp2,
2614
                pmx2,theta, flux, dval;
2615 225 bertin
   float         *covart;
2616 244 bertin
   int          findex[MODEL_NMAX],
2617 225 bertin
                i,j,p, nparam;
2618 89 bertin
 
2619 221 bertin
/*  hw = (float)(profit->modnaxisn[0]/2);*/
2620
/*  hh = (float)(profit->modnaxisn[1]/2);*/
2621
/*  r2max = hw<hh? hw*hw : hh*hh;*/
2622
/*  xstart = -hw;*/
2623
/*  y = -hh;*/
2624
/*  pix = profit->modpix;*/
2625
/*  mx2 = my2 = mxy = mx = my = sum = 0.0;*/
2626
/*  for (iy=profit->modnaxisn[1]; iy--; y+=1.0)*/
2627
/*    {*/
2628
/*    x = xstart;*/
2629
/*    for (ix=profit->modnaxisn[0]; ix--; x+=1.0)*/
2630
/*      if (y*y+x*x <= r2max)*/
2631
/*        {*/
2632
/*        val = *(pix++);*/
2633
/*        sum += val;*/
2634
/*        mx  += val*x;*/
2635
/*        my  += val*y;*/
2636
/*        mx2 += val*x*x;*/
2637
/*        mxy += val*x*y;*/
2638
/*        my2 += val*y*y;*/
2639
/*        }*/
2640
/*      else*/
2641
/*        pix++;*/
2642
/*    }*/
2643
 
2644
/*  if (sum <= 1.0/BIG)*/
2645
/*    sum = 1.0;*/
2646
/*  mx /= sum;*/
2647
/*  my /= sum;*/
2648
/*  obj2->prof_mx2 = mx2 = mx2/sum - mx*mx;*/
2649
/*  obj2->prof_my2 = my2 = my2/sum - my*my;*/
2650
/*  obj2->prof_mxy = mxy = mxy/sum - mx*my;*/
2651
 
2652 225 bertin
  nparam = profit->nparam;
2653 226 bertin
  if (FLAG(obj2.prof_e1err) || FLAG(obj2.prof_pol1err))
2654