VIRCAM Pipeline  1.3.3
vircam_match.c
1 /* $Id: vircam_match.c,v 1.23 2012-01-15 17:40:09 jim Exp $
2  *
3  * This file is part of the VIRCAM Pipeline
4  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jim $
23  * $Date: 2012-01-15 17:40:09 $
24  * $Revision: 1.23 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 /* Includes */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <math.h>
35 
36 #include <cpl.h>
37 #include <string.h>
38 
39 #include "vircam_mods.h"
40 #include "vircam_stats.h"
41 #include "vircam_utils.h"
42 
43 #define NX 2048
44 #define NY 2048
45 #define NGRIDMAX_XY 61
46 #define NGRIDMAX_STD 31
47 
48 static cpl_table *vircam_mkmstd_table(cpl_table *objtab, cpl_table *stdstab);
49 
52 /*---------------------------------------------------------------------------*/
102 /*---------------------------------------------------------------------------*/
103 
104 extern int vircam_matchxy(cpl_table *progtab, cpl_table *template, float srad,
105  float *xoffset, float *yoffset, int *nm,
106  cpl_table **outtab, int *status) {
107  cpl_propertylist *p;
108  float *xprog,*yprog,*xtemp,*ytemp,aveden,errlim,xoffbest,yoffbest,xoff;
109  float yoff,x,y,*xoffs,*yoffs;
110  const char *fctid = "vircam_matchxy";
111  int nprog,ntemp,ngrid,ngrid2,ibest,ig,jg,nmatch,k,jm;
112 
113  /* Inherited status */
114 
115  *xoffset = 0.0;
116  *yoffset = 0.0;
117  *nm = 0;
118  *outtab = NULL;
119  if (*status != VIR_OK)
120  return(*status);
121 
122  /* Check the size of each of the tables */
123 
124  nprog = (int)cpl_table_get_nrow(progtab);
125  ntemp = (int)cpl_table_get_nrow(template);
126  if (nprog == 0) {
127  cpl_msg_warning(fctid,"Program table has no rows");
128  WARN_RETURN
129  } else if (ntemp == 0) {
130  cpl_msg_warning(fctid,"Template table has no rows");
131  WARN_RETURN
132  }
133 
134  /* First, sort the two tables by the Y coordinate */
135 
136  p = cpl_propertylist_new();
137  cpl_propertylist_append_bool(p,"Y_coordinate",0);
138  if (cpl_table_sort(progtab,p) != CPL_ERROR_NONE) {
139  cpl_propertylist_delete(p);
140  FATAL_ERROR
141  }
142  if (cpl_table_sort(template,p) != CPL_ERROR_NONE) {
143  cpl_propertylist_delete(p);
144  FATAL_ERROR
145  }
146  cpl_propertylist_delete(p);
147 
148  /* Get the x,y coordinates for each table */
149 
150  xprog = cpl_table_get_data_float(progtab,"X_coordinate");
151  yprog = cpl_table_get_data_float(progtab,"Y_coordinate");
152  xtemp = cpl_table_get_data_float(template,"X_coordinate");
153  ytemp = cpl_table_get_data_float(template,"Y_coordinate");
154  if (xprog == NULL || yprog == NULL || xtemp == NULL || ytemp == NULL)
155  FATAL_ERROR
156 
157  /* Calculate the error limit and the number of grid points */
158 
159  aveden = (float)ntemp/(float)(NX*NY);
160  errlim = 1.0/sqrt(4.0*CPL_MATH_PI*aveden);
161  errlim = min(errlim,15.0);
162  ngrid = (int)(srad/errlim);
163  ngrid = (ngrid/2)*2 + 1;
164  ngrid = max(5,min(NGRIDMAX_XY,ngrid));
165  ngrid2 = ngrid/2 + 1;
166 
167  /* Now search for the best solution */
168 
169  ibest = 0;
170  xoffbest = 0.0;
171  yoffbest = 0.0;
172  for (ig = -ngrid2; ig <= ngrid2; ig++) {
173  xoff = (float)ig*errlim*CPL_MATH_SQRT2;
174  for (jg = -ngrid2; jg <= ngrid2; jg++) {
175  yoff = (float)jg*errlim*CPL_MATH_SQRT2;
176  nmatch = 0;
177  for (k = 0; k < nprog; k++) {
178  x = xprog[k] + xoff;
179  y = yprog[k] + yoff;
180  if (vircam_fndmatch(x,y,xtemp,ytemp,ntemp,errlim) > -1)
181  nmatch++;
182  }
183  if (nmatch > ibest) {
184  ibest = nmatch;
185  xoffbest = xoff;
186  yoffbest = yoff;
187  }
188  }
189  }
190 
191  /* Now allocate some workspace so that you can calculate a good median
192  coordinate difference */
193 
194  xoffs = cpl_malloc(nprog*sizeof(*xoffs));
195  yoffs = cpl_malloc(nprog*sizeof(*yoffs));
196 
197  /* Now get the coordinate differences and find the medians */
198 
199  nmatch = 0;
200  for (k = 0; k < nprog; k++) {
201  x = xprog[k] + xoffbest;
202  y = yprog[k] + yoffbest;
203  jm = vircam_fndmatch(x,y,xtemp,ytemp,ntemp,errlim);
204  if (jm > -1) {
205  xoffs[nmatch] = xtemp[jm] - xprog[k];
206  yoffs[nmatch] = ytemp[jm] - yprog[k];
207  nmatch++;
208  }
209  }
210  if (nmatch > 0) {
211  *xoffset = vircam_med(xoffs,NULL,nmatch);
212  *yoffset = vircam_med(yoffs,NULL,nmatch);
213  } else {
214  *xoffset = 0.0;
215  *yoffset = 0.0;
216  }
217  *nm = nmatch;
218 
219  /* Create the output table */
220 
221  *outtab = cpl_table_new((cpl_size)nprog);
222  cpl_table_new_column(*outtab,"X_coordinate_1",CPL_TYPE_FLOAT);
223  cpl_table_new_column(*outtab,"Y_coordinate_1",CPL_TYPE_FLOAT);
224  cpl_table_new_column(*outtab,"X_coordinate_2",CPL_TYPE_FLOAT);
225  cpl_table_new_column(*outtab,"Y_coordinate_2",CPL_TYPE_FLOAT);
226  nmatch = 0;
227  for (k = 0; k < nprog; k++) {
228  x = xprog[k] + *xoffset;
229  y = yprog[k] + *yoffset;
230  jm = vircam_fndmatch(x,y,xtemp,ytemp,ntemp,1.0);
231  if (jm > -1) {
232  cpl_table_set_float(*outtab,"X_coordinate_1",(cpl_size)nmatch,
233  xtemp[jm]);
234  cpl_table_set_float(*outtab,"Y_coordinate_1",(cpl_size)nmatch,
235  ytemp[jm]);
236  cpl_table_set_float(*outtab,"X_coordinate_2",(cpl_size)nmatch,
237  xprog[k]);
238  cpl_table_set_float(*outtab,"Y_coordinate_2",(cpl_size)nmatch,
239  yprog[k]);
240  nmatch++;
241  }
242  }
243  cpl_table_set_size(*outtab,(cpl_size)nmatch);
244 
245  /* Tidy and exit */
246 
247  freespace(xoffs);
248  freespace(yoffs);
249  GOOD_STATUS
250 }
251 
252 /*---------------------------------------------------------------------------*/
297 /*---------------------------------------------------------------------------*/
298 
299 extern int vircam_matchstds(cpl_table *objtab, cpl_table *stdstab, float srad,
300  cpl_table **outtab, int *status) {
301  const char *fctid = "vircam_matchstds";
302  char *colname;
303  int nobj,nstd,ngrid,ngrid2,ibest,ig,jg,nmatch,k,*matches,jm,l,dont,null;
304  float *xstd,*ystd,*xobj,*yobj,aveden,errlim,xoffbest,yoffbest,*xoffs;
305  float *yoffs,x,y,xx2,yy2,r2,xx1,yy1,r1,xoffmed,sigx,yoffmed,sigy,xoff,yoff;
306  cpl_propertylist *p;
307  cpl_table *mstds;
308 
309  /* Inherited status */
310 
311  *outtab = NULL;
312  if (*status != VIR_OK)
313  return(*status);
314 
315  /* Check the size of each of the tables */
316 
317  nobj = (int)cpl_table_get_nrow(objtab);
318  nstd = (int)cpl_table_get_nrow(stdstab);
319  if (nobj == 0) {
320  cpl_msg_warning(fctid,"Object table has no rows");
321  mstds = vircam_mkmstd_table(objtab,stdstab);
322  *outtab = cpl_table_extract_selected(mstds);
323  cpl_table_delete(mstds);
324  WARN_RETURN
325  } else if (nstd == 0) {
326  cpl_msg_warning(fctid,"Standards RA/DEC table has no rows");
327  mstds = vircam_mkmstd_table(objtab,stdstab);
328  *outtab = cpl_table_extract_selected(mstds);
329  cpl_table_delete(mstds);
330  WARN_RETURN
331  }
332 
333  /* First, sort the two tables by the Y coordinate */
334 
335  p = cpl_propertylist_new();
336  cpl_propertylist_append_bool(p,"Y_coordinate",0);
337  if (cpl_table_sort(objtab,p) != CPL_ERROR_NONE) {
338  cpl_propertylist_delete(p);
339  FATAL_ERROR
340  }
341  cpl_propertylist_erase(p,"Y_coordinate");
342  cpl_propertylist_append_bool(p,"ypredict",0);
343  if (cpl_table_sort(stdstab,p) != CPL_ERROR_NONE) {
344  cpl_propertylist_delete(p);
345  FATAL_ERROR
346  }
347  cpl_propertylist_delete(p);
348 
349  /* Get the x,y coordinates for each table */
350 
351  xobj = cpl_table_get_data_float(objtab,"X_coordinate");
352  yobj = cpl_table_get_data_float(objtab,"Y_coordinate");
353  xstd = cpl_table_get_data_float(stdstab,"xpredict");
354  ystd = cpl_table_get_data_float(stdstab,"ypredict");
355  if (xstd == NULL || ystd == NULL || xobj == NULL || yobj == NULL)
356  FATAL_ERROR
357 
358  /* Calculate the error limit and the number of grid points */
359 
360  aveden = (float)max(nstd,nobj)/(float)(NX*NY);
361  errlim = 1.0/sqrt(4.0*CPL_MATH_PI*aveden);
362  errlim = min(errlim,15.0);
363  ngrid = (int)(srad/errlim);
364  ngrid = (ngrid/2)*2 + 1;
365  ngrid = max(5,min(NGRIDMAX_STD,ngrid));
366  ngrid2 = ngrid/2 + 1;
367 
368  /* Now search for the best solution */
369 
370  ibest = 0;
371  xoffbest = 0.0;
372  yoffbest = 0.0;
373  for (ig = -ngrid2; ig <= ngrid2; ig++) {
374  xoff = (float)ig*errlim*CPL_MATH_SQRT2;
375  for (jg = -ngrid2; jg <= ngrid2; jg++) {
376  yoff = (float)jg*errlim*CPL_MATH_SQRT2;
377  nmatch = 0;
378  for (k = 0; k < nobj; k++) {
379  x = xobj[k] + xoff;
380  y = yobj[k] + yoff;
381  if (vircam_fndmatch(x,y,xstd,ystd,nstd,errlim) > -1)
382  nmatch++;
383  }
384  if (nmatch > ibest) {
385  ibest = nmatch;
386  xoffbest = xoff;
387  yoffbest = yoff;
388  }
389  }
390  }
391 
392  /* Now allocate some workspace so that you can calculate a good median
393  coordinate difference */
394 
395  xoffs = cpl_malloc(nstd*sizeof(*xoffs));
396  yoffs = cpl_malloc(nstd*sizeof(*yoffs));
397  matches = cpl_malloc(nstd*sizeof(*matches));
398  for (k = 0; k < nstd; k++)
399  matches[k] = -1;
400 
401  /* Now get the best matches */
402 
403  nmatch = 0;
404  for (k = 0; k < nstd; k++) {
405  x = xstd[k] - xoffbest;
406  y = ystd[k] - yoffbest;
407  jm = vircam_fndmatch(x,y,xobj,yobj,nobj,errlim);
408  if (jm > -1) {
409  dont = 0;
410  xx2 = xobj[jm] - x;
411  yy2 = yobj[jm] - y;
412  r2 = sqrt(xx2*xx2 + yy2*yy2);
413  for (l = 0; l < nstd; l++) {
414  if (matches[l] == jm) {
415  xx1 = xobj[jm] - (xstd[l] - xoffbest);
416  yy1 = yobj[jm] - (ystd[l] - yoffbest);
417  r1 = sqrt(xx1*xx1 + yy1*yy1);
418  if (r2 < r1)
419  matches[l] = -1;
420  else
421  dont = 1;
422  break;
423  }
424  }
425  if (dont == 0)
426  matches[k] = jm;
427  }
428  }
429 
430  /* Now get the coordinate difference for the best matches */
431 
432  for (k = 0; k < nstd; k++) {
433  jm = matches[k];
434  if (jm != -1) {
435  xoffs[nmatch] = xobj[jm] - xstd[k];
436  yoffs[nmatch] = yobj[jm] - ystd[k];
437  nmatch++;
438  }
439  }
440  if (nmatch == 0) {
441  xoffmed = 0.0;
442  sigx = 1.0;
443  yoffmed = 0.0;
444  sigy = 1.0;
445  } else {
446  vircam_medmad(xoffs,NULL,nmatch,&xoffmed,&sigx);
447  sigx *= 1.48;
448  vircam_medmad(yoffs,NULL,nmatch,&yoffmed,&sigy);
449  sigy *= 1.48;
450  }
451 
452  /* Now go through one final time with a reduced error box and get
453  the final matches */
454 
455  errlim = 3.0*max(sigx,sigy);
456  for (k = 0; k < nstd; k++)
457  matches[k] = -1;
458  for (k = 0; k < nstd; k++) {
459  x = xstd[k] + xoffmed;
460  y = ystd[k] + yoffmed;
461  jm = vircam_fndmatch(x,y,xobj,yobj,nobj,errlim);
462  if (jm > -1) {
463  dont = 0;
464  xx2 = xobj[jm] - x;
465  yy2 = yobj[jm] - y;
466  r2 = sqrt(xx2*xx2 + yy2*yy2);
467  for (l = 0; l < nstd; l++) {
468  if (matches[l] == jm) {
469  xx1 = xobj[jm] - (xstd[l] + xoffmed);
470  yy1 = yobj[jm] - (ystd[l] + yoffmed);
471  r1 = sqrt(xx1*xx1 + yy1*yy1);
472  if (r2 < r1)
473  matches[l] = -1;
474  else
475  dont = 1;
476 /* break; */
477  }
478  }
479  if (dont == 0)
480  matches[k] = jm;
481  }
482  }
483  jm = matches[1];
484 
485  /* Make a copy of the standards table and add all the columns from the
486  object catalogue to it. Ingore the RA and DEC columns in the catalogue
487  as the standards table will already have these.*/
488 
489  mstds = cpl_table_duplicate(stdstab);
490  colname = (char *)cpl_table_get_column_name(objtab);
491  while (colname != NULL) {
492  if (strcmp(colname,"RA") && strcmp(colname,"DEC"))
493  cpl_table_new_column(mstds,colname,
494  cpl_table_get_column_type(objtab,colname));
495  colname = (char *)cpl_table_get_column_name(NULL);
496  }
497  cpl_table_unselect_all(mstds);
498 
499  /* Now go through and find the matches */
500 
501  for (k = 0; k < nstd; k++) {
502  jm = matches[k];
503  if (jm != -1) {
504  colname = (char *)cpl_table_get_column_name(objtab);
505  while (colname != NULL) {
506  if (!strcmp(colname,"RA") || !strcmp(colname,"DEC")) {
507  colname = (char *)cpl_table_get_column_name(NULL);
508  continue;
509  }
510  null = 0;
511  switch (cpl_table_get_column_type(objtab,colname)) {
512  case CPL_TYPE_INT:
513  cpl_table_set_int(mstds,colname,(cpl_size)k,
514  cpl_table_get_int(objtab,colname,
515  (cpl_size)jm,&null));
516  break;
517  case CPL_TYPE_FLOAT:
518  cpl_table_set_float(mstds,colname,(cpl_size)k,
519  cpl_table_get_float(objtab,colname,
520  (cpl_size)jm,&null));
521  break;
522  case CPL_TYPE_DOUBLE:
523  cpl_table_set_double(mstds,colname,(cpl_size)k,
524  cpl_table_get_double(objtab,colname,
525  (cpl_size)jm,&null));
526  break;
527  default:
528  cpl_table_set_float(mstds,colname,(cpl_size)k,
529  cpl_table_get_float(objtab,colname,
530  (cpl_size)jm,&null));
531  break;
532  }
533  colname = (char *)cpl_table_get_column_name(NULL);
534  }
535  cpl_table_select_row(mstds,(cpl_size)k);
536  }
537  }
538 
539  /* Now extract the selected rows into the output table */
540 
541  *outtab = cpl_table_extract_selected(mstds);
542  cpl_table_delete(mstds);
543 
544  /* Tidy up */
545 
546  freespace(matches);
547  freespace(xoffs);
548  freespace(yoffs);
549  GOOD_STATUS
550 }
551 
552 extern int vircam_tpoffset(cpl_table *progtab, cpl_table *template,
553  const cpl_wcs *progwcs, const cpl_wcs *tempwcs,
554  float srad, double *xoffset, double *yoffset,
555  int *nm, float *xoff_pix, float *yoff_pix,
556  int *status) {
557  int nprog,ntemp,nmatch,k,jm;
558  const char *fctid = "vircam_tpoffset";
559  float *xprog,*yprog,*xtemp,*ytemp,x,y,xoff,yoff;
560  double *xoffs,*yoffs;
561  cpl_matrix *in,*outt,*outp;
562  cpl_array *st;
563  cpl_table *outxy;
564 
565  /* Inherited status */
566 
567  *xoffset = 0.0;
568  *yoffset = 0.0;
569  *xoff_pix = 0.0;
570  *yoff_pix = 0.0;
571  *nm = 0;
572  if (*status != VIR_OK)
573  return(*status);
574 
575  /* Get a good xy match first */
576 
577  (void)vircam_matchxy(progtab,template,srad,&xoff,&yoff,&nmatch,&outxy,
578  status);
579  freetable(outxy);
580  if (*status != VIR_OK) {
581  cpl_msg_warning(fctid,"Error getting xy offset");
582  FATAL_ERROR
583  }
584  *xoff_pix = xoff;
585  *yoff_pix = yoff;
586 
587  /* Get some info. NB we don't check any of these as they will have
588  already been checked in vircam_matchxy */
589 
590  nprog = (int)cpl_table_get_nrow(progtab);
591  ntemp = (int)cpl_table_get_nrow(template);
592  xprog = cpl_table_get_data_float(progtab,"X_coordinate");
593  yprog = cpl_table_get_data_float(progtab,"Y_coordinate");
594  xtemp = cpl_table_get_data_float(template,"X_coordinate");
595  ytemp = cpl_table_get_data_float(template,"Y_coordinate");
596 
597  /* Now allocate some workspace so that you can calculate a good median
598  coordinate difference */
599 
600  xoffs = cpl_malloc(nprog*sizeof(*xoffs));
601  yoffs = cpl_malloc(nprog*sizeof(*yoffs));
602  in = cpl_matrix_new(1,2);
603 
604  /* Now get the coordinate differences and find the medians */
605 
606  nmatch = 0;
607  for (k = 0; k < nprog; k++) {
608  x = xprog[k] + xoff;
609  y = yprog[k] + yoff;
610  jm = vircam_fndmatch(x,y,xtemp,ytemp,ntemp,0.5);
611  if (jm > -1) {
612  cpl_matrix_set(in,0,0,(double)xtemp[jm]);
613  cpl_matrix_set(in,0,1,(double)ytemp[jm]);
614  cpl_wcs_convert(tempwcs,in,&outt,&st,CPL_WCS_PHYS2WORLD);
615  cpl_array_delete(st);
616  cpl_matrix_set(in,0,0,(double)xprog[k]);
617  cpl_matrix_set(in,0,1,(double)yprog[k]);
618  cpl_wcs_convert(progwcs,in,&outp,&st,CPL_WCS_PHYS2WORLD);
619  cpl_array_delete(st);
620  xoffs[nmatch] = cpl_matrix_get(outt,0,0) - cpl_matrix_get(outp,0,0);
621  yoffs[nmatch] = cpl_matrix_get(outt,0,1) - cpl_matrix_get(outp,0,1);
622  nmatch++;
623  cpl_matrix_delete(outt);
624  cpl_matrix_delete(outp);
625  }
626  }
627  if (nmatch > 0) {
628  *xoffset = vircam_dmed(xoffs,NULL,nmatch);
629  *yoffset = vircam_dmed(yoffs,NULL,nmatch);
630  } else {
631  *xoffset = 0.0;
632  *yoffset = 0.0;
633  }
634  *nm = nmatch;
635 
636  /* Tidy and exit */
637 
638  cpl_matrix_delete(in);
639  freespace(xoffs);
640  freespace(yoffs);
641  return(VIR_OK);
642 }
643 
644 /*---------------------------------------------------------------------------*/
664 /*---------------------------------------------------------------------------*/
665 
666 static cpl_table *vircam_mkmstd_table(cpl_table *objtab, cpl_table *stdstab) {
667  cpl_table *mstds;
668  char *colname;
669 
670  /* Copy the input standards table */
671 
672  mstds = cpl_table_duplicate(stdstab);
673 
674  /* Loop throught the object table columns and copy all of them over,
675  except for the RA and DEC tables */
676 
677  colname = (char *)cpl_table_get_column_name(objtab);
678  while (colname != NULL) {
679  if (strcmp(colname,"RA") && strcmp(colname,"DEC"))
680  cpl_table_new_column(mstds,colname,
681  cpl_table_get_column_type(objtab,colname));
682  colname = (char *)cpl_table_get_column_name(NULL);
683  }
684  cpl_table_unselect_all(mstds);
685 
686  /* Get out of here */
687 
688  return(mstds);
689 }
690 
694 /*
695 
696 $Log: not supported by cvs2svn $
697 Revision 1.22 2010/07/13 11:16:50 jim
698 A few changes to deal with compiler whinges
699 
700 Revision 1.21 2010/06/07 12:42:40 jim
701 Modifications to get rid of compiler gripes
702 
703 Revision 1.20 2009/09/09 09:47:02 jim
704 Uses CPL defined constant macros
705 
706 Revision 1.19 2009/07/03 12:29:24 jim
707 Fixed error limits in matchstds
708 
709 Revision 1.18 2009/02/20 10:55:00 jim
710 Plugged a small memory leak
711 
712 Revision 1.17 2008/11/21 10:10:41 jim
713 Added new output table parameter to vircam_matchxy
714 
715 Revision 1.16 2008/10/24 10:54:41 jim
716 Changed how vircam_tpoffset works out tangent point shift
717 
718 Revision 1.15 2008/10/21 08:40:34 jim
719 Added vircam_tpoffset
720 
721 Revision 1.14 2008/08/05 14:07:01 jim
722 Relaxed matching criteria
723 
724 Revision 1.13 2007/10/19 09:25:10 jim
725 Fixed problems with missing includes
726 
727 Revision 1.12 2007/04/23 13:02:02 jim
728 Added static routine to make the matched standards table
729 
730 Revision 1.11 2007/03/29 12:19:39 jim
731 Little changes to improve documentation
732 
733 Revision 1.10 2007/03/01 12:42:42 jim
734 Modified slightly after code checking
735 
736 Revision 1.9 2007/02/25 06:34:20 jim
737 Plugged memory leak
738 
739 Revision 1.8 2006/07/03 09:33:18 jim
740 Fixed a few things to keep the compiler happy
741 
742 Revision 1.7 2006/05/26 15:04:07 jim
743 Fixed sign error
744 
745 Revision 1.6 2006/05/18 12:33:38 jim
746 Fixed bugs in the definition of the matched standard catalogue
747 
748 Revision 1.5 2006/05/17 12:06:56 jim
749 Modified to take new definition of matched standards catalogue into account
750 
751 Revision 1.4 2006/03/23 21:18:51 jim
752 Minor changes mainly to comment headers
753 
754 Revision 1.3 2006/03/22 13:58:32 jim
755 Cosmetic fixes to keep lint happy
756 
757 Revision 1.2 2006/02/22 14:10:21 jim
758 Fixed omission in docs
759 
760 Revision 1.1 2006/02/18 11:52:34 jim
761 new file
762 
763 
764 */