IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Apr 16, 2020, 2:04:27 PM (6 years ago)
Author:
tdeboer
Message:

quick undo

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Ohana/src/opihi/lib.shell/VectorIO.c

    r41340 r41341  
    22void gfits_compress_timing ();
    33 
     4static int VectorGetMaxStringLength (Vector *vec) {
     5
     6  int MaxLength = 0;
     7
     8  if (vec[0].type != OPIHI_STR) return 0;
     9
     10  for (int i = 0; i < vec[0].Nelements; i++) {
     11    MaxLength = MAX (MaxLength, strlen(vec[0].elements.Str[i]));
     12  }
     13  return MaxLength;
     14}
     15
    416// write a set of vectors to a FITS FTable structure (vectors names become fits column names)
    517static int WriteVectorTable (FTable *ftable, char *extname, Vector **vec, int Nvec, char *format, char nativeOrder) {
     
    719  int j;
    820
    9   char *tformat = NULL;
    10 
    1121  Header *theader = ftable->header;
    1222  gfits_create_table_header (theader, "BINTABLE", extname);
    1323
    14   ALLOCATE (tformat, char, 2*Nvec);
     24  // allocate an array of strings to represent the format for each output field
     25  // formats include single column formats (BIJKDE) and multi-column formats (e.g., 2I)
     26  // we will have no more than Nvec fields (but we can have fewer)
     27  int Nfield = 0;
     28  ALLOCATE_PTR (tformat, char *, Nvec);
     29  ALLOCATE_PTR (Nelement, int, Nvec);
     30
    1531  if (format) {
    16     // the bintable format string can only define the byte-width of each field.  valid output columns are currently:
     32    // the bintable format string can defines the byte-width of each field and number of elements (columns per field).
     33    // valid output columns are currently:
    1734    // B (char), I (16 bit short), J (32 bit int), E (32 bit float), D (64 bit double).
    18     // the format string is just the sequence of types, eg: LIIJEED
    19     // validate the format string
     35    // the format string is just the sequence of types, eg: LIIJEED.
     36    // it may have spaces or integer element counts:
     37    // "2D 4I EEJ"
     38
     39    // *** validate the format string
     40
     41    // as I parse each elements, if it is a digit, I need parse that value
     42
    2043    char *ptr = format;
    21     for (j = 0; j < Nvec; j++) {
     44    for (j = 0; j < Nvec; ) {
    2245      while (*ptr && OHANA_WHITESPACE (*ptr)) ptr++;
    2346      if (*ptr == 0) {
     
    2548        goto escape;
    2649      }
    27       if ((*ptr != 'B') && (*ptr != 'I') && (*ptr != 'J') && (*ptr != 'K') && (*ptr != 'D') && (*ptr != 'E')) {
     50
     51      // is there a leading integer?
     52      char *endptr;
     53      Nelement[Nfield] = strtol (ptr, &endptr, 10);
     54      if (endptr == ptr) {
     55        Nelement[Nfield] = 1;
     56      }
     57      ptr = endptr; // this should now point at the letter that is the format type
     58      if ((*ptr != 'B') && (*ptr != 'I') && (*ptr != 'J') && (*ptr != 'K') && (*ptr != 'D') && (*ptr != 'E') && (*ptr != 'A')) {
    2859        gprint (GP_ERR, "error in binary table format %s: invalid character %c\n", format, *ptr);
    2960        goto escape;
    3061      }
    31       tformat[2*j + 0] = *ptr;
    32       tformat[2*j + 1] = 0; // a bit sleazy : use a 2xN string to store N 1-byte strings
     62
     63      int Nchar = snprintf (tformat[Nfield], 0, "%d%c", Nelement[Nfield], *ptr);
     64      ALLOCATE (tformat[Nfield], char, Nchar + 1);
     65      int Nout = snprintf (tformat[Nfield], Nchar + 1, "%d%c", Nelement[Nfield], *ptr);
     66      myAssert (Nout <= Nchar, "oops");
     67
     68      // tformat[2*j + 0] = *ptr;
     69      // tformat[2*j + 1] = 0; // a bit sleazy : use a 2xN string to store N 1-byte strings
     70
     71      // For numeric multi-valued fields, the number of elements from the format defines the number of
     72      // vectors which go into that field.  For string-type vectors, the format specifies the maximum number of characters
     73      // that go into the field.
     74
     75      // for example, a format code of 3E should match a list of three numeric-type vectors while a format code of 15A should
     76      // match a single string-type vector which will supply up to 15 chars per row.
     77
     78      if (*ptr != 'A') {
     79        j += Nelement[Nfield]; // advance past Nelement vectors
     80      } else {
     81        if (vec[j][0].type != OPIHI_STR) {
     82          gprint (GP_ERR, "error in binary table format %s (mismatch between string format and numeric vector %s)\n", format, vec[j][0].name);
     83          goto escape;
     84        }
     85        j ++; // advance past a single string-type vector (validate that?)
     86      }
     87      if (j > Nvec) {
     88        gprint (GP_ERR, "error in binary table format %s (too few vectors for listed field)\n", format);
     89        goto escape;
     90      }
     91
    3392      ptr ++;
     93      Nfield ++;
    3494    }
    3595    while (*ptr && OHANA_WHITESPACE (*ptr)) ptr++;
     
    40100  } else {
    41101    for (j = 0; j < Nvec; j++) {
    42       // if the format is not defined, just use the native byte-widths
    43       tformat[2*j + 0] = (vec[j][0].type == OPIHI_FLT) ? 'D' : 'K'; // this depends on opihi_int == int64_t for Int
    44       tformat[2*j + 1] = 0;
    45     }
     102      switch (vec[j][0].type) {
     103        case OPIHI_FLT:
     104        case OPIHI_INT:
     105          // if the format is not defined, just use the native byte-widths
     106          ALLOCATE (tformat[j], char, 2);
     107          tformat[j][0] = (vec[j][0].type == OPIHI_FLT) ? 'D' : 'K';
     108          tformat[j][1] = 0;
     109          Nelement[j] = 1;
     110          break;
     111        case OPIHI_STR:
     112          // we need to examine the vector to determine the length
     113          Nelement[j] = VectorGetMaxStringLength(vec[j]);
     114          int Nchar = snprintf (tformat[j], 0, "%d%c", Nelement[j], 'A');
     115          ALLOCATE (tformat[j], char, Nchar + 1);
     116          int Nout = snprintf (tformat[j], Nchar + 1, "%d%c", Nelement[j], 'A');
     117          myAssert (Nout <= Nchar, "oops");
     118          break;
     119      }
     120    }
     121    Nfield = Nvec;
    46122  }
    47123
     
    49125  // output table (because the data goes to the named column below).  need to enforce
    50126  // this somehow
    51   for (j = 0; j < Nvec; j++) {
    52     gfits_define_bintable_column (theader, &tformat[2*j], vec[j][0].name, NULL, NULL, 1.0, 0.0);
     127  int ivec = 0;
     128  for (j = 0; j < Nfield; j++) {
     129    // XX need to loop over fields, and skip the additional vectors that are part of a field
     130    // this call supported multiple columns per named field
     131    gfits_define_bintable_column (theader, tformat[j], vec[ivec][0].name, NULL, NULL, 1.0, 0.0);
     132    if (vec[ivec][0].type == OPIHI_STR) {
     133      ivec ++;
     134    } else {
     135      ivec += Nelement[j];
     136    }
     137  }
     138
     139  // need to free the array
     140  for (j = 0; j < Nfield; j++) {
     141    free (tformat[j]);
    53142  }
    54143  free (tformat);
     
    57146  gfits_create_table (theader, ftable);
    58147
     148  // I need to add each vector in order, but I need to
     149  // track which field it corresponds to.
     150
    59151  // add the vectors to the output array
    60   for (j = 0; j < Nvec; j++) {
    61     if (vec[j][0].type == OPIHI_FLT) {
    62       gfits_set_bintable_column_reformat (theader, ftable, vec[j][0].name, "double",  vec[j][0].elements.Flt, vec[j][0].Nelements, nativeOrder);
     152  for (ivec = 0, j = 0; j < Nfield; j++) {
     153    // the first vector provides the name for the field
     154    char *fieldname = vec[ivec][0].name;
     155
     156    if (vec[ivec][0].type == OPIHI_STR) {
     157      // string-type vectors need to be copied into a contiguous buffer with the right dimensions:
     158      Vector *thisvec = vec[ivec];
     159
     160      ALLOCATE_PTR (strbuffer, char, Nelement[j]*thisvec->Nelements);
     161      for (int i = 0; i < thisvec->Nelements; i++) {
     162        int nChar = MIN (strlen (thisvec->elements.Str[i]), Nelement[j]);
     163        // fprintf (stderr, "%d %d %d : %d : %d : %s\n", ivec, j, i, Nelement[j], nChar, thisvec->elements.Str[i]);
     164        memcpy (&strbuffer[i*Nelement[j]], thisvec->elements.Str[i], nChar);
     165      }
     166      gfits_set_bintable_column (theader, ftable, fieldname, strbuffer, thisvec->Nelements);
     167      free (strbuffer);
     168      ivec ++;
    63169    } else {
    64 //    gfits_set_bintable_column_reformat (theader, ftable, vec[j][0].name, "int",     vec[j][0].elements.Int, vec[j][0].Nelements, nativeOrder);
    65       gfits_set_bintable_column_reformat (theader, ftable, vec[j][0].name, "int64_t", vec[j][0].elements.Int, vec[j][0].Nelements, nativeOrder);
     170      for (int k = 0; k < Nelement[j]; k++, ivec++) {
     171        Vector *thisvec = vec[ivec];
     172        switch (thisvec->type) {
     173          case OPIHI_FLT:
     174            gfits_set_bintable_column_reformat (theader, ftable, fieldname, "double",  thisvec->elements.Flt, thisvec->Nelements, k, nativeOrder);
     175            break;
     176          case OPIHI_INT:
     177            gfits_set_bintable_column_reformat (theader, ftable, fieldname, "int64_t", thisvec->elements.Int, thisvec->Nelements, k, nativeOrder);
     178            break;
     179        }
     180      }
    66181    }
    67182  }
     
    110225}
    111226
     227// insert a new header line, return end pointer
     228char *gfits_insert_header_line (Header *header, char *endptr, char *newline) {
     229
     230  if (0) {
     231    char temp1[32], temp2[32];
     232    memset (temp1, 0, 32);
     233    memset (temp2, 0, 32);
     234
     235    if (endptr) {
     236      memcpy (temp1, endptr, 8);
     237    }
     238    memcpy (temp2, newline, 8);
     239    fprintf (stderr, "insert: %s : %s\n", temp1, temp2);
     240  }
     241
     242  /* find the END of the header, if not supplied */
     243  if (!endptr) {
     244    endptr = gfits_header_field (header, "END", 1);
     245    if (endptr == NULL) return NULL;
     246  }
     247
     248  /* is there enough space for 1 more line? */
     249  if (header[0].datasize - (endptr - (header[0].buffer)) < 2*FT_LINE_LENGTH) {
     250    // no, so expand by a full header block (FT_RECORD_SIZE = 32*80 = 2880)
     251    header[0].datasize += FT_RECORD_SIZE;
     252    REALLOCATE (header[0].buffer, char, header[0].datasize);
     253    // re-find the "END" marker, in case new memory block is used
     254    endptr = gfits_header_field (header, "END", 1);
     255    if (endptr == NULL) return NULL;
     256    memset (endptr + FT_LINE_LENGTH, ' ', FT_RECORD_SIZE);
     257  }
     258
     259  /* push END line back 1 */
     260  memmove ((endptr + FT_LINE_LENGTH), endptr, FT_LINE_LENGTH);
     261  memset (endptr, ' ', FT_LINE_LENGTH);
     262
     263  strncpy (endptr, newline, 80);
     264  endptr += FT_LINE_LENGTH;
     265
     266  return endptr;
     267}
     268 
     269static char *rawkeywords[] = {"SIMPLE", "BITPIX", "NAXIS", "PCOUNT", "GCOUNT", "EXTEND", "EXTNAME", "BSCALE", "BZERO", "TFIELDS", "TFORM", "TZERO", "TSCAL", "        ", NULL};
     270
    112271// write a set of vectors to a FITS file (vectors names become fits column names)
    113 int WriteVectorTableFITS (char *filename, char *extname, Vector **vec, int Nvec, int append, char *compress, char *format, int Ntile) {
     272int WriteVectorTableFITS (char *filename, char *extname, Header *extraheader, Vector **vec, int Nvec, int append, char *compress, char *format, int Ntile) {
    114273 
    115274  Header rawheader;
     
    139298  rawtable.header = &rawheader;
    140299  if (!WriteVectorTable (&rawtable, extname, vec, Nvec, format, (compress != NULL))) goto escape;
    141   // NOTE : for compression, the table is constructed in native by order
     300  // NOTE : for compression, the table is constructed in native byte order
    142301
    143302  FTable *outtable = &rawtable;
     
    163322
    164323  if (!append) {
     324    // generate a blank PHU header
    165325    Header header;
    166326    Matrix matrix;
     
    176336  }
    177337
     338  if (extraheader) {
     339    // copy keywords which are not the standard or table keywords
     340    char *buf = extraheader->buffer;
     341    char *endptr = NULL;
     342    for (int i = 0; i < extraheader->datasize; i+= FT_LINE_LENGTH, buf += FT_LINE_LENGTH) {
     343
     344      if (0) {
     345        char temp1[32];
     346        memset (temp1, 0, 32);
     347        memcpy (temp1, buf, 8);
     348        fprintf (stderr, "buffer: %s\n", temp1);
     349      }
     350
     351      for (int j = 0; rawkeywords[j] != NULL; j++) {
     352        if (!strncmp (buf, rawkeywords[j], strlen(rawkeywords[j]))) goto skip_insert;
     353      }
     354      endptr = gfits_insert_header_line (outheader, endptr, buf);
     355      if (!endptr) {
     356        gprint (GP_ERR, "failed to update FITS header with extra keywords\n");
     357        return (FALSE);
     358      }
     359    skip_insert:
     360      continue;
     361    }
     362  }
     363
    178364  // write the actual table data
    179365  gfits_fwrite_Theader (f, outheader);
Note: See TracChangeset for help on using the changeset viewer.