public software.sextractor

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

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