public software.sextractor

[/] [trunk/] [src/] [pc.c] - Blame information for rev 206

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 bertin
  /*
2
                                pc.c
3
 
4
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5
*
6
*       Part of:        SExtractor
7
*
8
*       Author:         E.BERTIN (IAP)
9
*
10
*       Contents:       Stuff related to Principal Component Analysis (PCA).
11
*
12 206 bertin
*       Last modify:    13/09/2009
13 2 bertin
*
14
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15
*/
16
 
17
#ifdef HAVE_CONFIG_H
18
#include        "config.h"
19
#endif
20
 
21
#include        <math.h>
22
#include        <stdio.h>
23
#include        <stdlib.h>
24
#include        <string.h>
25
 
26
#include        "define.h"
27
#include        "globals.h"
28
#include        "prefs.h"
29
#include        "fits/fitscat.h"
30
#include        "check.h"
31
#include        "image.h"
32 173 bertin
#include        "wcs/poly.h"
33 2 bertin
#include        "psf.h"
34
 
35
static  obj2struct      *obj2 = &outobj2;
36
 
37
/****** pc_end ***************************************************************
38
PROTO   void pc_end(pcstruct *pc)
39
PURPOSE Free a PC structure and everything it contains.
40
INPUT   pcstruct pointer.
41
OUTPUT  -.
42
NOTES   -.
43
AUTHOR  E. Bertin (IAP, Leiden observatory & ESO)
44
VERSION 15/07/99
45
 ***/
46
void    pc_end(pcstruct *pc)
47
  {
48
   int  i;
49
 
50
  free(pc->maskcomp);
51
  free(pc->omaskcomp);
52
  free(pc->omasksize);
53
  free(pc->maskcurr);
54
  free(pc->masksize);
55
  free(pc->mx2);
56
  free(pc->my2);
57
  free(pc->mxy);
58
  free(pc->flux);
59
  free(pc->bt);
60
  if (pc->code)
61
    {
62
    free(pc->code->pc);
63
    for (i=0; i<pc->code->nparam;i++)
64
      free(pc->code->param[i]);
65
    free(pc->code->param);
66
    free(pc->code);
67
    }
68
  free(pc);
69
 
70
  return;
71
  }
72
 
73
 
74
/********************************** pc_load **********************************/
75
/*
76
Load the PC data from a FITS file.
77
*/
78
pcstruct        *pc_load(catstruct *cat)
79
  {
80
   pcstruct     *pc;
81
   tabstruct    *tab;
82
   keystruct    *key;
83
   codestruct   *code;
84
   char         *head, str[80], *ci, *filename;
85
   int          i, ncode,nparam;
86
 
87
  if (!(tab = name_to_tab(cat, "PC_DATA", 0)))
88
    return NULL;
89
 
90
  filename = cat->filename;
91
 
92
/* OK, we now allocate memory for the PC structure itself */
93
  QCALLOC(pc, pcstruct, 1);
94
 
95
/* Store a short copy of the PC filename */
96
  if ((ci=strrchr(filename, '/')))
97
    strcpy(pc->name, ci+1);
98
  else
99
    strcpy(pc->name, filename);
100
 
101
/* Load important scalars (which are stored as FITS keywords) */
102
  head = tab->headbuf;
103
 
104
/* Dimensionality of the PC mask */
105
  if (fitsread(head, "PCNAXIS", &pc->maskdim, H_INT, T_LONG) != RETURN_OK)
106
    return NULL;
107
  if (pc->maskdim<2 || pc->maskdim>4)
108
    error(EXIT_FAILURE, "*Error*: wrong dimensionality for the PC "
109
        "mask in ", filename);
110
  QMALLOC(pc->masksize, int, pc->maskdim);
111
  for (i=0; i<pc->maskdim; i++)
112
    pc->masksize[i] = 1;
113
  pc->masknpix = 1;
114
  for (i=0; i<pc->maskdim; i++)
115
    {
116
    sprintf(str, "PCAXIS%1d ", i+1);
117
    if (fitsread(head, str, &pc->masksize[i], H_INT,T_LONG) != RETURN_OK)
118
      goto headerror;
119
    pc->masknpix *= pc->masksize[i];
120
   }
121
 
122
  pc->npc = pc->masksize[pc->maskdim-1];
123
 
124
  ncode = 0;
125
  fitsread(head, "NCODE", &ncode, H_INT, T_LONG);
126
  fitsread(head, "NCODEPAR", &nparam, H_INT, T_LONG);
127
 
128
/* Load the PC mask data */
129
  key = read_key(tab, "PC_CONVMASK");
130
  pc->maskcomp = key->ptr;
131
 
132
  key = read_key(tab, "PC_MASK");
133
  pc->omaskcomp = key->ptr;
134
  pc->omaskdim = key->naxis;
135
  pc->omasknpix = 1;
136
  QMALLOC(pc->omasksize, int, pc->omaskdim);
137
  for (i=0; i<pc->omaskdim; i++)
138
    pc->omasknpix *= (pc->omasksize[i] = key->naxisn[i]);
139
 
140
  key = read_key(tab, "PC_MX2");
141
  pc->mx2 = key->ptr;
142
 
143
  key = read_key(tab, "PC_MY2");
144
  pc->my2 = key->ptr;
145
 
146
  key = read_key(tab, "PC_MXY");
147
  pc->mxy = key->ptr;
148
 
149
  key = read_key(tab, "PC_FLUX");
150
  pc->flux = key->ptr;
151
 
152
  key = read_key(tab, "PC_BRATIO");
153
  pc->bt = key->ptr;
154
 
155
  if (ncode)
156
    {
157
    QMALLOC(pc->code, codestruct, 1);
158
    code = pc->code;
159
    QMALLOC(code->param, float *, nparam);
160
    QMALLOC(code->parammod, int, nparam);
161
    code->ncode = ncode;
162
    code->nparam = nparam;
163
    key = read_key(tab, "CODE_PC");
164
    code->pc = (float *)key->ptr;
165
    for (i=0; i<nparam; i++)
166
      {
167
      sprintf(str, "CODE_P%d", i+1);
168
      key = read_key(tab, str);
169
      code->param[i] = (float *)key->ptr;
170
      sprintf(str, "CODE_M%d", i+1);
171
      fitsread(head, str, &code->parammod[i], H_INT, T_LONG);
172
      }
173
    }
174
 
175 206 bertin
  QMALLOC(pc->maskcurr, float, pc->masksize[0]*pc->masksize[1]*pc->npc);
176 2 bertin
 
177
/* But don't touch my arrays!! */
178
  blank_keys(tab);
179
 
180
  return pc;
181
 
182
headerror:
183
  error(EXIT_FAILURE, "*Error*: Incorrect or obsolete PC data in ", filename);
184
  return NULL;
185
  }
186
 
187
 
188
/********************************** pc_fit **********************************/
189
/*
190
Fit the PC data to the current data.
191
*/
192 206 bertin
void    pc_fit(psfstruct *psf, float *data, float *weight,
193 2 bertin
                int width, int height,int ix, int iy,
194 206 bertin
                float dx, float dy, int npc, float backrms)
195 2 bertin
  {
196
   pcstruct     *pc;
197
   checkstruct  *check;
198
   codestruct   *code;
199 206 bertin
   double       *basis,*basis0;
200
   float        *cpix,*cpix0, *pcshift,*wpcshift,
201 2 bertin
                *spix,*wspix, *w, *sumopc,*sumopct, *checkbuf,
202
                *sol,*solt, *datat,
203
                *mx2t, *my2t, *mxyt,
204
                val,val2, xm2,ym2,xym,flux, temp,temp2, theta, pmx2,pmy2,
205
                wnorm, ellip, norm, snorm;
206
   float        **param, *ppix, *ospix, *cpc,*cpc2, *fparam,
207
                pixstep, fval, fvalmax, fscale, dparam;
208
   int          *parammod,
209
                c,n,p, npix,npix2,nopix, ncoeff, nparam, nmax,nmax2, ncode;
210
 
211
  pc = psf->pc;
212
/* Build the "local PCs", using the basis func. coeffs computed in psf_fit() */
213
  if (npc > pc->npc)
214
    npc = pc->npc;
215
  npix = pc->masksize[0]*pc->masksize[1];
216
  npix2 = width*height;
217
  ncoeff = psf->poly->ncoeff;
218
  pixstep = 1.0/psf->pixstep;
219
  dx *= pixstep;
220
  dy *= pixstep;
221
 
222 206 bertin
  memset(pc->maskcurr, 0, npix*npc*sizeof(float));
223 2 bertin
  basis0 = psf->poly->basis;
224
  cpix0 = pc->maskcurr;
225
  ppix = pc->maskcomp;
226
 
227
/* Sum each (PSF-dependent) component */
228
  for (c=npc; c--; cpix0 += npix)
229
    {
230
    basis = basis0;
231
    for (n = ncoeff; n--;)
232
      {
233
      cpix = cpix0;
234
      val = *(basis++);
235
      for (p=npix; p--;)
236 206 bertin
        *(cpix++) += val**(ppix++);
237 2 bertin
      }
238
    }
239
 
240
/* Allocate memory for temporary buffers */
241 206 bertin
  QMALLOC(pcshift, float, npix2*npc);
242
  QMALLOC(wpcshift, float, npix2*npc);
243
  QMALLOC(sol, float, npc);
244 2 bertin
 
245
/* Now shift and scale to the right position, and weight the PCs */
246
  cpix = pc->maskcurr;
247
  spix = pcshift;
248
  wspix = wpcshift;
249
  for (c=npc; c--; cpix += npix)
250
    {
251
    vignet_resample(cpix, pc->masksize[0], pc->masksize[1],
252
                spix, width, height, -dx, -dy, pixstep);
253
    w = weight;
254
    for (p=npix2; p--;)
255
      *(wspix++) = *(spix++)**(w++);
256
    }
257
 
258
/* Compute the weight normalization */
259
  wnorm = 0.0;
260
  w = weight;
261
  for (p=npix2; p--;)
262
    {
263
    val = *(w++);
264
    wnorm += val*val;
265
    }
266
 
267
/* Scalar product of data and (approximately orthogonal) basis functions */
268
  wspix = wpcshift;
269
  solt = sol;
270
  snorm = 0.0;
271
  for (c=npc; c--;)
272
    {
273
    datat = data;
274
    val = 0.0;
275
    for (p=npix2; p--;)
276
      val += *(datat++)**(wspix++);
277
    val2 = *(solt++) = val*npix2/wnorm;
278
    snorm += val2*val2;
279
    }
280
 
281
 
282
/* Normalize solution vector */
283
  snorm = sqrt(snorm);
284
  solt = sol;
285
  for (c=npc; c--;)
286
    *(solt++) /= snorm;
287
 
288
  if ((code = pc->code))
289
    {
290
    ncode = code->ncode;
291
/*-- Codebook search */
292
    cpc = code->pc;
293
    fvalmax = -BIG;
294
    nmax = 0;
295
    for (n=ncode; n--;)
296
      {
297
      fval = 0.0;
298
      solt = sol;
299
      for (p=npc; p--;)
300
        fval += *(solt++)**(cpc++);
301
      if (fval>fvalmax)
302
        {
303
        fvalmax = fval;
304
        nmax = n;
305
        }
306
      }
307
    nmax = ncode - 1 - nmax;
308
 
309
/*-- Interpolation */
310
    param = code->param;
311
    parammod = code->parammod;
312
    nparam = code->nparam;
313
    QMALLOC(fparam, float, nparam);
314
    for (p=0; p<nparam; p++)
315
      {
316
      dparam = 0.0;
317
      if (parammod[p])
318
        {
319
        val2 = 0.0;
320
        if ((nmax2 = nmax+parammod[p]) < ncode)
321
          {
322
          cpc = code->pc+npc*nmax;
323
          cpc2 = code->pc+npc*nmax2;
324
          solt = sol;
325
          norm = 0.0;
326
          for (c=npc; c--;)
327
            {
328
            val = *(cpc2++)-*cpc;
329
            val2 += val*(*(solt++) - *(cpc++));
330
            norm += val*val;
331
            }
332
          if (norm>0.0)
333
            dparam = val2/norm*(param[p][nmax2]-param[p][nmax]);
334
          else
335
            val2 = 0.0;
336
          }
337
/*------ If dot product negative of something went wrong, try other side */
338
        if (val2<=0.0 && (nmax2 = nmax-parammod[p]) >= 0)
339
          {
340
          cpc = code->pc+npc*nmax;
341
          cpc2 = code->pc+npc*nmax2;
342
          solt = sol;
343
          norm = val2 = 0.0;
344
          for (c=npc; c--;)
345
            {
346
            val = *(cpc2++)-*cpc;
347
            val2 += val*(*(solt++) - *(cpc++));
348
            norm += val*val;
349
            }
350
          if (norm>0.0)
351
            dparam = val2/norm*(param[p][nmax2]-param[p][nmax]);
352
          }
353
        fparam[p] = param[p][nmax] + dparam;
354
        }
355
      }
356
 
357
    solt = sol;
358
    cpc = code->pc+npc*nmax;
359
    fscale = fvalmax*code->param[0][nmax]*snorm;
360
    for (p=npc; p--;)
361
      *(solt++) = fscale**(cpc++);
362
 
363
/*-- Copy the derived physical quantities to output parameters */
364
/*-- (subject to changes) */
365
    obj2->flux_galfit = fscale;
366
    obj2->gdposang = fparam[1];
367
    if (obj2->gdposang>90.0)
368
      obj2->gdposang -= 180.0;
369
    else if (obj2->gdposang<-90.0)
370
      obj2->gdposang += 180.0;
371
    obj2->gdscale = fparam[2];
372
    obj2->gdaspect = fparam[3];
373
    ellip = (1.0 - obj2->gdaspect)/(1.0 + obj2->gdaspect);
374
    obj2->gde1 = (float)(ellip*cos(2*obj2->gdposang*PI/180.0));
375
    obj2->gde2 = (float)(ellip*sin(2*obj2->gdposang*PI/180.0));
376
/*---- Copy the best-fitting PCs to the VECTOR_PC output vector */
377
    if (FLAG(obj2.vector_pc))
378
      {
379
      solt = sol;
380
      ppix = obj2->vector_pc;
381
      for (c=prefs.pc_vectorsize>npc?npc:prefs.pc_vectorsize; c--;)
382
        *(ppix++) = *(solt++);
383
      }
384
 
385
    free(fparam);
386
    }
387
 
388
  xm2 = ym2 = xym = flux = 0.0;
389
  solt = sol;
390
  mx2t = pc->mx2;
391
  my2t = pc->my2;
392
  mxyt = pc->mxy;
393
  for (c=npc; c--;)
394
    {
395
    val = *(solt++);
396
    xm2 += val**(mx2t++);
397
    ym2 += val**(my2t++);
398
    xym += val**(mxyt++);
399
    }
400
 
401
  obj2->mx2_pc = xm2;
402
  obj2->my2_pc = ym2;
403
  obj2->mxy_pc = xym;
404
 
405
  if (FLAG(obj2.a_pc))
406
    {
407
/* Handle fully correlated x/y (which cause a singularity...) */
408
    if ((temp2=xm2*ym2-xym*xym)<0.00694)
409
      {
410
      xm2 += 0.0833333;
411
      ym2 += 0.0833333;
412
      temp2 = xm2*ym2-xym*xym;
413
      }
414
 
415
    if ((fabs(temp=xm2-ym2)) > 0.0)
416
      theta = atan2(2.0 * xym,temp) / 2.0;
417
    else
418
      theta = PI/4.0;
419
 
420
    temp = sqrt(0.25*temp*temp+xym*xym);
421
    pmy2 = pmx2 = 0.5*(xm2+ym2);
422
    pmx2 += temp;
423
    pmy2 -= temp;
424
 
425
    obj2->a_pc = (float)sqrt(pmx2);
426
    obj2->b_pc = (float)sqrt(pmy2);
427
    obj2->theta_pc = (float)(theta*180.0/PI);
428
    }
429
 
430
/* CHECK-Images */
431
  if (prefs.check[CHECK_SUBPCPROTOS] || prefs.check[CHECK_PCPROTOS])
432
    {
433
    spix = pcshift;
434
    solt = sol;
435
    for (c=npc; c--; solt++)
436
      {
437
      ppix = checkmask;
438
      for (p=npix2; p--;)
439
        *(ppix++) = (PIXTYPE)*(spix++);
440
      if ((check = prefs.check[CHECK_SUBPCPROTOS]))
441
        addcheck(check, checkmask, width,height, ix,iy, -*solt);
442
      if ((check = prefs.check[CHECK_PCPROTOS]))
443
        addcheck(check, checkmask, width,height, ix,iy, *solt);
444
      }
445
    }
446
  if ((check = prefs.check[CHECK_PCOPROTOS]))
447
    {
448
/*- Reconstruct the unconvolved profile */
449
    nopix = pc->omasksize[0]*pc->omasksize[1];
450 206 bertin
    QCALLOC(sumopc, float, nopix);
451 2 bertin
    solt = sol;
452
    ospix = pc->omaskcomp;
453
    for (c=npc; c--;)
454
      {
455
      val = *(solt++);
456
      sumopct = sumopc;
457
      for (p=nopix; p--;)
458 206 bertin
        *(sumopct++) += val**(ospix++);
459 2 bertin
      }
460 206 bertin
    QMALLOC(checkbuf, float, npix2);
461 2 bertin
    vignet_resample(sumopc, pc->omasksize[0], pc->omasksize[1],
462
                checkbuf, width, height, -dx, -dy, pixstep);
463
    ppix = checkmask;
464
    spix = checkbuf;
465
    for (p=npix2; p--;)
466
      *(ppix++) = (PIXTYPE)*(spix++);
467
    addcheck(check, checkmask, width,height, ix,iy, 1.0);
468
    free(checkbuf);
469
    free(sumopc);
470
    }
471
 
472
/* Free memory */
473
  free(pcshift);
474
  free(wpcshift);
475
  free(sol);
476
 
477
  return;
478
  }
479