00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033
00034 #include <cpl.h>
00035 #include <math.h>
00036
00037 #include "vircam_mods.h"
00038 #include "vircam_utils.h"
00039 #include "vircam_wcsutils.h"
00040 #include "vircam_stats.h"
00041 #include "vircam_pfits.h"
00042
00043 static double *work = NULL;
00044 static unsigned char *iwork = NULL;
00045
00046 static int vircam_plate6(double *xpos, double *ypos, double *xi, double *eta,
00047 unsigned char *flag, int nstds, double *a, double *b,
00048 double *c, double *d, double *e, double *f);
00049 static int vircam_plate4(double *xpos, double *ypos, double *xi, double *eta,
00050 unsigned char *flag, int nstds, double *a, double *b,
00051 double *c, double *d, double *e, double *f);
00052 static void tidy(void);
00053
00056
00129
00130
00131 extern int vircam_platesol(cpl_propertylist *plist, cpl_propertylist *tlist,
00132 cpl_table *matchedstds, int nconst, int shiftan,
00133 int *status) {
00134 int nstds,nc2,i,niter,nrej,ngood,nreq=6,xcol,ycol;
00135 long n1,n2;
00136 const char *fctid = "vircam_platesol";
00137 float *tptr;
00138 double *xptr,*yptr,*xptr2,*yptr2,*ra,*dec,*xiptr,*etaptr,*wptr,averr;
00139 double r1,r2,d1,d2,newcrval1,newcrval2,a,b,c,d,e,f,xifit,etafit,dxi,deta;
00140 double crpix1,crpix2,xi,eta,rac_before,rac_after,decc_before,decc_after;
00141 double xcen,ycen,oldtheta,scale,oldcrpix1,oldcrpix2,*crdata;
00142 unsigned char *isbad,*wptr2;
00143 const char *reqcols[] = {"X_coordinate","Y_coordinate","xpredict",
00144 "ypredict","RA","Dec"};
00145 char key[9];
00146 cpl_wcs *wcs;
00147 cpl_array *cr;
00148 cpl_matrix *crm;
00149
00150
00151
00152 if (*status != VIR_OK)
00153 return(*status);
00154
00155
00156
00157 if (nconst != 4 && nconst != 6) {
00158 cpl_msg_error(fctid,"Value of nconst = %d is unsupported",nconst);
00159 FATAL_ERROR
00160 }
00161
00162
00163
00164 nstds = cpl_table_get_nrow(matchedstds);
00165 nc2 = nconst/2;
00166 if (nstds < nc2) {
00167 cpl_msg_error(fctid,
00168 "Too few standards (%d) in table for %d coefficient fit",
00169 nstds,nconst);
00170 FATAL_ERROR
00171 }
00172
00173
00174
00175 for (i = 0; i < nreq; i++) {
00176 if (cpl_table_has_column(matchedstds,reqcols[i]) != 1) {
00177 cpl_msg_error(fctid,"Matched standards table missing column %s\n",
00178 reqcols[i]);
00179 FATAL_ERROR
00180 }
00181 }
00182
00183
00184
00185 work = cpl_malloc(10*nstds*sizeof(*work));
00186 iwork = cpl_calloc(3*nstds,sizeof(*isbad));
00187 xptr = work;
00188 yptr = work + nstds;
00189 xptr2 = work + 2*nstds;
00190 yptr2 = work + 3*nstds;
00191 ra = work + 4*nstds;
00192 dec = work + 5*nstds;
00193 xiptr = work + 6*nstds;
00194 etaptr = work + 7*nstds;
00195 wptr = work + 8*nstds;
00196 isbad = iwork;
00197 wptr2 = iwork + nstds;
00198
00199
00200
00201
00202 tptr = cpl_table_get_data_float(matchedstds,"X_coordinate");
00203 for (i = 0; i < nstds; i++)
00204 xptr[i] = (double)tptr[i];
00205 tptr = cpl_table_get_data_float(matchedstds,"Y_coordinate");
00206 for (i = 0; i < nstds; i++)
00207 yptr[i] = (double)tptr[i];
00208 tptr = cpl_table_get_data_float(matchedstds,"xpredict");
00209 for (i = 0; i < nstds; i++)
00210 xptr2[i] = (double)tptr[i];
00211 tptr = cpl_table_get_data_float(matchedstds,"ypredict");
00212 for (i = 0; i < nstds; i++)
00213 yptr2[i] = (double)tptr[i];
00214 tptr = cpl_table_get_data_float(matchedstds,"RA");
00215 for (i = 0; i < nstds; i++)
00216 ra[i] = (double)tptr[i];
00217 tptr = cpl_table_get_data_float(matchedstds,"Dec");
00218 for (i = 0; i < nstds; i++)
00219 dec[i] = (double)tptr[i];
00220
00221
00222
00223
00224 if (shiftan) {
00225 wcs = cpl_wcs_new_from_propertylist(plist);
00226 cr = cpl_wcs_get_crval(wcs);
00227 crdata = cpl_array_get_data_double(cr);
00228 for (i = 0; i < nstds; i++) {
00229 vircam_xytoradec(wcs,xptr[i],yptr[i],&r1,&d1);
00230 vircam_xytoradec(wcs,xptr2[i],yptr2[i],&r2,&d2);
00231 xiptr[i] = r2 - r1;
00232 etaptr[i] = d2 - d1;
00233 }
00234 r1 = vircam_dmed(xiptr,NULL,nstds);
00235 d1 = vircam_dmed(etaptr,NULL,nstds);
00236 newcrval1 = crdata[0] + r1;
00237 newcrval2 = crdata[1] + d1;
00238 cpl_propertylist_update_double(plist,"CRVAL1",newcrval1);
00239 cpl_propertylist_update_double(plist,"CRVAL2",newcrval2);
00240 cpl_wcs_delete(wcs);
00241 }
00242
00243
00244
00245 wcs = cpl_wcs_new_from_propertylist(plist);
00246 (void)vircam_pfits_get_naxis1(plist,&n1);
00247 (void)vircam_pfits_get_naxis2(plist,&n2);
00248 cr = cpl_wcs_get_crpix(wcs);
00249 crdata = cpl_array_get_data_double(cr);
00250 oldcrpix1 = crdata[0];
00251 oldcrpix2 = crdata[1];
00252 xcen = 0.5*(double)n1;
00253 ycen = 0.5*(double)n2;
00254 vircam_xytoradec(wcs,xcen,ycen,&rac_before,&decc_before);
00255
00256
00257
00258 for (i = 0; i < nstds; i++) {
00259 vircam_radectoxieta(wcs,ra[i],dec[i],&xi,&eta);
00260 xiptr[i] = xi;
00261 etaptr[i] = eta;
00262 }
00263
00264
00265
00266
00267 niter = 0;
00268 while (niter >= 0) {
00269
00270
00271
00272 switch (nconst) {
00273 case 6:
00274 *status = vircam_plate6(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
00275 &c,&e,&d,&f);
00276 break;
00277 case 4:
00278 *status = vircam_plate4(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
00279 &c,&e,&d,&f);
00280 break;
00281 default:
00282 *status = vircam_plate6(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
00283 &c,&e,&d,&f);
00284 break;
00285 }
00286 if (*status != VIR_OK) {
00287 cpl_msg_error(fctid,"Plate constant solution failed");
00288 tidy();
00289 FATAL_ERROR
00290 }
00291
00292
00293
00294 for (i = 0; i < nstds; i++) {
00295 xifit = xptr[i]*a + yptr[i]*b + c;
00296 etafit = xptr[i]*d + yptr[i]*e + f;
00297 dxi = fabs(xifit - xiptr[i]);
00298 deta = fabs(etafit - etaptr[i]);
00299 wptr[i*2] = dxi;
00300 wptr[i*2+1] = deta;
00301 wptr2[i*2] = isbad[i];
00302 wptr2[i*2+1] = isbad[i];
00303 }
00304 averr = vircam_dmed(wptr,wptr2,2*nstds);
00305 averr *= 1.48;
00306 if (niter == 3)
00307 break;
00308 nrej = 0;
00309 ngood = 0;
00310 for (i = 0; i < nstds; i++) {
00311 if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) nrej++;
00312 if (!isbad[i])
00313 ngood++;
00314 }
00315 ngood -= nrej;
00316 if (nrej == 0 || ngood < nconst)
00317 break;
00318 for (i = 0; i < nstds; i++) {
00319 if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) isbad[i] = 1;
00320 }
00321 niter++;
00322 }
00323
00324
00325
00326 crpix1 = (e*c - b*f)/(d*b - e*a);
00327 crpix2 = (a*f - d*c)/(d*b - e*a);
00328 a *= DEGRAD;
00329 b *= DEGRAD;
00330 d *= DEGRAD;
00331 e *= DEGRAD;
00332
00333
00334
00335 ngood = 0;
00336 for (i = 0; i < nstds; i++)
00337 if (! isbad[i])
00338 ngood++;
00339 averr *= DEGRAD*3600.0;
00340
00341
00342
00343 cpl_propertylist_update_double(plist,"CRPIX1",crpix1);
00344 cpl_propertylist_update_double(plist,"CRPIX2",crpix2);
00345 cpl_propertylist_update_double(plist,"CD1_1",a);
00346 cpl_propertylist_update_double(plist,"CD1_2",b);
00347 cpl_propertylist_update_double(plist,"CD2_1",d);
00348 cpl_propertylist_update_double(plist,"CD2_2",e);
00349 cpl_propertylist_update_int(plist,"ESO DRS NUMBRMS",ngood);
00350 cpl_propertylist_set_comment(plist,"ESO DRS NUMBRMS",
00351 "Number of stars in WCS fit");
00352 cpl_propertylist_update_float(plist,"ESO DRS STDCRMS",(float)averr);
00353 cpl_propertylist_set_comment(plist,"ESO DRS STDCRMS",
00354 "[arcsec] Average error in WCS fit");
00355
00356
00357
00358 crm = cpl_wcs_get_cd(wcs);
00359 crdata = cpl_matrix_get_data(crm);
00360 oldtheta = 0.5*(fabs(atan2(crdata[1],crdata[0])) +
00361 fabs(atan2(crdata[2],crdata[3])));
00362 cpl_wcs_delete(wcs);
00363 wcs = cpl_wcs_new_from_propertylist(plist);
00364 vircam_xytoradec(wcs,xcen,ycen,&rac_after,&decc_after);
00365 xcen = 3600.0*(rac_after - rac_before);
00366 ycen = 3600.0*(decc_after - decc_before);
00367 cpl_propertylist_update_float(plist,"ESO DRS WCSRAOFF",(float)xcen);
00368 cpl_propertylist_set_comment(plist,"ESO DRS WCSRAOFF",
00369 "[arcsec] cenpix RA_after - RA_before)");
00370 cpl_propertylist_update_float(plist,"ESO DRS WCSDECOFF",(float)ycen);
00371 cpl_propertylist_set_comment(plist,"ESO DRS WCSDECOFF",
00372 "[arcsec] cenpix Dec_after - Dec_before)");
00373
00374
00375
00376 if (tlist != NULL) {
00377 xcol = vircam_findcol(tlist,"X");
00378 ycol = vircam_findcol(tlist,"Y");
00379 if (xcol != -1 && ycol != -1) {
00380 snprintf(key,9,"TCRPX%d",xcol);
00381 cpl_propertylist_update_double(tlist,key,crpix1);
00382 snprintf(key,9,"TCRPX%d",ycol);
00383 cpl_propertylist_update_double(tlist,key,crpix2);
00384 snprintf(key,9,"TC%d_%d",xcol,xcol);
00385 cpl_propertylist_update_double(tlist,key,a);
00386 snprintf(key,9,"TC%d_%d",xcol,ycol);
00387 cpl_propertylist_update_double(tlist,key,b);
00388 snprintf(key,9,"TC%d_%d",ycol,xcol);
00389 cpl_propertylist_update_double(tlist,key,d);
00390 snprintf(key,9,"TC%d_%d",ycol,ycol);
00391 cpl_propertylist_update_double(tlist,key,e);
00392 cpl_propertylist_update_int(tlist,"ESO DRS NUMBRMS",ngood);
00393 cpl_propertylist_set_comment(tlist,"ESO DRS NUMBRMS",
00394 "Number of stars in WCS fit");
00395 cpl_propertylist_update_float(tlist,"ESO DRS STDCRMS",(float)averr);
00396 cpl_propertylist_set_comment(tlist,"ESO DRS STDCRMS",
00397 "[arcsec] Average error in WCS fit");
00398 cpl_propertylist_update_float(tlist,"ESO DRS WCSRAOFF",(float)xcen);
00399 cpl_propertylist_set_comment(tlist,"ESO DRS WCSRAOFF",
00400 "[arcsec] cenpix RA_after - RA_before)");
00401 cpl_propertylist_update_float(tlist,"ESO DRS WCSDECOFF",(float)ycen);
00402 cpl_propertylist_set_comment(tlist,"ESO DRS WCSDECOFF",
00403 "[arcsec] cenpix Dec_after - Dec_before)");
00404 }
00405 }
00406
00407
00408
00409
00410 cr = cpl_wcs_get_crval(wcs);
00411 crdata = cpl_array_get_data_double(cr);
00412 vircam_xytoradec(wcs,oldcrpix1,oldcrpix2,&rac_after,&decc_after);
00413 rac_after -= crdata[0];
00414 decc_after -= crdata[1];
00415 cpl_propertylist_update_float(plist,"ESO QC WCS_DCRVAL1",(float)rac_after);
00416 cpl_propertylist_set_comment(plist,"ESO QC WCS_DCRVAL1",
00417 "[deg] change in crval1");
00418 cpl_propertylist_update_float(plist,"ESO QC WCS_DCRVAL2",(float)decc_after);
00419 cpl_propertylist_set_comment(plist,"ESO QC WCS_DCRVAL2",
00420 "[deg] change in crval2");
00421
00422
00423
00424 crm = cpl_wcs_get_cd(wcs);
00425 crdata = cpl_matrix_get_data(crm);
00426 oldtheta = 0.5*(fabs(atan2(crdata[1],crdata[0])) +
00427 fabs(atan2(crdata[2],crdata[3]))) - oldtheta;
00428 oldtheta *= DEGRAD;
00429 cpl_propertylist_update_float(plist,"ESO QC WCS_DTHETA",(float)oldtheta);
00430 cpl_propertylist_set_comment(plist,"ESO QC WCS_DTHETA",
00431 "[deg] change in rotation");
00432
00433
00434
00435 scale = 1800.0*(sqrt(pow(crdata[0],2.0) + pow(crdata[1],2.0)) +
00436 sqrt(pow(crdata[2],2.0) + pow(crdata[3],2.0)));
00437 cpl_propertylist_update_float(plist,"ESO QC WCS_SCALE",(float)scale);
00438 cpl_propertylist_set_comment(plist,"ESO QC WCS_SCALE",
00439 "[arcsec] mean plate scale");
00440
00441
00442
00443 oldtheta = fabs(atan2(crdata[1],crdata[0])) -
00444 fabs(atan2(crdata[2],crdata[3]));
00445 cpl_propertylist_update_float(plist,"ESO QC WCS_SHEAR",(float)oldtheta);
00446 cpl_propertylist_set_comment(plist,"ESO QC WCS_SHEAR",
00447 "[deg] abs(xrot) - abs(yrot)");
00448
00449
00450
00451 cpl_propertylist_update_float(plist,"ESO QC WCS_RMS",(float)averr);
00452 cpl_propertylist_set_comment(plist,"ESO QC WCS_RMS",
00453 "[arcsec] Average error in WCS fit");
00454
00455
00456
00457 cpl_wcs_delete(wcs);
00458 tidy();
00459 GOOD_STATUS
00460 }
00461
00462
00496
00497
00498 static int vircam_plate6(double *xpos, double *ypos, double *xi, double *eta,
00499 unsigned char *flag, int nstds, double *a, double *b,
00500 double *c, double *d, double *e, double *f) {
00501 double sx1sq,sy1sq,sx1y1,sx1x2,sy1x2;
00502 double sy1y2,sx1y2,xposmean,yposmean,ximean,etamean,xx1,yy1,xx2,yy2;
00503 int i,ngood,nbad;
00504
00505
00506
00507 (void)vircam_sumbpm(flag,nstds,&nbad);
00508 ngood = nstds - nbad;
00509 if (ngood < 2)
00510 return(VIR_FATAL);
00511
00512
00513
00514 sx1sq = 0.0;
00515 sy1sq = 0.0;
00516 sx1y1 = 0.0;
00517 sx1x2 = 0.0;
00518 sy1x2 = 0.0;
00519 sy1y2 = 0.0;
00520 sx1y2 = 0.0;
00521 xposmean = 0.0;
00522 yposmean = 0.0;
00523 ximean = 0.0;
00524 etamean = 0.0;
00525
00526
00527
00528 xposmean = vircam_dmean(xpos,flag,nstds);
00529 yposmean = vircam_dmean(ypos,flag,nstds);
00530 ximean = vircam_dmean(xi,flag,nstds);
00531 etamean = vircam_dmean(eta,flag,nstds);
00532
00533
00534
00535 for (i = 0; i < nstds; i++) {
00536 if (!flag[i]) {
00537 xx1 = xpos[i] - xposmean;
00538 yy1 = ypos[i] - yposmean;
00539 xx2 = xi[i] - ximean;
00540 yy2 = eta[i] - etamean;
00541 sx1sq += xx1*xx1;
00542 sy1sq += yy1*yy1;
00543 sx1y1 += xx1*yy1;
00544 sx1x2 += xx1*xx2;
00545 sy1x2 += yy1*xx2;
00546 sy1y2 += yy1*yy2;
00547 sx1y2 += xx1*yy2;
00548 }
00549 }
00550
00551
00552
00553 *a = (sx1y1*sy1x2 - sx1x2*sy1sq)/(sx1y1*sx1y1 - sx1sq*sy1sq);
00554 *b = (sx1x2*sx1y1 - sx1sq*sy1x2)/(sx1y1*sx1y1 - sx1sq*sy1sq);
00555 *c = -xposmean*(*a) - yposmean*(*b) + ximean;
00556
00557
00558
00559 *d = (sx1y1*sx1y2 - sy1y2*sx1sq)/(sx1y1*sx1y1 - sy1sq*sx1sq);
00560 *e = (sy1y2*sx1y1 - sy1sq*sx1y2)/(sx1y1*sx1y1 - sy1sq*sx1sq);
00561 *f = -xposmean*(*e) - yposmean*(*d) + etamean;
00562
00563
00564
00565 return(VIR_OK);
00566 }
00567
00568
00602
00603
00604 static int vircam_plate4(double *xpos, double *ypos, double *xi, double *eta,
00605 unsigned char *flag, int nstds, double *a, double *b,
00606 double *c, double *d, double *e, double *f) {
00607 double sx1sq,sy1sq,sx1x2,sy1x2,sy1y2,sx1y2,xposmean,yposmean;
00608 double ximean,etamean,xx1,yy1,xx2,yy2,det,num,denom,theta,mag;
00609 double stheta,ctheta;
00610 int i,ngood,nbad;
00611
00612
00613
00614 (void)vircam_sumbpm(flag,nstds,&nbad);
00615 ngood = nstds - nbad;
00616 if (ngood < 2)
00617 return(VIR_FATAL);
00618
00619
00620
00621 sx1sq = 0.0;
00622 sy1sq = 0.0;
00623 sx1x2 = 0.0;
00624 sy1x2 = 0.0;
00625 sy1y2 = 0.0;
00626 sx1y2 = 0.0;
00627 xposmean = 0.0;
00628 yposmean = 0.0;
00629 ximean = 0.0;
00630 etamean = 0.0;
00631
00632
00633
00634 xposmean = vircam_dmean(xpos,flag,nstds);
00635 yposmean = vircam_dmean(ypos,flag,nstds);
00636 ximean = vircam_dmean(xi,flag,nstds);
00637 etamean = vircam_dmean(eta,flag,nstds);
00638
00639
00640
00641 for (i = 0; i < nstds; i++) {
00642 if (!flag[i]) {
00643 xx1 = xpos[i] - xposmean;
00644 yy1 = ypos[i] - yposmean;
00645 xx2 = xi[i] - ximean;
00646 yy2 = eta[i] - etamean;
00647 sx1sq += xx1*xx1;
00648 sy1sq += yy1*yy1;
00649 sx1x2 += xx1*xx2;
00650 sy1x2 += yy1*xx2;
00651 sy1y2 += yy1*yy2;
00652 sx1y2 += xx1*yy2;
00653 }
00654 }
00655
00656
00657
00658 det = sx1x2*sy1y2 - sy1x2*sx1y2;
00659 if (det < 0.0) {
00660 num = sy1x2 + sx1y2;
00661 denom = -sx1x2 + sy1y2;
00662 } else {
00663 num = sy1x2 - sx1y2;
00664 denom = sx1x2 + sy1y2;
00665 }
00666 if (num == 0.0 && denom == 0.0) {
00667 theta = 0.0;
00668 } else {
00669 theta = atan2(num,denom);
00670 if (theta < 0.0)
00671 theta += M_TWOPI;
00672 }
00673
00674
00675
00676 ctheta = cos(theta);
00677 stheta = sin(theta);
00678 num = denom*ctheta + num*stheta;
00679 denom = sx1sq + sy1sq;
00680 if (denom <= 0.0) {
00681 mag = 1.0;
00682 } else {
00683 mag = num/denom;
00684 }
00685
00686
00687
00688 if (det < 0.0) {
00689 *a = -mag*ctheta;
00690 *e = mag*stheta;
00691 } else {
00692 *a = mag*ctheta;
00693 *e = -mag*stheta;
00694 }
00695 *b = mag*stheta;
00696 *d = mag*ctheta;
00697 *c = -xposmean*(*a) - yposmean*(*b) + ximean;
00698 *f = -xposmean*(*e) - yposmean*(*d) + etamean;
00699
00700
00701
00702 return(VIR_OK);
00703 }
00704
00705 static void tidy(void) {
00706
00707 freespace(work);
00708 freespace(iwork);
00709 }
00710
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785