/*++++++++++++++ .IDENTIFICATION nomad1.c .LANGUAGE C .AUTHOR Francois Ochsenbein [CDS] .ENVIRONMENT USNO-B1.0 Catalogue .KEYWORDS CDS Catalogue Server .VERSION 1.0 05-Aug-2006: similar to USNO-B1 .VERSION 1.1 17-Feb-2007: Accept Jname .VERSION 1.2 31-Jul-2007: Accept -eb = basic, -ep = position only .VERSION 1.3 08-Dec-2007: alarm .VERSION 1.31 29-Aug-2009: added title .VERSION 1.32 26-Feb-2011: accept -i zone-num, ... (number >= zone) .COMMENTS Access to NOMAD1 catalogue Remember that the environment variable NOMADroot provides the root of NOMAD compressed catalogue; its default is derived from the program name IF the program resides in a .../bin or .../src directory. If everything fails, the absolute default of NOMADroot is /NOMAD. ---------------*/ #define VERSION "1.32" #include /* Structure definitions */ #ifndef ROOTdir #define ROOTdir "/NOMAD" #endif #ifndef TIMEOUT #define TIMEOUT 3600 #endif #define RADIUS (7.5/60.) /* Default target radius */ #ifndef COMPUTE_EpPOS /* 0 by +/- 1 by Matrix 2 by Cartesian */ #define COMPUTE_EpPOS 0 #endif #include #include /* Malloc */ #include /* isatty */ #include #include #include #include #define ITEMS(a) (sizeof(a)/sizeof(a[0])) #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) #define ABS(a) ((a)<0 ? -(a) : a ) #define issign(c) (((c)=='+')||((c)=='-')) #define sind(x) sin((x)*(M_PI/180.)) #define cosd(x) cos((x)*(M_PI/180.)) #define tand(x) tan((x)*(M_PI/180.)) #define asind(x) (180./M_PI)*asin(x) #define atand(x) (180./M_PI)*atan(x) #define atan2d(x,y) (180./M_PI)*atan2(x,y) #define adeg(x) ((x)*3600*1000) /* Degree into mas */ #define NULLmag (-32768) static char *theProg; /* Options for NOMAD queries....... */ int nomad_options = 0 ; /* Linked records, to sort them... */ typedef struct linked_NOMAD { struct linked_NOMAD *lt ; struct linked_NOMAD *eq ; struct linked_NOMAD *gt ; NOMADrec rec ; } LNOMAD ; static int4 compare_calls; static int mrec = 1000; static int irec, truncated ; static int input_id ; /* ID(1) Zone (2) */ static char *prompt[] = { "Center", /* input_id=0 */ "NOMAD-ID", /* input_id=1 */ "Jname", /* input_id=2 */ "RA+Dec Limits", /* input_id=3 */ "NOMAD Zone", /* input_id=4 */ } ; static char whole_nomad ; /* -whole option */ LNOMAD *last, *arec, *root; /* Definitions related to Center of Field */ static double radius = 0 ; static double boxy[2] ; static double localR[3][3] ; /* Matrix, [0] = dir.cos. of center */ static double du2max = -1 ; static char optE; /* Other options */ static int opted = 6 ; /* Default edit Decimal, Epoch, ID */ /* Definitions of the record fields */ struct s_fields { char name[4] ; /* letter */ char flags; /* Peculiarities: */ #define F_RA 1 /* Periodic variable */ #define F_SD 2 /* South polar declnation */ #define F_SHORT 0x20 /* Short field (for null) */ #define F_FLAG 0x80 /* Is a flag (bit set) */ char selected ; short order ; double factor ; int4 lim[2] ; }; static struct s_fields thefields[] = { {"r",0,0,0,3.6e6}, /* MUST BE #0 */ {"i",0,0,0,1.}, /* MUST BE #1 */ {"x",0,0,0,(180./M_PI)*3.6e6}, /* MUST BE #2 */ {"y",0,0,0,(180./M_PI)*3.6e6}, /* MUST BE #3 */ {"a",F_RA,0,0,3.6e6}, /* Must be #4 */ {"d",F_SD,0,0,3.6e6}, /* Must be #5 */ {"p",0,0,0,10.}, /* pmt #6 */ {"e",0,0,0,10.}, /* Mean Epoch */ {"k",F_FLAG,0,0,1., {NOMAD_USEME}}, /* Mag. blue */ {"mb",F_SHORT,0,0,1000.}, /* Mag. blue */ {"mv",F_SHORT,0,0,1000.}, /* Mag. visible */ {"mr",F_SHORT,0,0,1000.}, /* Mag. red */ {"mj",F_SHORT,0,0,1000.}, /* Mag. Jmag */ {"mh",F_SHORT,0,0,1000.}, /* Mag. Hlag */ {"mk",F_SHORT,0,0,1000.}, /* Mag. Ksmag */ /*{"t",0,0,0,USNOB_TYC}, -- Tycho-2 Star */ {"cbv",F_SHORT,0,0,1000.}, /* Color example */ {"sp", 0,0,0,10.}, /* Sigma properm */ {"s", 0,0,0,1.}, /* Sigma pos. */ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {"\377\377\377\377"} } ; #define FIELDS_m 6 /* Fields with magnitude */ #define FIELDS_c 14 /* Fields with color --- */ static struct s_fields *compare_fields[32] ; static struct s_fields *check_fields[32] ; static double _factor_ = 1 ; static int4 matched ; /* Matching records */ static int stopid; /* 1 = Stop after last ID read */ static char nom_title[] = "\ #====== NOMAD1 server (2006-06, V%s) ====== CDS, Strasbourg ======\n\ "; static char optEmsg[] = "\ #---------Position recomputed to Epoch."; static char usage[] = "\ Usage: nomad1 [-HELP] [-R root_name] [-E] [-r[s] [min,]radius] [-b[s] x[,y]]\n\ [-e edit_opt] [-f input_file] [-m max_records] [-kR]\n\ [-c center | -i NOMAD-ID | -z zone | Jname | -whole]\n\ [-l! min,max] [-s !] [-whole]\n\ "; static char help[] = "\ -HELP: display column explanations\n\ -b: target box in arcmin ; -bs = target box in arcsec\n\ -r: target radius in arcmin ; -rs = target radius in arcsec\n\ -c: target center in decimal or sexagesimal (default in stdin)\n\ -e: s=edit Sexa; m=edit mas; i=edit NOMAD-ID; a=edit all IDs; x=edit x,y\n\ -f: specifies an input file (default stdin)\n\ -id: query from an NOMAD1 number (zzzz-nnnnnnn)\n\ -kR: keep only recommended astrometric standards (flag USEME set)\n\ -m: max number of stars to retrieve\n\ -l!: Set the limits (range) on one of the parameters (below)\n\ -s!: Sort the result by the parameter ! (list below)\n\ -zxxxx: search on a zone (between 0000 and 1799)\n\ Jname: search sources matching the truncated IAU-name\n\ -whole: search on the whole sky\n\ -E: Compute the position of mean Epoch (apply the proper motion back)\n\ -R: Root (directory) name where the NOMAD files are located ($NOMADroot)\n\ ====The abbreviations of the parameters (symbolized !)are:\n\ a=Alpha c=anyColor d=Delta e=Epoch i=NOMAD1 m=anyMag\n\ p=pmotion r=distance s=sigma sp=sigma(pm) x=proj.E y=proj.N\n\ 'c' and 'm' may be followed by the color(s) B V R J H K (or lowercase)\n\ 's' is the sigma on position, and 'sp' the sigma on proper motion\n\ "; static char HELP[] = "\ Access to NOMAD-1.0 Catalog at CDS\n\ =============================================================================\n\ \n\ The fields have the following meaning:\n\ \n\ NOMAD = Sequential number in original catalogue, as ZZZZ-NNNNNNN, \n\ where ZZZZ is the zone number from 0000 to 1799\n\ USNO-B1.0 = ID in the USNO-B1.0 catalog (Monet et al., Cat. I/284)\n\ UCAC2 = ID in the UCAC2 catalog (Zacharias et al., Cat. I/289)\n\ Tycho-2 = Name in the 'Tycho-2 Catalog' (Hog et al., 2000, Cat. I/259)\n\ or Hipparcos catalog (I/239/hip_main) (3)\n\ RA,Dec,r = Position (Alpha, Delta) at Epoch and Equinox J2000, from r (1)\n\ sRA,sDE = Mean Error on (RAcos(DE)) and (DE) at mean Epoch\n\ Ep.RA,EpDec = Mean Epoch of the positions (epoch of the sigmas on position)\n\ pmRA,pmDE = relative proper motions, in arcsec/yr, of the object\n\ spA,spD = mean error on proper motions pmRA and pmDE resp.\n\ R=object recommended as astrometric standard\n\ Xmag,r = magnitudes in band X (B V R J H K), origin r(1)\n\ FlagsR = hexadecimal flags for this NOMAD source, followed by \n\ * (problematic) or R (recommended as astrometric standard) (2)\n\ -----------------------------------------------------------------------------\n\ r(\") = distance from specified center, in arc seconds.\n\ x,y(\") = position from center toward East (x) and North (y)\n\ -----------------------------------------------------------------------------\n\ Note (1): Sources of the values are:\n\ B = USNO-B1.0 (Monet et al., Cat. I/284)\n\ C = UCAC2 (Zacharias et al., Cat. I/289)\n\ M = 2MASS catalog of point sources (Cutri et al., Cat. II/246)\n\ Y = YB6 Catalog (USNO, unpublished)\n\ T = Tycho-2 Catalog (Hog et al., 2000, Cat. I/259)\n\ H = Hipparcos catalog (Table I/239/hip_main)\n\ o = Palomar-I blue (O) plate (for Bmag)\n\ e = Palomar-I red (E) plate (for Rmag)\n\ Note (2): Flags are written in hexadecimal (symbols 0-f) with meanings:\n\ 00001 = UBBIT : Fails Blaise's test for USNO-B1.0 star\n\ 00002 = TMBIT : Fails Roc's test for clean 2MASS star\n\ 00004 = YB6 : Included in YB6 catalog (Y)\n\ 00008 = 2MASS : Included in 2MASS catalog (M)\n\ 00010 = TYBIT : Astrometry comes from Tycho2 catalog (T)\n\ 00020 = XRBIT : Alternative correlations for same (RA,Dec)\n\ 00040 = ITMBIT : Alternative correlations for same 2MASS ID\n\ 00080 = IUCBIT : Alternative correlations for same UCAC-2 ID\n\ 00100 = ITYBIT : Alternative correlations for same Tycho2 ID\n\ 00200 = OMAGBIT : Blue magnitude from O (not J) plate (o)\n\ 00400 = EMAGBIT : Red magnitude from E (not F) plate (e)\n\ 00800 = TMONLY : Object found only in 2MASS catalog (M)\n\ 01000 = HIPAST : Ast from Hipparcos catalog (H)\n\ 02000 = SPIKE : USNO-B1.0 diffraction spike bit set\n\ 04000 = TYCONF : Tycho2 confusion flag set\n\ 08000 = BSCONF : Bright star has nearby faint source\n\ 10000 = BSART : Faint source is bright star artifact\n\ 20000 = USEME : Recommended astrometric standard\n\ * = one of SPIKE|YCONF|BSCONF|BSART|XRBIT|ITMBIT|IUCBIT|ITYBIT set\n\ R = USEME (recommended astrometric standard)\n\ Note (3): The Tycho-2 number is followed by an asterisk(*) when the distance\n\ between the NOMAD and Tycho-2 poitions is larger than 1\".\n\ =============================================================================\n\ For details concerning NOMAD, see http://www.nofs.navy.mil/nomad/\n\ =============================================================================\n\ "; /*================================================================== Find the NOMADroot parameter *==================================================================*/ static void set_root(char *pgm) /*++++++++++++++++ .PURPOSE Define the NOMADroot .RETURNS .REMARKS Take care of soft links... -----------------*/ { char *a; a = malloc(12+strlen(ROOTdir)); sprintf(a, "NOMADroot=%s", ROOTdir); putenv(a); } static int strloc(char *text, int c) /*++++++++++++++++ .PURPOSE Locate specified character .RETURNS Index of located char -----------------*/ { char *s; for ( s = text; *s; s++) if (*s == c) break; return(s-text); } /*================================================================== Get the parameters *==================================================================*/ static struct s_fields *dup_field(struct s_fields *field) /*++++++++++++++++ .PURPOSE Clone a field .RETURNS The copy -----------------*/ { struct s_fields *f; f = (struct s_fields *)malloc(sizeof(struct s_fields)); memcpy(f, field, sizeof(struct s_fields)) ; return(f); } static struct s_fields *get_field(struct s_fields *fields, char *name) /*++++++++++++++++ .PURPOSE Interpret the meaning of a parameter .RETURNS The relevant field / NULL -----------------*/ { struct s_fields *f, *f1; int letter, i, j; letter = tolower(name[0]); f1 = (struct s_fields *)0; for (f=fields; f->name[0]; f++) { if (f->name[0] != letter) continue; for (i=j=1; f->name[i]; i++, j++) { if (name[j] == '-') j++; /* Accept B-V as bv */ if (name[j] == 0) break; if (tolower(f->name[i]) != tolower(name[j])) break; } if (name[i] == 0) return(f) ; f1 = f; } /* Field not found -- add if a color */ if (f1) { /* Matching first letter -- look for mag letter(s) */ if (f[1].name[0] == '\377') { /* Too many selection fields */ fprintf(stderr, "****Too many fields, ignored: %s\n", name); f = (struct s_fields *)0; } else { f->name[0] = name[0]; f->flags = f1->flags; for (i=j=1; name[j] && (i<3); j++) { if (isalpha(name[j])) f->name[i++] = tolower(name[j]); } f->factor = f1->factor; } } else f = f1; return(f); } /*============================================================================*/ static void tr_ou(double o[2], double u[3]) /*++++++++++++++++ .PURPOSE Compute direction cosines .RETURNS --- -----------------*/ { u[0] = u[1] = cosd(o[1]) ; u[0] *= cosd(o[0]) ; u[1] *= sind(o[0]) ; u[2] = sind(o[1]) ; } static int tr_uo(double u[3], double o[2]) /*++++++++++++++++ .PURPOSE Compute RA+Dec from direction cosines .RETURNS 1 / 0 (x=y=z=0) -----------------*/ { double r2; /* sqrt(x*x+y*y) */ r2 = u[0]*u[0] + u[1]*u[1]; o[0] = 0.e0; if (r2 == 0.e0) { /* in case of poles */ o[0] = 999.; o[1] = 99.; if (u[2] == 0.e0) return(0); o[1] = ( u[2]>0.e0 ? 90.e0 : -90.e0); o[0] = 0.; return(1); } o[1] = atand ( u[2] / sqrt(r2)); o[0] = atan2d (u[1] , u[0] ); if (o[0] < 0.e0) o[0] += 360.e0; return (1); } static void tr_oR ( o , R ) /*++++++++++++++++ .PURPOSE Creates the rotation matrix R[3][3] defined as R[0] (first row) = unit vector towards Zenith R[1] (second row) = unit vector towards East R[2] (third row) = unit vector towards North .RETURNS --- -----------------*/ double o[2]; /* IN: original angles */ double R[3][3]; /* OUT: rotation matrix */ { R[2][2] = cosd(o[1]); R[0][2] = sind(o[1]); R[1][1] = cosd(o[0]); R[1][0] = -sind(o[0]); R[1][2] = 0.e0; R[0][0] = R[2][2] * R[1][1]; R[0][1] = -R[2][2] * R[1][0]; R[2][0] = -R[0][2] * R[1][1]; R[2][1] = R[0][2] * R[1][0]; } static void tr_uu( u1 , u2 , R ) /*++++++++++++++++ .PURPOSE Rotates the unit vector u1 to u2, as (u2) = (R) * (u1) .RETURNS --- -----------------*/ double u1[3]; /* IN: Unit vector */ double u2[3]; /* OUT: Resulting unit vector after rotation */ double R[3][3]; /* IN: rotation matrix (e.g. created by tr_oR)*/ { register int i; double u_stack[3]; /* allows same address for input/output */ for (i=0; i<3; i++) u_stack[i] = R[i][0]*u1[0] +R[i][1]*u1[1] + R[i][2]*u1[2] ; u2[0] = u_stack[0]; /* copies to output */ u2[1] = u_stack[1]; /* copies to output */ u2[2] = u_stack[2]; /* copies to output */ } static void tr_uu1( u1 , u2 , R ) /*++++++++++++++++ .PURPOSE Rotates the unit vector u1 to u2, as (u2) = (R)^-1^ * (u1) .RETURNS --- -----------------*/ double u1[3]; /* IN: Unit vector */ double u2[3]; /* OUT: Resulting unit vector after rotation */ double R[3][3]; /* IN: rotation matrix (e.g. created by tr_oR)*/ { register int i; double u_stack[3]; /* allows same address for input/output */ for (i=0; i<3; i++) u_stack[i] = R[0][i]*u1[0] +R[1][i]*u1[1] + R[2][i]*u1[2] ; u2[0] = u_stack[0]; /* copies to output */ u2[1] = u_stack[1]; /* copies to output */ u2[2] = u_stack[2]; /* copies to output */ } /*===========================================================================*/ static int match_unum (char *string, double *value) /*++++++++++++++++ .PURPOSE Analyze the incoming and get unsigned number (no E notation) .RETURNS How many bytes matched .REMARKS Initial blanks return 0 -----------------*/ { char *p; for (p=string; isdigit(*p); p++) ; if (*p == '.') for (++p; isdigit(*p); p++) ; if (p == string) *value = 0 ; else *value = _factor_ * atof(string) ; return(p-string); } static int match_num (char *string, double *value) /*++++++++++++++++ .PURPOSE Analyze the incoming and get signed number (no E notation) .RETURNS How many bytes matched .REMARKS The internal _value_ is set -----------------*/ { char *p, *s ; for (s=string; *s == ' '; s++) ; p = s ; if ((*p == '+') || (*p == '-')) p++ ; p += match_unum(p, value) ; if (*s == '-') *value = -*value ; return(p-string); } int match_Jname (char *arg, int4 *mas, int4 *Jprec) /*++++++++++++++++ .PURPOSE Interpret a string for a Jname .RETURNS Number of bytes matched .REMARKS Results of RA and Dec in mas. Value of last decimals saved in Jprec, in mas (beware, Jprec negative when declination negative!) -----------------*/ { static int step1[] = { /* Factors to convert to ms */ 36000000, /* #° */ 3600000, 360000, /* HH or DD DDd */ 60000, 6000, /* HHMM HHMMm */ 1000, 100, /* HHMMSS[s] */ 10, 1 /* HHMMSSss[s] */ }; char apart[12], sign, dpart[11], *p; int a, d, i, ms; p = arg; if (toupper(*p) == 'J') p++; for (i=a=0; (i<10) && p[i]; i++) { if (p[i] == '.') { if (a==6) continue; fprintf(stderr, "#***Bad Jname(RA) : %s\n", arg); return(-1); } if (isdigit(p[i])) apart[a++] = p[i]; else break; } apart[a] = 0; sign = p[i++]; if ((sign != '+') && (sign != '-')) { fprintf(stderr, "#***Bad Jname(sgn): %s\n", arg); return(-1); } p += i; for (d=i=0; (i<10) && p[i]; i++) { if (p[i] == '.') { if (d==6) continue; fprintf(stderr, "#***Bad Jname(Dec): %s\n", arg); return(-1); } if (isdigit(p[i])) dpart[d++] = p[i]; else break; } dpart[d] = 0; if ((a<4)||(d<2)) { fprintf(stderr, "#***Bad Jname(...): %s\n", arg); return(-1); } /* Convert to 1/1000" */ step1[2] = a == 3 ? 360000 : 600000; step1[4] = a == 5 ? 6000 : 10000; for (i=ms=0; apart[i]; i++) ms += (apart[i]-'0')*step1[i]; if (Jprec) Jprec[0] = step1[a-1]*15; mas[0] = ms*15; step1[2] = d == 3 ? 360000 : 600000; step1[4] = d == 5 ? 6000 : 10000; for (i=ms=0; dpart[i]; i++) ms += (dpart[i]-'0')*step1[i]; if (Jprec) Jprec[1] = step1[d-1]; mas[1] = ms; if (sign == '-') { mas[1] = -ms; Jprec[1] = -Jprec[1]; } return(p-arg); } static int get_lim (char *string, double values[2]) /*++++++++++++++++ .PURPOSE Find out the limits (2 numbers separated by ,) .RETURNS 0 / 1 / 2 / 3 .REMARKS Accept p=min1,max1=min2,max2 ==> sqrt(min1^2+min2^2) / -----------------*/ { int found, round, n ; double val ; char *p ; found = 0 ; p = string ; values[0] = values[1] = 0 ; round = 0 ; NextRound: round ^= 1; n = match_num(p, &val) ; if (n) { found |= 1, p += n ; if (round) values[0] = val ; else values[0] = sqrt(values[0]*values[0] + val*val) ; } if (*p) { p++ ; n = match_num(p, &val) ; if (n) { found |= 2, p += n ; } if (round) values[1] = val ; else values[1] = sqrt(values[1]*values[1] + val*val) ; } if (*p && round) goto NextRound; return(found) ; } static int get_zID (char *string, int4 id[2]) /*++++++++++++++++ .PURPOSE Interpret a string for NOMAD Numbers (zone-number) .RETURNS Number of bytes matched .REMARKS Accept ZONE-* -----------------*/ { double v ; char *p ; p = string ; p += match_unum(p, &v) ; id[0] = v ; if (*p) { /* Zone is specified */ ++p; p += match_unum(p, &v) ; if (*p) { /* V1.32: There are non-numeric chars, e.g. 12*, or 1200, */ if (strchr("%*?_[]^", *p)) /* Assume an expression */ v = 0; else /* V1.32: assume a lower limit */ v = -v; } id[1] = v ; } else id[1] = id[0] ; return(p-string) ; } static int get_center (char *string, double center[2]) /*++++++++++++++++ .PURPOSE Interpret a string for RA + DEC .RETURNS Number of bytes matched -----------------*/ { double v, factor ; char *p, *s ; if (toupper(*string) == 'J') { int4 mas[2], bytes; bytes = match_Jname(string, mas, (int4 *)0); center[0] = mas[0]/3.6e6; center[1] = mas[1]/3.6e6; return(bytes); } factor = _factor_ ; center[0] = center[1] = 0 ; p = string ; while (*p == ' ') p++ ; p += match_unum(p, center) ; while (*p == ' ') p++ ; if (*p == ',') /* For those HEASARC guys ! */ for (++p; *p == ' '; p++) ; if ((*p == '+') || (*p == '-')) ; else { /* Sexagesimal */ while ((*p == ':') || isdigit(*p)) { _factor_ /= 60.; if (*p == ':') p++ ; p += match_unum(p, &v); while (*p == ' ') p++ ; center[0] += v ; } center[0] *= 15. ; /* Right Ascension */ } s = p ; if ((*s == '+') || (*s == '-')) p++ ; _factor_ = 1 ; while ((*p == ':') || isdigit(*p)) { if (*p == ':') p++ ; p += match_unum(p, &v); while (*p == ' ') p++ ; center[1] += v ; _factor_ /= 60. ; } if (*s == '-') center[1] = -center[1] ; _factor_ = factor ; /* Restore */ return(p-string) ; } /*================================================================== Check routine (return 0 = don't keep, 1 = keep) *==================================================================*/ static int matching_color(char *col, NOMADrec *rec) /*++++++++++++++++ .PURPOSE Match the color 0=B 1=V 2=R 3=J 4=H 5=K .RETURNS 0..5 => the required index (6=error) -----------------*/ { int i; if (!col[0]) { /* Color not specified -- take first valid one */ for (i=0; NOMADmag[i] && (rec->mag[i] == NULLmag ); i++) ; if (NOMADmag[i]) return(i); } return(strloc(NOMADmag, toupper(col[0]))); } static int remove_pm(NOMADrec *rec) /*++++++++++++++++ .PURPOSE Re-compute the position at original epoch .RETURNS 0 (no proper motion) / 1 .REMARKS Use matrix dx -sin(a) -sin(d)cos(a) dy = cos(a) -sin(d)sin(a) . mu1.t dz 0 +cos(d) mu2t -----------------*/ { double R[3][3], u[3], v[3], o[2], t[2]; int ra, sd; if ((rec->pmra | rec->pmsd) == 0) /* Zero proper motion */ return(0); t[0] = rec->epra - 20000; t[0] /= 10.; t[1] = rec->epsd - 20000; t[1] /= 10.; if ((t[0] == 0) && (t[1] == 0)) /* E.g. for Tycho-2 */ return(0); o[0] = rec->ra; o[1] = rec->sd - adeg(90); o[0] /= 3.6e6; o[1] /= 3.6e6; v[1] = rec->pmra*t[0]/3.6e6; v[2] = rec->pmsd*t[1]/3.6e6; #if COMPUTE_EpPOS == 0 if (fabs(o[1]) > 84) { /* Close to Pole */ v[0] = 1; v[1] *= (M_PI/180.); v[2] *= (M_PI/180.); tr_oR(o, R); tr_uu1(v, u, R); tr_uo(u, o); } else { o[0] += v[1]/cosd(o[1]); if (o[0] < 0.) o[0] += 360.; if (o[0] >= 360.) o[0] -= 360.; o[1] += v[2]; } #else # if COMPUTE_EpPOS == 1 /* Use Full Matrix expression */ v[0] = 1; v[1] *= (M_PI/180.); v[2] *= (M_PI/180.); tr_oR(o, R); tr_uu1(v, u, R); # else /* Compute Cartesian diffarence */ tr_ou(o,u); R[0][1] = -sind(o[0]); R[1][1] = cosd(o[0]); R[2][1] = 0; R[0][2] = sind(o[1]); R[1][2] = R[0][2]*R[0][1]; R[2][2] = cosd(o[1]); R[0][2]*= -R[1][1]; u[0] += R[0][1]*v[1] + R[0][2]*v[2]; u[1] += R[1][1]*v[1] + R[1][2]*v[2]; u[2] += R[2][2]*v[2]; # endif tr_uo(u, o); #endif /* Convert to mas */ ra = adeg(o[0]); sd = adeg(o[1]) + adeg(90); #if 0 /* How large is the change ?? */ fprintf(stderr, "....Change for %4d-%07d (%+05.1fyr) %6d %6d\n", rec->zone, rec->id, t, ra-rec->ra, sd-rec->sd); #endif return(1); } static int check(NOMADrec *rec) /*++++++++++++++++ .PURPOSE Verify the various constraints .RETURNS 1 (OK) / 0 (does not fit) -----------------*/ { struct s_fields **f; double o[2], u[3], du, dr2 ; int i, j, value, flag; /* Verify first the Position */ flag = 0 ; rec->xy[0] = rec->xy[1] = NULLxy ; if (du2max >= 0) { o[0] = rec->ra / 3.6e6 ; o[1] = rec->sd / 3.6e6 - 90. ; tr_ou(o, u); flag |= 1 ; du = u[0] - localR[0][0] ; dr2 = du * du ; du = u[1] - localR[0][1] ; dr2 += du * du ; du = u[2] - localR[0][2] ; dr2 += du * du ; if (dr2 > du2max) return(0) ; rec->rho = thefields[0].factor * 2.*asind(0.5*sqrt(dr2)) ; if (opted&8) { /* Compute x,y */ tr_uu(u, u, localR) ; rec->xy[0] = thefields[2].factor*u[1]/u[0] ; rec->xy[1] = thefields[3].factor*u[2]/u[0] ; flag |= 2 ; } } else rec->rho = -1 ; /* printf("#id=%4d,%8d, rho=%8d, mags=%4d,%4d,%4d\n", rec->zone,rec->id,rec->rho, rec->mB, rec->mR, rec->ci) ; */ for (f=check_fields ; *f; f++) switch((*f)->name[0]) { case_xy: if (!flag) { o[0] = rec->ra / 3.6e6 ; o[1] = rec->sd / 3.6e6 - 90. ; tr_ou(o, u); flag |= 1 ; } if (!(flag&2)) { tr_uu(u, u, localR) ; rec->xy[0] = thefields[2].factor*u[1]/u[0] ; rec->xy[1] = thefields[3].factor*u[2]/u[0] ; flag |= 2 ; } if (rec->xy[i] < (*f)->lim[0]) return(0) ; if (rec->xy[i] > (*f)->lim[1]) return(0) ; break ; case 'x': i = 0 ; goto case_xy ; case 'y': i = 1 ; goto case_xy ; case 'a': /* Right Ascension */ if ((*f)->lim[0] <= (*f)->lim[1]) { if (rec->ra < (*f)->lim[0]) return(0) ; if (rec->ra > (*f)->lim[1]) return(0) ; } else { if ((rec->ra < (*f)->lim[0]) && (rec->ra > (*f)->lim[1])) return(0) ; } continue ; case 'm': /* One magnitude */ i = matching_color((*f)->name+1, rec); if (i>=6) return(0); if (rec->mag[i] < (*f)->lim[0]) return(0) ; if (rec->mag[i] > (*f)->lim[1]) return(0) ; continue ; case 'c': /* One colour index */ /* if (rec->flags&NOMAD_TYC) return(0); */ i = strloc(NOMADmag, toupper((*f)->name[1])); j = strloc(NOMADmag, toupper((*f)->name[2])); if (rec->mag[i] == NULLmag) return(0); if (rec->mag[j] == NULLmag) return(0); value = rec->mag[i] - rec->mag[j]; if (value < (*f)->lim[0]) return(0); if (value > (*f)->lim[1]) return(0); continue ; case 'd': /* Declination */ if (rec->sd < (*f)->lim[0]) return(0) ; if (rec->sd > (*f)->lim[1]) return(0) ; continue ; case 'e': /* Epoch */ value = (rec->epra + rec->epsd)/2; if (value < (*f)->lim[0]) return(0) ; if (value > (*f)->lim[1]) return(0) ; continue ; case 'i': /* lim[0] = Zone, lim[1] = ID */ if (rec->zone != (*f)->lim[0]) return(stopid) ; if ((*f)->lim[1] <= 0) /* Whole Zone (mod. V1.32) */ continue; if (rec->id < (*f)->lim[1]) return(0) ; if (rec->id > (*f)->lim[1]) return(stopid) ; continue ; #if 0 case 't': /* A Tycho-2 star */ if ((rec->TYC3) < (*f)->lim[0]) return(0); /*if ((rec->TYCHO3) > (*f)->lim[1]) return(0);*/ #endif case 'p': /* Proper motion */ if (rec->pmtot < 0) { u[0] = rec->pmra ; u[1] = rec->pmsd ; rec->pmtot = 0.5 + sqrt(u[0]*u[0] + u[1]*u[1]) ; } if (rec->pmtot < (*f)->lim[0]) return(0) ; if (rec->pmtot > (*f)->lim[1]) return(0) ; continue ; case 'k': /* Flags -- min contains the mask, max the result */ i = rec->flags&(*f)->lim[0] ; if (i^(*f)->lim[1]) return(0); continue; case 's': /* Sigmas (pos or proper motion) */ value = (*f)->name[1] == 'p' ? /* Sigma proper motion */ rec->e_pmra*rec->e_pmra + rec->e_pmsd*rec->e_pmsd : rec->e_ra*rec->e_ra + rec->e_sd*rec->e_sd; if (value < (*f)->lim[0]*(*f)->lim[0]) return(0); if (value > (*f)->lim[1]*(*f)->lim[1]) return(0); continue; case 'r': /* Radius */ if (rec->rho < (*f)->lim[0]) return(0) ; if (rec->rho > (*f)->lim[1]) return(0) ; continue ; } return(1) ; } /*================================================================== Comparison routines *==================================================================*/ static int compare(NOMADrec *a, NOMADrec *b) /*++++++++++++++++ .PURPOSE Compare two records according to the sort options .RETURNS Difference (a-b) -----------------*/ { struct s_fields **af, *f; double u[3] ; int i, j, c[2]; int diff = 0; compare_calls++; for (af=compare_fields ; (diff==0) && *af; af++) { f = *af; switch(f->name[0]) { case 'x': diff = a->xy[0] - b->xy[0]; break; case 'y': diff = a->xy[1] - b->xy[1]; break; case 'a': /* RA */ diff = a->ra - b->ra; break; case 'c': /* Color */ i = strloc(NOMADmag, toupper(f->name[1])); j = strloc(NOMADmag, toupper(f->name[2])); c[0] = (a->mag[i] == NULLmag) || (a->mag[j] == NULLmag) ? NULLmag : a->mag[i] - a->mag[j]; c[1] = (b->mag[i] == NULLmag) || (b->mag[j] == NULLmag) ? NULLmag : b->mag[i] - b->mag[j]; if (c[0] == c[1]) continue; if (c[0] == NULLmag) { diff = 30000; continue; } /* Keep b */ if (c[1] == NULLmag) { diff = -30000; continue; } /* Keep a */ diff = c[0] - c[1]; break; case 'i': /* NOMAD-id */ diff = a->id - b->id; break; case 'd': /* Declination */ diff = a->sd - b->sd; break; case 'm': /* Magnitude */ i = strloc(NOMADmag, toupper(f->name[1])); if (a->mag[i] == b->mag[i]) continue; if (a->mag[i] == NULLmag) { diff = 30000; continue; } /* Keep b */ if (b->mag[i] == NULLmag) { diff = -30000; continue; } /* Keep a */ diff = a->mag[i] - b->mag[i]; break; case 'p': /* Total proper motion */ if (a->pmtot < 0) { u[0] = a->pmra ; u[1] = a->pmsd ; a->pmtot = 0.5 + sqrt(u[0]*u[0] + u[1]*u[1]) ; } if (b->pmtot < 0) { u[0] = b->pmra ; u[1] = b->pmsd ; b->pmtot = 0.5 + sqrt(u[0]*u[0] + u[1]*u[1]) ; } diff = a->pmtot - b->pmtot; break; case 'e': /* Epoch */ i = (a->epra + a->epsd)/2; j = (b->epra + b->epsd)/2; diff = i-j; break; case 'r': diff = a->rho - b->rho; break; } if (f->order<0) diff = -diff; } return(diff) ; } /*================================================================== Sorting the Records *==================================================================*/ #if 0 /* Used for tests */ static void print_inodes(LNOMAD *node) /*++++++++++++++++ .PURPOSE Print mag2 + ID .RETURNS --- .REMARKS Recursivity = simplicity !! -----------------*/ { LNOMAD *n; if (!node) return; if (node->lt) print_inodes(node->lt); for (n=node; n; n=n->eq) printf("%10d %6d %6d %6d %6d %6d %6d\n", n->rec.id, n->rec.mag[0], n->rec.mag[1], n->rec.mag[2], n->rec.mag[3], n->rec.mag[4], n->rec.mag[5]); if (node->gt) print_inodes(node->gt); } #endif static int add_rec(NOMADrec *new) /*++++++++++++++++ .PURPOSE Add a new record, link it. .RETURNS 0 (not kept) / 1 -----------------*/ { LNOMAD *node, *prev, *n; int4 comp1; int diff=0; comp1 = compare_calls; /* (0) Check if the new record has any use... */ n = (LNOMAD *)0; /* n -> last */ if (irec == mrec) { if (!last) for (last=root; last->gt; last=last->gt) n = last; diff = compare(new, &(last->rec)); if (diff >= 0) { truncated++; return(0); } } /* (1) Find where in the list we've to insert the new record */ node = root; prev = (LNOMAD *)0; while(node) { diff = compare(new, &(node->rec)); prev = node; if (diff == 0) break; node = diff < 0 ? node->lt : node->gt ; } /* (2) If max attained, put the new in place of last * node = where to store the new record. */ if (irec == mrec) { truncated++ ; node = last ; /* Where to store new record */ if (last->eq) { /* Several last records... */ node = last->eq; last->eq = node->eq ; } else { /* n->gt must give LAST record */ if (!n) for (last=root; last->gt; last=last->gt) n = last; if (!n) { /* Happens when root == last ! */ root = root->lt; last = root; } else { /* The last is now given by n */ if (prev == last) { /* new attached to last */ prev = n; diff = compare(new, &(prev->rec)); } last = n; last->gt = node->lt; } } while(last->gt) last = last->gt; } else node = arec + irec++ ; /* (3) Insert the new record, and set the links */ *(&(node->rec)) = *new ; node->lt = node->gt = node->eq = (LNOMAD *)0; if (!prev) { root = node; last = (LNOMAD *)0; } else { if (diff < 0) { prev->lt = node; } else if (diff > 0) { /* I may have prev == last ... */ prev->gt = node; if (last) while(last->gt) last = last->gt; } else { /* Here diff == 0 */ node->eq = prev->eq; prev->eq = node; } } #if 0 fprintf(stderr, "....Adding#%d: comparisons=%ld\n", irec, compare_calls-comp1); #endif /* * printf("----(truncated=%d)\n", truncated); * print_inodes(root); */ return(1) ; } static void print_nodes(LNOMAD *node) /*++++++++++++++++ .PURPOSE Print all nodes in order .RETURNS --- .REMARKS Recursivity = simplicity !! -----------------*/ { LNOMAD *n; if (!node) return; if (node->lt) print_nodes(node->lt); for (n=node; n; n=n->eq) puts(nomad2a(&(n->rec), opted)); if (node->gt) print_nodes(node->gt); } /*================================================================== Search in a Circle *==================================================================*/ static int digest(NOMADrec *rec) /*++++++++++++++++ .PURPOSE Digest routine: check and display if necessary .RETURNS 0 -----------------*/ { int st ; /* --- Apply the Position Transformation if needed */ if (optE) remove_pm(rec); st = check(rec) ; if (st <= 0) return(st) ; matched += 1 ; if (compare_fields[0]) add_rec(rec) ; else { if (irec >= mrec) { truncated++; matched = 0; return(-1) ; } irec++ ; puts(nomad2a(rec, opted)); } return(0) ; } int4 nomad_loop() /*++++++++++++++++ .PURPOSE Loop on read & test of NOMAD records .RETURNS Number of tested records. -----------------*/ { int4 tested = 0 ; NOMADrec rec ; while(1) { if (nomad_read(&rec) <= 0) break ; tested++; if (digest(&rec) < 0) break ; } return(tested) ; } int4 nomad_pos(int4 gra[2], int4 gsd[2]) /*++++++++++++++++ .PURPOSE Launch Search on NOMAD stars from limits in RA + DE .RETURNS Number of tested records. .REMARKS Merge with specified RA / DE limits -----------------*/ { int4 ra[2], sd[2], sra[4], tra[4], tested ; int i, j ; tested = 0 ; if ((!thefields[5].selected) && (!thefields[4].selected)) return(nomad_search(gra, gsd, digest)) ; if (gsd) sd[0] = gsd[0], sd[1] = gsd[1] ; else sd[0] = 0, sd[1] = adeg(180) ; if (thefields[5].selected) { /* Limits in DE */ sd[0] = MAX(sd[0], thefields[5].lim[0]) ; sd[1] = MIN(sd[1], thefields[5].lim[1]) ; if (sd[0] > sd[1]) return(0); /* Mismatch Dec */ } sra[0] = tra[0] = 0; sra[1] = tra[1] = adeg(360)-1 ; /* Selected RA */ sra[2] = tra[2] = sra[3] = tra[3] = -1 ; if (gra) { tra[0] = gra[0]; if (gra[0] <= gra[1]) tra[1] = gra[1] ; else tra[3] = gra[1], tra[2] = 0 ; } if (thefields[4].selected) { /* Limits in RA */ sra[0] = thefields[4].lim[0] ; if (thefields[4].lim[0] <= thefields[4].lim[1]) sra[1] = thefields[4].lim[1] ; else sra[3] = thefields[4].lim[1], sra[2] = 0 ; } for (i=0; i<4; i += 2) for (j=0; j<4; j += 2) { if (sra[j] < 0) continue ; if (tra[i] < 0) continue ; ra[0] = MAX(tra[i], sra[j]) ; ra[1] = MIN(tra[i+1], sra[j+1]) ; if (ra[0] > ra[1]) continue ; tested += nomad_search(ra, sd, digest) ; } return(tested) ; } int4 nomad_center(double center[2]) /*++++++++++++++++ .PURPOSE Search NOMAD stars from a central position: - either within circle of radius (degrees) - or within box of half-dimensions boxy .RETURNS Number of tested records. -----------------*/ { int4 ra[2], sd[2]; double value, sr, cosdec, da, dd, maxrad=RADIUS; ra[0] = 0, ra[1] = adeg(360) - 1 ; dd = 180. ; if ((radius==0) && (boxy[1]==0)) radius = RADIUS ; if (radius > 0) dd = maxrad = radius ; if (boxy[1] > 0) /* Search in a Box */ dd = maxrad = sqrt(boxy[0]*boxy[0] + boxy[1]*boxy[1]) ; /* Don't accept too large searches... */ if (dd > 45.) { fprintf(stderr, "****Radius [%.5f]deg or Box [%.5fx%.5f] too large\n", maxrad, boxy[0], boxy[1]) ; exit(1) ; } /* Derive first the limits in Dec and RA */ value = center[1] - dd ; sd[0] = (90.+value) * 3.6e6 ; value = center[1] + dd ; sd[1] = (90.+value) * 3.6e6 ; if (sd[0] < 0) sd[0] = 0 ; if (sd[1] > adeg(180)) sd[1] = adeg(180) ; cosdec = cosd(center[1]) ; sr = sind(maxrad) ; du2max = 2. * sind(maxrad/2.) ; /* Compute limits on RA */ if (sr < cosdec) { /* Pole not included in circle */ da = asind(sr/cosdec) ; ra[0] = (center[0] - da)*3.6e6 ; if (ra[0] < 0) ra[0] += adeg(360) ; ra[1] = (center[0] + da)*3.6e6 ; ra[1] %= adeg(360) ; } /* Define the constants */ tr_oR(center, localR) ; du2max *= du2max ; /* Display the Constraints */ if (nomad_options&1) { printf("#....nomad_center(%.5f, %.5f) maxrad=%.5f, limits_mas:\n", center[0], center[1], maxrad) ; printf("#.... ra=[%d,%d]", ra[0], ra[1]) ; printf(" sd=[%d,%d]\n", sd[0], sd[1]) ; } /* Merge the -la & -ld limits, and Launch Search */ return(nomad_pos(ra, sd)) ; } /*================================================================== Main Program *==================================================================*/ /* Signal: if interrupted, return the signal number */ #include void OnSignal(signo) { char hostname[32]; hostname[0] = 0; gethostname(hostname, sizeof(hostname)); if (signo == SIGALRM) printf( "\n#***tooLong (>%ds), STOP (%s@%s)\n", TIMEOUT, theProg, hostname) ; else printf( "\n#***Signal #%d received, STOP (%s@%s)\n", signo, theProg, hostname) ; exit(signo) ; } int main (argc, argv) int argc; char **argv; { char line[BUFSIZ], *p, *a ; double center[2]; double flims[2] ; char *the_center, *pgm, argline[BUFSIZ] ; struct s_fields *f, *fc ; int goon = 1 ; int4 tested, aint4, Jpos[2], Jprec[2]; int i, sign ; int non_flagged_arg = 0 ; int limradec = 0; FILE *input_file ; theProg = argv[0]; if (argc < 2) { fprintf(stderr, "%s%s", usage, help) ; exit(1) ; } /* Display the interruption for all signals execpt start/stop */ for (i=1; i<15; i++) { if (i == SIGTSTP) continue; if (i == SIGCONT) continue; signal(i, OnSignal) ; } siginterrupt(SIGALRM, 1); alarm(TIMEOUT); /* Keep program name to define the default NOMAD root name */ pgm = argv[0] ; /* fprintf(stderr, "....pgm=%s\n", pgm ? pgm : "(nil)") ; */ /* NOTE: The options can also be RA-DEC Radius */ the_center = line ; input_file = stdin ; while (--argc > 0) { p = *++argv; if (*p == '-') switch(p[1]) { case 'H': /* HELP */ printf("%s", HELP); exit(0) ; case 'h': /* Help */ fprintf(stderr, "%s%s", usage, help) ; exit(0) ; case 'f': /* Next parameter = input file */ argc--, argv++; input_file = fopen(*argv, "r") ; if (!input_file) { perror(*argv) ; exit(1) ; } continue ; case 'b': /* Next parameter = Box limits */ argc--, argv++; switch(p[2]) { case 'd': _factor_ = 1; break ; case 's': _factor_ = 1./3600. ; break ; default: _factor_ = 1./60. ; break ; } if (get_lim(*argv, flims) < 2) flims[1] = flims[0] ; _factor_ = 1.; flims[0] /= 2.0 ; flims[1] /= 2.0 ; boxy[0] = flims[0] ; boxy[1] = flims[1] ; thefields[2].lim[1] = thefields[2].factor*tand(flims[0]) ; thefields[3].lim[1] = thefields[3].factor*tand(flims[1]) ; thefields[2].lim[0] = -thefields[2].lim[1] ; thefields[3].lim[0] = -thefields[3].lim[1] ; thefields[2].selected = thefields[3].selected = 1 ; continue ; case 'E': /* Remove the proper motion effect */ optE = 1; continue ; case 'R': /* Root Name of Catalogue */ if (p[2]) p += 2; else p = *++argv, argc-- ; a = malloc(12+strlen(p)) ; sprintf(a, "NOMADroot=%s", p) ; putenv(a) ; pgm = (char *)0 ; /* Forget about implied from program name */ continue ; case 'r': /* Next parameter = Radius */ argc--, argv++; switch(p[2]) { case 'd': _factor_ = 1; break ; case 's': _factor_ = 1./3600. ; break ; default: _factor_ = 1./60. ; break ; } if (get_lim(*argv, flims) < 2) { flims[1] = flims[0] ; flims[0] = 0 ; } radius = flims[1] ; _factor_ = 1.; thefields[0].lim[0] = thefields[0].factor*flims[0] ; thefields[0].lim[1] = thefields[0].factor*flims[1] ; /* Need to be specifically tested only r_min != 0 */ if (thefields[0].lim[0]>0) thefields[0].selected = 1; continue ; case 'm': /* Max number of records */ argc--, argv++; mrec = atoi(*argv) ; if (mrec < 1) mrec = 1 ; continue ; case 'e': /* Edit option */ p += 2; /* Is the argument of sort glued with -e ? */ if (!*p) p = *++argv, argc-- ; opted = 0 ; if (isdigit(*p)) opted = atoi(p) ; else while(*p) switch(*(p++)) { case '.': case '+': opted |= 6; continue; case ' ': case 'd': continue ; case 'b': opted = 0; continue ; /* Basic data V1.2 */ case 's': opted |= 1 ; continue ; case 'i': opted |= 2 ; continue ; case 'e': opted |= 4 ; continue ; case 'a': opted |= 10; continue ; /* All ids = 8|2 */ case 'm': opted |= 16; continue ; case 'x': opted |= 32; continue ; case 'p': opted |=128; continue ; /* Pos.Only, V1.2 */ default: fprintf(stderr, "****Bad argument: -e '%s'\n%s", --p, usage); exit(1) ; } continue ; case 'i': /* Input ID */ input_id = 1 ; thefields[1].selected = 1; if (argc > 1) { /* ID as argument */ stopid = -1 ; /* Indicates to stop after last ID read */ argc--, argv++; the_center = strdup(*argv) ; } continue ; case 'z': /* A Zone */ input_id = 4 ; if (argc > 1) { /* Zone as argument */ nomad_stop(1) ; /* Must stop at EOF */ argc--, argv++; the_center = strdup(*argv) ; } continue ; case 'k': /* Keep only astrometric standards */ f = get_field(thefields, "k"); f->selected = 1; f->lim[1] = strchr(p+2, '-') ? 0 : f->lim[0]; continue; case 'l': /* Set up the limits */ argc--, argv++; i = get_lim(*argv, flims); if (i==1) flims[1] = flims[0] ; if (i==2) flims[0] = -0x7fffffff ; if (!(f = get_field(thefields, p+2))) { fprintf(stderr, "****Unknown field in %s\n%s", p, usage); exit(1) ; } f->selected = 1 ; f->lim[0] = flims[0] * f->factor ; f->lim[1] = flims[1] * f->factor ; /* Special NULL limits */ if (i==2) { /* No lower limit */ f->lim[0] = f->flags&F_SHORT ? -0x7fff : -0x7fffffff; } /* Peculiar options */ if (f->flags&F_RA) /* Limits in RA */ limradec |= 1; else if (f->flags&F_SD) { /* Limits Dec */ f->lim[0] += adeg(90), f->lim[1] += adeg(90) ; limradec |= 2; } /* Sort the limits in their right order */ if ((f->lim[1] < f->lim[0]) && ((f->flags&F_RA) == 0)) { aint4 = f->lim[0], f->lim[0] = f->lim[1], f->lim[1] = aint4 ; } continue ; case 's': /* Sort Order */ p += 2; /* Is the argument of sort glued with -s ? */ if (!*p) p = *++argv, argc-- ; for (i = 0 ; *p && (i < ITEMS(compare_fields)); i++, p++) { sign = 1 ; if (*p == '-') sign = -1, p++ ; else if (*p == '+') p++ ; f = get_field(thefields, p) ; if (!f) { fprintf(stderr, "****Unknown field in -s %s\n%s", *argv, usage) ; exit(1) ; } f = dup_field(f); f->order = sign ; /* Skip the rest of the word, until next sort */ for (sign=1; p[1] && f->name[sign] && isalnum(*p); p++) sign++; f->name[sign] = 0; /* e.g. magnitudes truncated */ compare_fields[i] = f ; } continue ; case 'c': /* Get Center */ argc--, argv++; if (argc < 1) { fprintf(stderr, "****Unspecified center in -c argument\n%s", usage) ; exit(1) ; } strcpy(argline, *argv); the_center = argline ; while (argc > 1) { /* Position as several arguments ? */ if (issign(argv[1][0])) { if (! isdigit(argv[1][1])) break ; } else if (! isdigit(argv[1][0])) break ; argc--, argv++ ; strcat(argline, " ") ; strcat(argline, *argv) ; } continue ; case 'v': /* Verbose */ if (strncmp(p, "-ver", 4) == 0) { printf("nomad1(%s) -- Version %s\n", ROOTdir, VERSION); exit(0); } nomad_options |= 1 ; continue ; case 'w': /* Whole sky */ if (strcmp(p, "-whole") == 0) { whole_nomad = 1 ; mrec = 1999999999 ; continue ; } /* NO BREAK */ default: fprintf(stderr, "****Unknown argument: %s\n%s", p, usage); exit(1) ; } /* Non-Option: if */ if (isdigit(*p) && (non_flagged_arg < 2)) { non_flagged_arg++ ; if (the_center == line) { the_center = *argv; continue ; } get_lim(*argv, flims); radius = flims[0]/60. ; continue ; } /* Non-Option: accept Jnames (V1.1) */ if ((toupper(*p) == 'J') && (input_id == 0)) { input_id = 2; the_center = p; continue; } fprintf(stderr, "****Unknown argument: %s\n%s", p, usage); exit(1) ; } printf(nom_title, VERSION); /* Limits in RA and DEC can be ok */ if ((input_id == 0) && (limradec == 3)) { input_id = 3; the_center = (char *)0; } /* Define NOMAD from the program name */ if (!getenv("NOMADroot")) set_root(pgm); #if 0 if (pgm && (!getenv("NOMADroot"))) { a = malloc(12+strlen(pgm)) ; sprintf(a, "NOMADroot=%s", pgm) ; for (p = a + strlen(a) -1 ; (p>a) && (*p != '/'); p--) ; if (p>a) for (--p; (p>a) && (*p != '/'); p--) ; if ((strncmp(p, "/bin/", 5) == 0) ||(strncmp(p, "/src/", 5) == 0)) { *p = 0; putenv(a) ; } else free(a) ; } #endif /* Set up the check_fields */ for (f=thefields, i=0; f->name[0]; f++) { if (!f->selected) continue; check_fields[i++] = fc = f; /* dup_field(f); */ } /* Set up the array of results */ if (compare_fields[0]) arec = (LNOMAD *)malloc(mrec*sizeof(LNOMAD)) ; while (goon) { alarm(TIMEOUT); compare_calls = 0; if (whole_nomad) goon = 0 ; else if (the_center == line) { if (isatty(fileno(input_file))) printf("----Give %s: ", prompt[input_id]) ; if (!fgets(line, sizeof(line), input_file)) break ; p = line + strlen(line) ; while ((p>line) && (iscntrl(p[-1]))) p-- ; *p = 0 ; if (strncasecmp(line, "quit", 4) == 0) break ; if (ispunct(line[0])) { puts(line); continue ; } /* Could be a center, identifier, or Jname */ for (p=line; isspace(*p); p++) ; if (input_id&5) ; /* Must be USNO-ID */ else input_id = toupper(*p) == 'J' ? 2 : 0; } else goon = 0 ; irec = truncated = tested = matched = 0 ; if (whole_nomad) { printf("#NOMAD %s\n", "(whole)") ; puts(nomad_head(opted)) ; tested = nomad_pos((int4 *)0, (int4 *)0); } else switch(input_id) { case 1: /* Get from NOMAD-IDs */ nomad_options &= ~0x10 ; get_zID(the_center, thefields[1].lim); printf("#NOMAD %s\n", the_center) ; if (optE) printf("%s\n", optEmsg); puts(nomad_head(opted)) ; /* V1.32: thefields[1].lim[1]<0 => lower limit */ if (nomad_set(thefields[1].lim[0], ABS(thefields[1].lim[1])) == 0) tested = nomad_loop() ; break ; case 4: /* Get in Zone */ nomad_options &= ~0x10 ; printf("#NOMAD Zone %s\n", the_center) ; puts(nomad_head(opted)) ; if (nomad_zopen(atoi(the_center)) == 0) tested = nomad_loop() ; break ; case 0: /* Get from Center */ nomad_options &= ~0x10 ; if (compare_fields[0]) { if (((compare_fields[0])->name[0] == 'r') &&((compare_fields[0])->order > 0)) nomad_options |= 0x10 ; } if (get_center(the_center, center) < 0) continue ; printf("#Center: %s\n", the_center) ; /* v1.5: Verify RA/Dec in correct range */ if ((center[0]>=360.0) || (center[1]<-90.) || (center[1]>90.)) { printf("#***bad: %s\t***(center out of limits)\n", the_center); break; } if (optE) printf("%s\n", optEmsg); puts(nomad_head(opted)) ; tested = nomad_center(center) ; break; case 2: /* Jname (V1.1) */ /* match_Jname returns position and Jprec in mas */ if (match_Jname(the_center, Jpos, Jprec) < 0) continue; f = thefields+4; f->lim[0] = Jpos[0]; f->lim[1] = Jpos[0] + Jprec[0]-1; f->selected = 1; f++; /* f->limsd */ if (Jprec[1] > 0) { /* North */ f->lim[0] = adeg(90) + Jpos[1]; f->lim[1] = f->lim[0] + Jprec[1]-1; } else { /* South */ f->lim[1] = adeg(90) + Jpos[1]; f->lim[0] = f->lim[1] + (Jprec[1]+1); } f->selected = 1; nomad_options |= 0x10 ; printf("#Jname: %s\n", the_center) ; puts(nomad_head(opted)) ; tested = nomad_pos(thefields[4].lim, thefields[5].lim) ; break; case 3: /* Use RA+Dec Lim. */ nomad_options |= 0x10; printf("#Limits (mas) in RA[%d,%d] and SPD[%d,%d]\n", thefields[4].lim[0], thefields[4].lim[1], thefields[5].lim[0], thefields[5].lim[1]); if (optE) printf("%s\n", optEmsg); puts(nomad_head(opted)); tested = nomad_pos(thefields[4].lim, thefields[5].lim); break; } /*---- List saved records in order (replace backward by forward link) */ if (compare_fields[0]) { print_nodes(root); root = last = (LNOMAD *)0; } if (truncated) { printf("#+++Truncated to %d out of ", mrec) ; if (matched) printf("%d", matched) ; else printf("(not-computed)") ; printf(" matches (%d tested)\n", tested) ; } else printf("#--- %d matches (%d tested)\n", matched, tested); printf("#...sort required %d total comparisons\n", compare_calls); } nomad_close() ; exit(0); }