Changeset 41341 for trunk/Ohana/src/opihi/lib.shell/VectorIO.c
- Timestamp:
- Apr 16, 2020, 2:04:27 PM (6 years ago)
- File:
-
- 1 edited
-
trunk/Ohana/src/opihi/lib.shell/VectorIO.c (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Ohana/src/opihi/lib.shell/VectorIO.c
r41340 r41341 2 2 void gfits_compress_timing (); 3 3 4 static 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 4 16 // write a set of vectors to a FITS FTable structure (vectors names become fits column names) 5 17 static int WriteVectorTable (FTable *ftable, char *extname, Vector **vec, int Nvec, char *format, char nativeOrder) { … … 7 19 int j; 8 20 9 char *tformat = NULL;10 11 21 Header *theader = ftable->header; 12 22 gfits_create_table_header (theader, "BINTABLE", extname); 13 23 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 15 31 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: 17 34 // 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 20 43 char *ptr = format; 21 for (j = 0; j < Nvec; j++) {44 for (j = 0; j < Nvec; ) { 22 45 while (*ptr && OHANA_WHITESPACE (*ptr)) ptr++; 23 46 if (*ptr == 0) { … … 25 48 goto escape; 26 49 } 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')) { 28 59 gprint (GP_ERR, "error in binary table format %s: invalid character %c\n", format, *ptr); 29 60 goto escape; 30 61 } 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 33 92 ptr ++; 93 Nfield ++; 34 94 } 35 95 while (*ptr && OHANA_WHITESPACE (*ptr)) ptr++; … … 40 100 } else { 41 101 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; 46 122 } 47 123 … … 49 125 // output table (because the data goes to the named column below). need to enforce 50 126 // 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]); 53 142 } 54 143 free (tformat); … … 57 146 gfits_create_table (theader, ftable); 58 147 148 // I need to add each vector in order, but I need to 149 // track which field it corresponds to. 150 59 151 // 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 ++; 63 169 } 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 } 66 181 } 67 182 } … … 110 225 } 111 226 227 // insert a new header line, return end pointer 228 char *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 269 static char *rawkeywords[] = {"SIMPLE", "BITPIX", "NAXIS", "PCOUNT", "GCOUNT", "EXTEND", "EXTNAME", "BSCALE", "BZERO", "TFIELDS", "TFORM", "TZERO", "TSCAL", " ", NULL}; 270 112 271 // 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) {272 int WriteVectorTableFITS (char *filename, char *extname, Header *extraheader, Vector **vec, int Nvec, int append, char *compress, char *format, int Ntile) { 114 273 115 274 Header rawheader; … … 139 298 rawtable.header = &rawheader; 140 299 if (!WriteVectorTable (&rawtable, extname, vec, Nvec, format, (compress != NULL))) goto escape; 141 // NOTE : for compression, the table is constructed in native by order300 // NOTE : for compression, the table is constructed in native byte order 142 301 143 302 FTable *outtable = &rawtable; … … 163 322 164 323 if (!append) { 324 // generate a blank PHU header 165 325 Header header; 166 326 Matrix matrix; … … 176 336 } 177 337 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 178 364 // write the actual table data 179 365 gfits_fwrite_Theader (f, outheader);
Note:
See TracChangeset
for help on using the changeset viewer.
