예제 #1
0
double smf_map_getpixsize( const smfData *data, int *status ) {

  double at[3]={0,0,0};         /* Grid coords. where we check the scale */
  int naxes;                    /* Number of axes */
  double pixsize=VAL__BADD;     /* The pixel size */
  double pixscl[3];

  if( *status != SAI__OK ) return pixsize;

  if( !data ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": NULL smfData supplied", status );
    return pixsize;
  }

  if( !data->hdr || !data->hdr->wcs ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": no header, or missing WCS", status );
    return pixsize;
  }

  /* Check number of axes in the frameset. It will usually be 3 because
     we have a frequency axis of length 1 for normal SMURF maps */
  naxes = astGetI( data->hdr->wcs, "naxes" );
  if( (naxes < 2) || (naxes > 3) ) {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME
            ": Frameset does not appear to corresond to a 2-d map", status );
    return pixsize;
  }

  /* Take the average of the x- and y-pixel spacings in radians at the
     centre of the map, and then convert to arcsec */

  at[0] = -(data->lbnd[0]-1);
  at[1] = -(data->lbnd[1]-1);

  kpgPixsc( data->hdr->wcs, at, pixscl, NULL, NULL, 0, status );
  if( *status == SAI__OK ) {
    pixsize = (pixscl[0] + pixscl[1])/2.;
    pixsize *= DR2AS;

    msgOutiff( MSG__DEBUG, "", FUNC_NAME
               ": determined pixel size from WCS at map coordinates (%g,%g) "
               "to be %g arcsec", status, at[0], at[1], pixsize );
  } else {
    *status = SAI__ERROR;
    errRep( "", FUNC_NAME ": could not determine pixel size from WCS", status );
  }


  return pixsize;
}
예제 #2
0
static void
smf__fits_copy_items( AstFitsChan * fromfits, AstFitsChan * tofits,
                      const char ** items, int * status ) {
  size_t i = 0;
  double value;

  if (*status != SAI__OK) return;

  while ( items[i] != NULL ) {
    char card[ 81 ];

    /* reset the position each time since we can not be sure that
       "items" is in order */
    astClear( fromfits, "Card" );

    /* Look in fromfits for the card */
    if ( astFindFits( fromfits, items[i], card, 0  ) ) {

      /* now look in tofits for the card */
      astClear( tofits, "Card" );
      if ( astFindFits( tofits, items[i], NULL, 0 ) ) {
        /* and if we find it replace it */
        if (astGetI(fromfits, "CardType") == AST__FLOAT
            && astGetFitsF(fromfits, NULL, &value)) {
          astSetFitsF(tofits, items[i], value, NULL, 1);
        }
        else {
          astPutFits( tofits, card, 1 );
        }
      }
    }

    i++;
  }

}
예제 #3
0
int *smf_jsatiles_region( AstRegion *region, smfJSATiling *skytiling,
                          int *ntile, int *status ){

/* Local Variables */
   AstFrameSet *fs;
   AstKeyMap *km;
   AstRegion *region2;
   AstRegion *space_region;
   AstRegion *tregion;
   AstSkyFrame *skyframe;
   char text[ 200 ];
   const char *key;
   double *mesh = NULL;
   double *xmesh;
   double *ymesh;
   int *tiles = NULL;
   int axes[ 2 ];
   int i;
   int ineb;
   int itile2;
   int itile;
   int ix;
   int iy;
   int key_index;
   int lbnd[ 2 ];
   int mapsize;
   int npoint;
   int old_sv;
   int overlap;
   int ubnd[ 2 ];
   int value;
   int xoff[ 4 ] = { -1, 0, 1, 0 };
   int xt;
   int yoff[ 4 ] = { 0, 1, 0, -1 };
   int yt;

/* Initialise */
   *ntile = 0;

/* Check inherited status */
   if( *status != SAI__OK ) return tiles;

/* Start an AST context so that all AST objects created in this function
   are annulled automatically. */
   astBegin;

/* Identify the celestial axes in the Region. */
   atlFindSky( (AstFrame *) region, &skyframe, axes + 1, axes, status );

/* Report an error if no celestial axes were found. */
   if( !skyframe && *status == SAI__OK ) {
      space_region = NULL;
      *status = SAI__ERROR;
      errRep( "", "The current WCS Frame in the supplied Region or "
              "NDF does not include celestial longitude and latitude axes.",
              status );

/* Otherwise, if the Region itself is 2-dimensional, it does not contain
   any other axes, so just use it as is. */
   } else if( astGetI( region, "Naxes" ) == 2 ) {
      space_region = astClone( region );

/* Otherwise, create a new Region by picking the celestial axes from the
   supplied Region. Report an error if a Region cannot be created in this
   way. */
   } else {
      space_region = astPickAxes( region, 2, axes, NULL );
      if( !astIsARegion( space_region ) && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRep( "", "The  celestial longitude and latitude axes in the "
                 "supplied Region or NDF are not independent of the other "
                 "axes.", status );
      }
   }

/* Create a FrameSet describing the whole sky in which each pixel
   corresponds to a single tile in SMF__JSA_HPX projection. The current
   Frame is ICRS (RA,Dec) and the base Frame is grid coords in which each
   grid pixel corresponds to a single tile. */
   smf_jsatile( -1, skytiling, 0, SMF__JSA_HPX, NULL, &fs, NULL, lbnd, ubnd,
                status );

/* Map the Region using the FrameSet obtained above so that the new Region
   describes offsets in tiles from the lower left tile. If "space_region"
   is a Polygon, ensure that the SimpVertices attribute is set so that the
   simplify method will take non-linearities into account (such as the
   region being split by the RA=12h meridian). */
   astInvert( fs );
   fs = astConvert( space_region, fs, "SKY" );
   if( !fs && *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "Cannot convert the supplied Region to ICRS.", status );
      goto L999;
   }

   old_sv = -999;
   if( astIsAPolygon( space_region ) ){
      if( astTest( space_region, "SimpVertices" ) ) {
         old_sv = astGetI( space_region, "SimpVertices" );
      }
      astSetI( space_region, "SimpVertices", 0 );
   }

   region2 = astMapRegion( space_region, fs, fs );

   if( astIsAPolygon( space_region ) ){
      if( old_sv == -999 ) {
         astClear( space_region, "SimpVertices" );
      } else {
         astSetI( space_region, "SimpVertices", old_sv );
      }
   }

/* Get a mesh of all-sky "grid" positions (actually tile X and Y indices)
   covering the region. Since the mesh positions are limited in number
   and placed arbitrarily within the Region, the mesh will identify some,
   but potentially not all, of the tiles that overlap the Region. */
   astGetRegionMesh( region2, 0, 0, 2, &npoint, NULL );
   mesh = astMalloc( 2*npoint*sizeof( *mesh ) );
   astGetRegionMesh( region2, 0, npoint, 2, &npoint, mesh );

/* Find the index of the tile containing each mesh position, and store
   them in a KeyMap using the tile index as the key and "1" (indicating
   the tile overlaps the region) as the value. The KeyMap is sorted by
   age of entry. Neighbouring tiles will be added to this KeyMap later.
   If an entry has a value of zero, it means the tile does not overlap
   the supplied Region. If the value is positive, it means the tile
   does overlap the supplied Region. If the value is negative, it means
   the tile has not yet been tested to see if it overlaps the supplied
   Region. */
   km = astKeyMap( "SortBy=KeyAgeDown" );
   xmesh = mesh;
   ymesh = mesh + npoint;
   for( i = 0; i < npoint && *status == SAI__OK; i++ ) {
      ix = (int)( *(xmesh++) + 0.5 ) - 1;
      iy = (int)( *(ymesh++) + 0.5 ) - 1;
      itile = smf_jsatilexy2i( ix, iy, skytiling, status );
      if (itile != VAL__BADI) {
         sprintf( text, "%d", itile );
         astMapPut0I( km, text, 1, NULL );
      }
   }

/* Starting with the oldest entry in the KeyMap, loop round checking all
   entries, in the order they were added, until all have been checked.
   Checking an entry may cause further entries to be added to the end of
   the KeyMap. */
   key_index = 0;
   mapsize = astMapSize( km );
   while( key_index < mapsize && *status == SAI__OK ) {
      key = astMapKey( km, key_index++ );

/* Convert the key string to an integer tile index. */
      itile = atoi( key );

/* Get the integer value associated with the tile. */
      astMapGet0I( km, key, &value );

/* If the tile associated with the current KeyMap entry has not yet been
   tested for overlap with the requested Region (as shown by the entry
   value being -1), test it now. */
      if( value == -1 ) {

/* Get a Region covering the tile. */
         smf_jsatile( itile, skytiling, 0, SMF__JSA_HPX, NULL, NULL, &tregion,
                      lbnd, ubnd, status );

/* See if this Region overlaps the user supplied region. Set the value of
   the KeyMap entry to +1 or 0 accordingly. */
         overlap = astOverlap( tregion, space_region );
         if( overlap == 0 ) {
            if( *status == SAI__OK ) {
               *status = SAI__ERROR;
               errRep( "", "Cannot align supplied Region with the sky "
                       "tile coordinate system (programming error).",
                       status );
            }
         } else if( overlap == 1 || overlap == 6 ) {
            value = 0;
         } else {
            value = 1;
         }
         astMapPut0I( km, key, value, NULL );
      }

/* Skip the current KeyMap entry if the corresponding tile does not
   overlap the requested Region (as shown by the entry value being zero). */
      if( value == 1 ) {

/* The current tile overlaps the supplied Region, so add the tile index to
   the returned list of tile indices. */
         tiles = astGrow( tiles, ++(*ntile), sizeof( *tiles ) );
         if( *status == SAI__OK ) {
            tiles[ *ntile - 1 ] = itile;

/* Add the adjoining tiles to the end of the KeyMap so that they will be
   tested in their turn, giving them a value of -1 to indicate that they
   have not yet been tested to see if they overlap the supplied Region.
   Ignore adjoining tiles that are already in the keyMap. */
            smf_jsatilei2xy( itile, skytiling, &xt, &yt, NULL, status );
            for( ineb = 0; ineb < 4; ineb++ ) {
               itile2 = smf_jsatilexy2i( xt + xoff[ ineb ], yt + yoff[ ineb ],
                                         skytiling, status );
               if( itile2 != VAL__BADI ) {
                  sprintf( text, "%d", itile2 );
                  if( !astMapHasKey( km, text ) ) {
                     astMapPut0I( km, text, -1, NULL );
                     mapsize++;
                  }
               }
            }
         }
      }
   }

/* Arrive here if an error occurs. */
   L999:;

/* Free resources. */
   mesh = astFree( mesh );

   if( *status != SAI__OK ) {
      tiles = astFree( tiles );
      *ntile = 0;
   }

   astEnd;

   return tiles;
}
예제 #4
0
void smf_fits_export2DA ( AstFitsChan *fitschan, size_t *ncards,
                          char *fitsrec,
                          int *status ) {

  /* Local variables */
  char blank[SZFITSCARD+1];/* Reference blank card */
  char card[SZFITSCARD+1];/* temporary buffer for current card */
  int found;              /* Boolean to indicate if a card was found */
  size_t i;               /* Loop counter */
  size_t ncopied = 0;     /* How many cards were copied */
  size_t numcards = 0;    /* How many cards are in the FitsChan */
  char *outpos = NULL;    /* current position in output buffer */
  int prevblank = 0;      /* Was this previously blank? */
  char *tempfits = NULL;  /* intermediate buffer for FITS cards */

  *ncards = 0;
  /* Check status */
  if (*status != SAI__OK) return;

  /* Fill the blank card */
  for (i=0; i<SZFITSCARD;i++) {
    blank[i] = ' ';
  }
  blank[SZFITSCARD] = '\0';

  /* Find the number of cards in this AstFitsChan and create a
     buffer for internal use. We do not yet worry about the allocated
     size of fitsrec because we might be compressing the array to
     get rid of multiple blank lines */
  numcards = astGetI ( fitschan, "Ncard" );
  tempfits = astMalloc( ( 1 + numcards * SZFITSCARD ) * sizeof(*tempfits) );

   /* Rewind */
   astClear ( fitschan, "Card");

   if (*status == SAI__OK) {
     /* Retrieve all the FITS headers and store them in the character array.
        We compress consecutive blank cards. */
     ncopied = 0;
     outpos = tempfits;
     prevblank = 0;
     for ( i = 0; i <= numcards; i++ ) {
       found = astFindFits ( fitschan, "%f", card, 1 );
       if ( found ) {
         int isblank = 0;
         if (strncmp( card, blank, SZFITSCARD ) == 0 ) isblank = 1;

         /* skip if this is blank and before was */
         if (isblank && prevblank) continue;
         prevblank = isblank;

         /* Now copy in the card and increment the pointer */
         strncpy ( outpos, card, SZFITSCARD );
         ncopied++;
         outpos += SZFITSCARD;
       } else {
         break;
       }
     }

     /* Guarantee to terminate the buffer */
     *outpos = '\0';

     /* make sure that it is no larger than the maximum allowed */
     if ( ncopied > SC2STORE__MAXFITS ) {
       *status = SAI__ERROR;
       msgSeti("NC", (int)numcards);
       msgSeti("MC", SC2STORE__MAXFITS);
       errRep( FUNC_NAME,
               "Number of FITS cards ^NC exceeds maximum allowed (^MC)",
               status );
       tempfits = astFree( tempfits );
       return;
     }

     /* Copy into the output buffer */
     one_strlcpy( fitsrec, tempfits, SZFITSCARD * SC2STORE__MAXFITS + 1, status );
   }

   tempfits = astFree(tempfits);
   *ncards = ncopied;
}
예제 #5
0
static AstTable *ReadNextTable( FILE *fd, const char *fname, int *iline,
                                int *status ) {
    /*
    *  Name:
    *     ReadOneTable

    *  Purpose:
    *     Reads a single Table from a text file.

    *  Description:
    *     This function reads text from the supplied file descriptor until it
    *     reaches the end of file or encounters an end-of-table marker (a line
    *     consisting just of two or more minus signs with no leading spaces).
    *     It creates an AstTable from the text and returns a pointer to it.

    *  Arguments:
    *     fd
    *        The file descriptor.
    *     fname
    *        The file name - used for error messages.
    *     iline
    *        Pointer to an int holding the number of lines read from the
    *        file so far. Updated on exit to include the lines read by the
    *        invocation of this function.
    *     status
    *        Pointer to the global status variable.

    *  Returned Value:
    *     A pointer to the Table read from the file, or NULL if an error occurs.

    */

    /* Local Variables: */
    AstTable *result;
    AstTable *subtable;
    char **cols;
    char **words;
    char *last_com;
    char *line;
    char *p;
    char *tname;
    char key[ 200 ];
    const char *cval;
    const char *oldname;
    const char *newname;
    double dval;
    int *types;
    int blank;
    int c;
    int com;
    int eot;
    int first;
    int icol;
    int irow;
    int ival;
    int iword;
    int line_len;
    int max_line_len;
    int more;
    int nc;
    int ncol;
    int nrow;
    int nword;
    int skip;
    size_t len;

    /* Initialise */
    result = NULL;

    /* Check the inherited status. */
    if( *status != SAI__OK ) return result;

    /* Create an empty Table. */
    result = astTable( " " );

    /* Allocate a buffer for one one line of text. This will be increased in
       size as required. */
    max_line_len = 80;
    line = astMalloc( max_line_len*sizeof( *line ) );

    /* Read each line of text from the file. */
    eot = 0;
    skip = 1;
    line_len = 0;
    more = 1;
    last_com = NULL;
    cols = NULL;
    first = 1;
    irow = 0;
    types = NULL;

    while( more && *status == SAI__OK ) {
        (*iline)++;
        line_len = 0;

        /* Loop reading characters from the file until a newline or the end of file is
           reached. */
        while( ( c = fgetc( fd ) ) != EOF && c != '\n' ) {

            /* Increment the current line length, and double the size of the line buffer
               if it is full. */
            if( ++line_len >= max_line_len ) {
                max_line_len *= 2;
                line = astRealloc( line, max_line_len*sizeof( *line ) );
                if( *status != SAI__OK ) break;
            }

            /* Store the character. Ignore leading white space. */
            if( skip ) {
                if( ! isspace( c ) ) {
                    line[ line_len - 1 ] = c;
                    skip = 0;
                } else {
                    line_len--;
                }
            } else {
                line[ line_len - 1 ] = c;
            }

        }

        /* If the end-of-file was reached indicate that we should leave the main
           loop after processing the current line. */
        if( c == EOF ) more = 0;

        /* Terminate the line. */
        line[ line_len ] = 0;

        /* Terminate it again to exclude trailing white space. */
        line[ astChrLen( line ) ] = 0;

        /* Assume the line is a blank non-comment, and store a pointer to the first
           character to use. */
        blank = 1;
        com = 0;
        p = line;

        /* Skip blank lines. */
        if( line[ 0 ] ) {

            /* If the line starts with a comment character... */
            if( line[ 0 ] == '#' || line[ 0 ] == '!' ) {
                com = 1;

                /* Get a pointer to the first non-space/tab character after the comment
                   character. */
                p = line + 1;
                while( *p == ' ' || *p == '\t' ) p++;

                /* Note if it is blank. */
                if( *p ) blank = 0;

                /* If it is not a comment line, then the line is not blank. */
            } else {
                blank = 0;

                /* See if it is the end-of-table marker - a line containing just two or
                   more minus signs with no leading spaces. */
                eot = ( strspn( line, "-" ) > 1 );
            }
        }

        /* Skip blank lines, whether comment or not. */
        if( ! blank ) {

            /* First handle comment lines. */
            if( com ) {

                /* Does it look like a  parameter assignment... */
                words = astChrSplitRE( p, "^\\s*(\\w+)\\s*=\\s*(.*)$", &nword, NULL );
                if( words ) {

                    /* Add a parameter declaration to the Table. */
                    astAddParameter( result, words[ 0 ] );

                    /* Store the parameter value, using an appropriate data type. */
                    len = strlen( words[ 1 ] );
                    if( nc = 0, ( 1 == astSscanf( words[ 1 ], "%d%n", &ival, &nc ) )
                            && ( nc >= len ) ) {
                        astMapPut0I( result, words[ 0 ], ival, NULL );

                    } else if( nc = 0, ( 1 == astSscanf( words[ 1 ], "%lg%n", &dval, &nc ) )
                               && ( nc >= len ) ) {
                        astMapPut0D( result, words[ 0 ], dval, NULL );

                    } else {
                        astMapPut0C( result, words[ 0 ], words[ 1 ], NULL );

                    }

                    /* Free the words returned by astChrSplitRE. */
                    for( iword = 0; iword < nword; iword++ ) {
                        words[ iword ] = astFree( words[ iword ] );
                    }
                    words = astFree( words );

                    /* If it does not look like a parameter assignment... */
                } else {

                    /* Save a copy of it in case it turns out to be the last non-blank comment
                       line before the first row of data values (in which case it should
                       contain the column names). */
                    last_com = astStore( last_com, p, strlen( p ) + 1 );
                }

                /* If the line is not a comment see if it is an end of table marker. If so
                   indicate that we should leave the loop. */
            } else if( eot ) {
                more = 0;

                /* If the line is not a comment or an end of table marker ... */
            } else {

                /* Get the words from the row. */
                words = astChrSplit( p, &nword );

                /* If this is the first non-blank non-comment line, get the column names from
                   the previous non-blank comment line. */
                if( first ) {
                    if( last_com ) {
                        first = 0;
                        cols = astChrSplit( last_com, &ncol );

                        /* Create an array to hold the data type for each colum, and initialise
                           them to "integer". */
                        types = astMalloc( ncol*sizeof( int ) ) ;
                        for( iword = 0; iword < nword && astOK; iword++ ) {
                            if( iword < ncol ) {
                                types[ iword ] = AST__INTTYPE;

                                /* The columns are stored initially using interim names which have "T_"
                                   prepended to the names given in the file. */
                                tname = NULL;
                                nc = 0;
                                tname = astAppendString( tname, &nc, "T_" );
                                tname = astAppendString( tname, &nc, cols[ iword ] );
                                astFree( cols[ iword ] );
                                cols[ iword ] = tname;

                                /* Create the column definition within the returned Table. We store them
                                   initially as strings and then convert to the appropriate column data type
                                   later (once all rows have been read and the the data types are known). */
                                astAddColumn( result, cols[ iword ], AST__STRINGTYPE,
                                              0, NULL, " " );
                            }
                        }

                    } else if( *status == SAI__OK ) {
                        *status = SAI__ERROR;
                        msgSetc( "F", fname );
                        errRep( " ", "No column headers found in file ^F.", status );
                    }
                }

                /* Report an error if the line has the wrong number of values. */
                if( nword != ncol ) {
                    if( *status == SAI__OK ) {
                        *status = SAI__ERROR;
                        msgSeti( "N", nword );
                        msgSeti( "I", (*iline) );
                        msgSeti( "M", ncol );
                        msgSetc( "F", fname );
                        errRep( " ", "Wrong number of values (^N) at line ^I in "
                                "file ^F (should be ^M).", status );
                    }

                    /* Otherwise increment the number of rows read. */
                } else {
                    irow++;

                    /* Store each string value in the table, excluding "null" strings. Also check
                       the data type of each string an dupdate the column data types if necessary. */
                    for( iword = 0; iword < nword && *status == SAI__OK; iword++ ) {
                        if( strcmp( words[ iword ], "null" ) ) {
                            sprintf( key, "%s(%d)", cols[ iword ], irow );
                            astMapPut0C( result, key, words[ iword ], NULL );

                            /* If the column is currently thought to hold integers, check that the
                               current word looks like an integer. If not, down-grade the column type
                               to double. */
                            len = strlen( words[ iword ] );
                            if( types[ iword ] == AST__INTTYPE ) {
                                if( nc = 0, ( 1 != astSscanf( words[ iword ], "%d%n",
                                                              &ival, &nc ) ) ||
                                        ( nc < len ) ) {
                                    types[ iword ] = AST__DOUBLETYPE;
                                }
                            }

                            /* If the column is currently thought to hold doubles, check that the
                               current word looks like an doubler. If not, down-grade the column type
                               to string. */
                            if( types[ iword ] == AST__DOUBLETYPE ) {
                                if( nc = 0, ( 1 != astSscanf( words[ iword ], "%lg%n",
                                                              &dval, &nc ) ) ||
                                        ( nc < len ) ) {
                                    types[ iword ] = AST__STRINGTYPE;
                                }
                            }
                        }
                    }
                }

                /* Free the words returned by astChrSplit. */
                for( iword = 0; iword < nword; iword++ ) {
                    words[ iword ] = astFree( words[ iword ] );
                }
                words = astFree( words );

            }
        }
    }

    /* The entire file has now been read, and a Table created in which every
       column holds strings. We also have flags indicating whether the values
       in each column are all integers or doubles. Modify the type of the
       column within the Table to match these flags. */
    nrow = astGetI( result, "Nrow" );
    for( icol = 0; icol < ncol && *status == SAI__OK; icol++ ) {

        /* The column will be re-named from "T_<name>" to "<name>". */
        oldname = cols[ icol ];
        newname = oldname + 2;

        /* First convert string columns to integer columns if all the values in
           the column look like integers. */
        if( types[ icol ] == AST__INTTYPE ) {

            /* Create the new column */
            astAddColumn( result, newname, AST__INTTYPE, 0, NULL, " " );

            /* Copy each cell of the current column, converting from string to integer. */
            for( irow = 1; irow <= nrow; irow++ ) {
                sprintf( key, "%s(%d)", oldname, irow );
                if( astMapGet0I( result, key, &ival ) ) {
                    sprintf( key, "%s(%d)", newname, irow );
                    astMapPut0I( result, key, ival, NULL );
                }
            }

            /* Now do double columns in the same way. */
        } else if( types[ icol ] == AST__DOUBLETYPE ) {
            astAddColumn( result, newname, AST__DOUBLETYPE, 0, NULL, " " );
            for( irow = 1; irow <= nrow; irow++ ) {
                sprintf( key, "%s(%d)", oldname, irow );
                if( astMapGet0D( result, key, &dval ) ) {
                    sprintf( key, "%s(%d)", newname, irow );
                    astMapPut0D( result, key, dval, NULL );
                }
            }

            /* Copy string values without change. */
        } else {
            astAddColumn( result, newname, AST__STRINGTYPE, 0, NULL, " " );
            for( irow = 1; irow <= nrow; irow++ ) {
                sprintf( key, "%s(%d)", oldname, irow );
                if( astMapGet0C( result, key, &cval ) ) {
                    sprintf( key, "%s(%d)", newname, irow );
                    astMapPut0C( result, key, cval, NULL );
                }
            }
        }

        /* Remove the old column. */
        astRemoveColumn( result, oldname );

    }

    /* Free resources. */
    line = astFree( line );
    last_com = astFree( last_com );
    types = astFree( types );
    if( cols ) {
        for( icol = 0; icol < ncol; icol++ ) {
            cols[ icol ] = astFree( cols[ icol ] );
        }
        cols = astFree( cols );
    }

    /* If the table ended with an end-of-table marker, there may be another
       Table in the file. Call this function recursively to read it. */
    if( eot ) {
        subtable = ReadNextTable( fd, fname, iline, status );

        /* Store the subtable as a table parameter in the returned table. */
        if( subtable ) {
            astAddParameter( result, "SubTable" );
            astMapPut0A( result, "SubTable", subtable, NULL );

            /* The Table clones the pointer, so we must annull our local copy of it. */
            subtable = astAnnul( subtable );
        }
    }

    /* Return the Table pointer. */
    return result;
}
예제 #6
0
void smurf_jsatilelist( int *status ) {

/* Local Variables */
   AstFitsChan *fc = NULL;
   AstFrameSet *fs = NULL;
   AstObject *obj;
   AstRegion *region;
   Grp *igrp = NULL;
   Grp *sgrp = NULL;
   double vertex_data[ 2*MAXVERT ];
   int *tiles = NULL;
   int i;
   int indf;
   int lbnd[2];
   int ntile;
   int nvert_dec;
   int nvert_ra;
   int ubnd[2];
   size_t size;
   size_t ssize;
   smfJSATiling tiling;

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Start a new AST context. */
   astBegin;

/* Attempt to to get an AST Region. */
   kpg1Gtobj( "IN", "Region",
              (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion),
              &obj, status );
   region = (AstRegion *) obj;

/* If successful, attempt to access the IN parameter as an NDF. If this
   works, we may be able to determine the instrument by looking at its
   FITS extension. */
   if( *status == SAI__OK && region ) {
      ndfExist( "IN", "Read", &indf, status );

/* If we got an NDF, get a FitsChan holding the contents of its FITS
   extension. Annul the error if the NDF has no FITS extension. */
      if( indf != NDF__NOID ) {
         kpgGtfts( indf, &fc, status );
         if( *status == KPG__NOFTS ) {
            errAnnul( status );
            fc = NULL;
         }
         ndfAnnul( &indf, status );
      }

/* Select a JSA instrument and get the parameters defining the layout of
   tiles for the selected instrument. */
      smf_jsainstrument( "INSTRUMENT", fc, SMF__INST_NONE, &tiling,
                         status );

/* Get the list of identifiers for tiles that overlap the region. */
      tiles = smf_jsatiles_region( region, &tiling, &ntile, status );

/* If a null value was supplied for IN, attempt to get the positions of
   vertices on the sky to define the region. */
   } else if( *status == PAR__NULL ) {
      errAnnul( status );
      parGet1d( "VERTEX_RA", MAXVERT, vertex_data, &nvert_ra, status );
      parGet1d( "VERTEX_DEC", MAXVERT, vertex_data + MAXVERT, &nvert_dec,
                 status );
      if( nvert_ra != nvert_dec && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( "", "Differing numbers of RA (%d) and Dec (%d) vertex values "
                 "supplied.", status, nvert_ra, nvert_dec );
      }

/* Convert from degrees to radians. */
      for( i = 0; i < nvert_ra; i++ ) {
         vertex_data[ i ] *= AST__DD2R;
         vertex_data[ MAXVERT + i ] *= AST__DD2R;
      }

/* Select a JSA instrument and get the parameters defining the layout of
   tiles for the selected instrument. */
      smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &tiling,
                         status );

/* Create a frame in which to define the region - we arbitrarily use tile 1. */
      smf_jsatile( 1, &tiling, 0, NULL, &fs, NULL, lbnd, ubnd, status );

/* Create the region. */
      region = (AstRegion *) astPolygon( fs, nvert_ra, MAXVERT, vertex_data, NULL, " " );

/* If the region is unbounded, it is probably because the vertices were
   given in the wrong order. Invert the Polyfon to correct this. */
      if( !astGetI( region, "bounded" ) ) astNegate( region );

/* Get the list of identifiers for tiles that overlap the region. */
      tiles = smf_jsatiles_region( region, &tiling, &ntile, status );
   }

/* If the IN parameter could not be accessed as a Region, annull any error
   and get a group of input data files. */
   if( !region || *status == SAI__ERROR ) {
      if( *status != SAI__OK ) errAnnul( status );
      kpg1Rgndf( "IN", 0, 1, "", &igrp, &size, status );

/* Get a group containing just the files holding science data. */
      smf_find_science( NULL, igrp, &sgrp, 0, NULL, NULL, 1, 1, SMF__NULL, NULL,
                        NULL, NULL, NULL, status );

/* Check we have at least once science file. */
      ssize = grpGrpsz( sgrp, status );
      if( ssize == 0 ) {
         msgOutif( MSG__NORM, " ", "None of the supplied input frames were SCIENCE.",
                   status );

/* Get the list of identifiers for tiles that receive any data. */
      } else {
         tiles = smf_jsatiles_data( sgrp, ssize, &tiling, &ntile, status );
      }

/* Delete the groups. */
      if( igrp ) grpDelet( &igrp, status);
      if( sgrp ) grpDelet( &sgrp, status);
   }

/* Sort the list of overlapping tiles into ascending order. */
   if( *status == SAI__OK ) {
      qsort( tiles, ntile, sizeof( *tiles ), jsatilelist_icomp );

/* Display the list of overlapping tiles. */
      msgBlank( status );
      msgOutf( "", "   %s tiles touched by supplied data:", status,
               tiling.name );
      msgBlank( status );
      for( i = 0; i < ntile; i++ ) {
         msgSeti( "I", tiles[ i ] );
         msgOut( "", "   ^I", status );
      }
      msgBlank( status );

/* Write out the list of overlapping tiles to the output parameter. */
      parPut1i( "TILES", ntile, tiles, status );
   }

/* Free resources. */
   tiles = astFree( tiles );

/* End the AST context. */
   astEnd;

/* Issue a status indication.*/
   msgBlank( status );
   if( *status == SAI__OK ) {
      msgOutif( MSG__VERB, "", "JSATILELIST succeeded.", status);
   } else {
      msgOutif( MSG__VERB, "", "JSATILELIST failed.", status);
   }
}
예제 #7
0
int main( int argc, char **argv ){

/* Local variables: */
   AstBox *pixbox;
   AstFitsChan *fchan;
   AstFrame *pixfrm;
   AstFrame *wcsfrm;
   AstFrameSet *frameset;
   AstKeyMap *warnings;
   AstMapping *pix2wcs;
   AstObject *object;
   AstRegion *wcsbox;
   AstStcsChan *schan;
   FILE *fd;
   char key[ 15 ];
   char keyword[ 9 ];
   const char *message;
   double p1[ MAX_AXES ];
   double p2[ MAX_AXES ];
   int axis;
   int iwarn;
   int naxis;
   int status;

/* Initialised the returned system status to indicate success. */
   status = 0;

/* Check a file was specified on the command line, and attempt to open it
   for read access. */
   if( argc < 2 ) {
      printf( "Usage: stcschan-demo2 <header-file>\n" );
      status = 1;
   } else {
      fd = fopen( argv[ 1 ], "r" );
      if( !fd ) {
         printf("Failed to open input file '%s'.\n", argv[ 1 ] );
         status = 1;
      }
   }

/* If a disk file was opened successfully... */
   if( !status ) {

/* Start an AST object context. This means we do not need to annull
   each AST Object individually. Instead, all Objects created within
   this context will be annulled automatically by the corresponding
   invocation of astEnd. */
      astBegin;

/* Create a FitsChan. This is the object that converts external FITS
   headers into corresponding AST Objects. Tell it to use the "source"
   function for obtaining lines of text from the disk file. */
      fchan = astFitsChan( source, NULL, " " );

/* Associate the descriptor for the input disk file with the StcsChan.
   This makes it available to the "source" function. Since this
   application is single threaded, we could instead have made "fd" a
   global variable, but the ChannelData facility is used here to illustrate
   how to pass data to a source or sink function safely in a multi-threaded
   application. */
      astPutChannelData( fchan, fd );

/* Attempt to read the FITS heades and convert them into an AST FrameSet. */
      object = astRead( fchan );

/* The astRead function is a generic function and so returns a generic
   AstObject pointer. Check an Object was created successfully. */
      if( !object ) {
         printf( "Failed to read an AST Object from file '%s'.\n",
                 argv[ 1 ] );
         status = 1;

/* Now check that the object read is actually an AST FrameSet, rather than
   some other class of AST Object. */
      } else if( !astIsAFrameSet( object ) ) {
         printf( "Expected a FrameSet but read a %s from file '%s'.\n",
                 astGetC( object, "Class" ), argv[ 1 ] );
         status = 1;

/* We now know we have a FrameSet so it is safe to use the pointer
   returned by astRead as a FrameSet pointer. Do the cast now to avoid
   repeated casting in future. */
      } else {
         frameset = (AstFrameSet *) object;

/* Get a pointer to the Frame that describes the attributes of the FITS
   world coordinate system. This is the current Frame in the FrameSet
   read from the FITS headers. */
         wcsfrm = astGetFrame( frameset, AST__CURRENT );

/* Get a pointer to the Frame that describes the attributes of the FITS
   pixel coordinate system. This is the base Frame in the FrameSet
   read from the FITS headers. */
         pixfrm = astGetFrame( frameset, AST__BASE );

/* Get the Mapping that transforms pixel positions into WCS positions.
   The is the Mapping from base to current Frame in the  FrameSet read
   from the FITS headers. */
         pix2wcs = astGetMapping( frameset, AST__BASE, AST__CURRENT );

/* Get the number of axes in ther pixel Frame. */
         naxis = astGetI( pixfrm, "Naxes" );

/* For each pixel axis, form the name of the corresponding NAXISi
   keyword. */
         for( axis = 0; axis < naxis; axis++ ) {
            sprintf( keyword, "NAXIS%d", axis + 1 );

/* Store the pixel coordinate on the current axis at the lower left corner
   of the first pixel. */
            p1[ axis ] = 0.5;

/* Get the NAXISi value for the current axis from the FITS header, and
   store it in array "p2". Report an error if NAXISi is not found. */
            if( !astGetFitsF( fchan, keyword, p2 + axis ) ){
               printf("Keyword '%s' not found in header\n", keyword );
               status = 1;
               break;

/* If it is found, modify "p2" so that it holds the pixel coordinate on
   the current axis at the upper right corner of the last pixel. */
            } else {
               p2[ axis ] += 0.5;
            }
         }
      }

/* If all has gone well, create an AST Region (a Box) describing the
   rectangular region of pixel coordinates covered by the pixel array. */
      if( !status ) {
         pixbox = astBox( pixfrm, 1, p1, p2, NULL, " " );

/* Map this box into the FITS world coordinate system. The Mapping is
   specified by "pix2wcs", and the attributes of the resulting axes is
   described by "wcsfrm". */
         wcsbox = astMapRegion( pixbox, pix2wcs, wcsfrm );

/* Create an StcsChan. This is the object that converts (either way)
   between external STC-S descriptions and their corresponding AST Objects.
   Tell it to use the "source" function for obtaining lines of text from
   the disk file. Also tell it to store all warnings generated by the
   conversion for later use. Other attributes of the StcsChan class retain
   their default values. */
         schan = astStcsChan( NULL, NULL, "ReportLevel=3" );

/* Attempt to write out the Region describing the pixel array (in WCS)
   as an STC-S description. Report an error if this fails. */
         if( ! astWrite( schan, wcsbox ) && astOK ) {
            printf( "Failed to convert the Region into an STC-S "
                    "description.\n" );
         }
      }

/* We asked the StcsChan to record any warnings that were generated
   whilst converting the AST Region into a corresponding STC-S description.
   We now see if any such warnings were generated by the earlier call to
   astWrite. */
      warnings = astWarnings( schan );

/* If any warnings were generated, and if no other error has occurred so
   far, display the warnings. */
      if( warnings && !status && astOK ) {
         printf( "\nThe following warnings were issued:\n" );

/* The warnings are stored in an AST KeyMap (a sort of hashmap). Each
   warning message is associated with a key of the form "Warning_1",
   "Warning_2", etc. Loop round successive keys, obtaining a value for
   each key from the warnings KeyMap, and displaying it. */
         iwarn = 1;
         while( astOK ) {
            sprintf( key, "Warning_%d", iwarn++ );
            if( astMapGet0C( warnings, key, &message ) ) {
               printf( "\n- %s\n", message );
            } else {
               break;
            }
         }
      }

/* End the AST Object context. All Objects created since the
   corresponding invocation of astbegin will be annulled automatically. */
      astEnd;

/* Close the disk file. */
      (void) fclose( fd );
   }

/* If an error occurred in the AST library, set the retiurns system
   status non-zero. */
   if( !astOK ) status = 1;
   return status;
}
예제 #8
0
static void smf1_jsadicer( int indfo, int *olbnd, int *oubnd,
                           AstMapping *tile_map, AstFrame *tile_frm,
                           AstMapping *p2pmap, void *ipd, void *ipv,
                           unsigned char *ipq, int *status ){
/*
*  Name:
*     smf1_jsadicer

*  Purpose:
*     Copy one tile from the input NDF into a specified output NDF.

*  Language:
*     Starlink ANSI C

*  Type of Module:
*     C function

*  Invocation:
*     void smf1_jsadicer( int indfo, int *olbnd, int *oubnd,
*                         AstMapping *tile_map, AstFrame *tile_frm,
*                         AstMapping *p2pmap, void *ipd, void *ipv,
*                         unsigned char *ipq, int *status )

*  Arguments:
*     indfo = int (Given)
*        An identifier for the NDF in which the copied data is to be
*        stored. It's original pixel bounds are used as the bounds of the
*        ipd, ipv and ipq arrays.
*     olbnd = int * (Given)
*        The new lower pixel bounds required for the output NDF. The bounds
*        of the supplied NDF are changed to match these values.
*     oubnd = int * (Given)
*        The new upper pixel bounds required for the output NDF. The bounds
*        of the supplied NDF are changed to match these values.
*     tile_map = AstMapping * (Given)
*        The mapping from pixel coords in the output NDF to WCS coords.
*     tile_frm = AstMapping * (Given)
*        The WCS Frame for the output NDF.
*     p2pmap = AstMapping * (Given)
*        The mapping from pixel coords in the input NDF to pixel coords in
*        the output NDF.
*     ipd = void * (Given)
*        Pointer to the start of the input data array. If this is NULL,
*        the existing contents of the NDF are used as input.
*     ipv = void * (Given)
*        Pointer to the start of the input variance array. Should be NULL
*        if no variances are available.
*     ipq = unsigned char * (Given)
*        Pointer to the start of the input quality array. Should be NULL
*        if no quality is available.
*     status = int * (Given)
*        Pointer to the inherited status variable.
*/

/* Local Variables: */
   AstFrame *use_frm = NULL;
   AstFrameSet *owcs;
   AstMapping *use_map = NULL;
   AstMapping *use_p2pmap = NULL;
   AstShiftMap *sm;
   char type[ NDF__SZTYP + 1 ];
   double shifts[ 3 ];
   int axes[ 2 ];
   int axout[ NDF__MXDIM ];
   int free_arrays;
   int isreal;
   int lbnd_tile[ 3 ];
   int ndim;
   int nel;
   int nin;
   int there;
   int ubnd_tile[ 3 ];
   unsigned char *ipq_out = NULL;
   void *ipd_out = NULL;
   void *ipv_out = NULL;

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST context. */
   astBegin;

/* Get the NDF data type - _REAL or _DOUBLE. */
   ndfType( indfo, "Data", type, sizeof(type), status );
   isreal = !strcmp( type, "_REAL" );

/* Get the existing bounds of the NDF. */
   ndfBound( indfo, 3, lbnd_tile, ubnd_tile, &ndim, status );

/* If no data array has been supplied, take a copy of the original Data,
   Quality and Variance arrays and use these as the input arrays. */
   if( !ipd ) {
      free_arrays = 1;

      ndfMap( indfo, "Data", type, "Read", &ipd_out, &nel, status );
      ipd = astStore( NULL, ipd_out,
                      nel*(isreal?sizeof(float):sizeof(double)) );
      ndfUnmap( indfo, "Data", status );

      ndfState( indfo, "Variance", &there, status );
      if( there ) {
         ndfMap( indfo, "Variance", type, "Read", &ipv_out, &nel, status );
         ipv = astStore( NULL, ipv_out,
                         nel*(isreal?sizeof(float):sizeof(double)) );
         ndfUnmap( indfo, "Variance", status );
      } else {
         ipv = NULL;
      }

      ndfState( indfo, "Quality", &there, status );
      if( there ) {
         ndfMap( indfo, "Quality", "_UBYTE", "Read", (void **) &ipq_out,
                 &nel, status );
         ipq = astStore( NULL, ipq_out, nel*sizeof(*ipq) );
         ndfUnmap( indfo, "Quality", status );
      } else {
         ipq = NULL;
      }

   } else {
      free_arrays = 0;
   }

/* Set the bounds of the NDF to the required values. */
   ndfSbnd( ndim, olbnd, oubnd, indfo, status );

/* Erase the existing WCS FrameSet and then get the default WCS FrameSet. */
   ndfReset( indfo, "WCS", status );
   ndfGtwcs( indfo, &owcs, status );

/* If the supplied mapping and Frame have two many axes, strip some off.
   The orering of pixel axes in the output JSA tile is hardwired by SMURF
   as (ra,dec,spec). */
   nin = astGetI( tile_map, "Nin" );
   if( nin == 3 && ndim == 2 ) {
      axes[ 0 ] = 1;
      axes[ 1 ] = 2;
      astMapSplit( tile_map, 2, axes, axout, &use_map );
      if( use_map ) {
         use_frm = astPickAxes( tile_frm, 2, axout, NULL );
      } else if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( " ", "smf1_jsadicer: cannot split mapping (programming "
                  "error).", status );
      }

      astMapSplit( p2pmap, 2, axes, axout, &use_p2pmap );
      if( !use_p2pmap && *status == SAI__OK ) {
         *status = SAI__ERROR;
         errRepf( " ", "smf1_jsadicer: cannot split mapping (programming "
                  "error).", status );
      }

   } else if( nin == ndim ) {
      use_p2pmap = astClone( p2pmap );
      use_map = astClone( tile_map );
      use_frm = astClone( tile_frm );

   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRepf( " ", "smf1_jsadicer: unexpected combination of nin (%d) and "
               "ndim (%d) (programming error).", status, nin, ndim );
   }

/* Add the tile WCS Frame into the output NDF's WCS FrameSet, using "tilemap"
   to connect it to the PIXEL Frame (NDF ensure Frame 2 is the PIXEL
   Frame). */
   astAddFrame( owcs, 2, use_map, use_frm );

/* The astResample function is odd in that it assumes that pixel coords
   are defined such that the centre of pixel "I" has integral pixel
   coord "I" (rather than "I-0.5" as is usual in Starlink). So we need to
   use a half-pixel ShiftMap at start and end of the p2pmap Mapping to
   account for this. */
   shifts[ 0 ] = -0.5;
   shifts[ 1 ] = -0.5;
   shifts[ 2 ] = -0.5;
   sm = astShiftMap( ndim, shifts, " " );
   use_p2pmap = (AstMapping *) astCmpMap( sm, use_p2pmap, 1, " " );
   astInvert( sm );
   use_p2pmap = (AstMapping *) astCmpMap( use_p2pmap, sm, 1, " " );

/* Store this modified WCS FrameSet in the output NDF. */
   ndfPtwcs( owcs, indfo, status );

/* Map the required arrays of the output NDF. */
   ndfMap( indfo, "Data", type, "Write", &ipd_out, &nel, status );
   if( ipv ) ndfMap( indfo, "Variance", type, "Write", &ipv_out, &nel,
                     status );
   if( ipq ) ndfMap( indfo, "Quality", "_UBYTE", "Write",
                      (void **) &ipq_out, &nel, status );

/* Copy the input data values to the output, using nearest neighbour
   interpolation (the mapping should always map input pixel centres onto
   output pixel centres). We can set the "tol" argument non-zero (e.g. 0.1)
   without introducing any error because the the p2pmap mapping will be
   piecewise linear. This gives a factor of about 5 decrease in the time
   spent within astResample. */
   if( !strcmp( type, "_REAL" ) ) {
      (void) astResampleF( use_p2pmap, ndim, lbnd_tile, ubnd_tile, (float *) ipd,
                           (float *) ipv, AST__NEAREST, NULL, NULL,
                           AST__USEBAD, 0.1, 1000, VAL__BADR, ndim,
                           olbnd, oubnd, olbnd, oubnd,
                           (float *) ipd_out, (float *) ipv_out );
   } else {
      (void) astResampleD( use_p2pmap, ndim, lbnd_tile, ubnd_tile, (double *) ipd,
                           (double *) ipv, AST__NEAREST, NULL, NULL,
                           AST__USEBAD, 0.1, 1000, VAL__BADD, ndim,
                           olbnd, oubnd, olbnd, oubnd,
                           (double *) ipd_out, (double *) ipv_out );
   }

   if( ipq ) {
      (void) astResampleUB( use_p2pmap, ndim, lbnd_tile, ubnd_tile, ipq, NULL,
                            AST__NEAREST, NULL, NULL, 0, 0.1, 1000, 0,
                            ndim, olbnd, oubnd, olbnd, oubnd, ipq_out,
                            NULL );
   }

/* Unmap everything the output NDF. */
   ndfUnmap( indfo, "*", status );

/* Free the input arrays if they were allocated in this function. */
   if( free_arrays ) {
      ipd = astFree( ipd );
      ipv = astFree( ipv );
      ipq = astFree( ipq );
   }

/* End the AST context. */
   astEnd;
}
예제 #9
0
void smf_addpolanal( AstFrameSet *fset, smfHead *hdr, AstKeyMap *config,
                     int *status ){

/* Local Variables */
   AstCmpMap *tmap;
   AstFrame *cfrm;
   AstFrame *pfrm;
   AstFrame *tfrm;
   AstFrameSet *tfs;
   AstPermMap *pm;
   char *polnorth = NULL;
   const char *cursys;
   const char *trsys;
   int aloff;
   int icurr;
   int inperm[2];
   int outperm[2];
   int pol2fp;

/* Check inherited status, and also check the supplied angle is not bad. */
   if( *status != SAI__OK ) return;

/* Begin an AST object context. */
   astBegin;

/* Get the value of the POLNORTH FITS keyword from the supplied header.
   The rest only happens if the keyword is found. */
   if( astGetFitsS( hdr->fitshdr, "POLNORTH", &polnorth ) ) {

/* Normally, we do not allow maps to be made from Q/U time streams that
   use focal plane Y as the reference direction (because of the problems
   of sky rotation). Therefore we report an error. However, we do need to
   make such maps as part of the process of determining the parameters of
   the Instrumental Polarisation (IP) model. So only report the error if
   "pol2fp" config parameter is non-zero. */
      if( !strcmp( polnorth, "FPLANE" ) ) {
         astMapGet0I( config, "POL2FP", &pol2fp );

         if( pol2fp ) {
            msgBlank( status );
            msgOut( "", "WARNING: The input NDFs hold POL-2 Q/U data specified "
                    "with respect to focal plane Y.",status );
            msgOut( "", "Maps should normally be made from POL-2 data specified "
                    "with respect to celestial north.",status );
            msgOut( "", "The output map will not contain a POLANAL Frame and "
                    "so will be unusable by POLPACK applications.",status );
            msgBlank( status );

         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRep( "", "The input NDFs hold POL-2 Q/U data specified with "
                    "respect to focal plane Y.",status );
            errRep( "", "Maps can only be made from POL-2 data specified with "
                    "respect to celestial north.",status );
         }

/* If the ref. direction is celestial north, create a suitable Frame and
   Mapping and add them into the supplied FrameSet. */
      } else {

/* Check the current Frame is a SkyFrame. */
         cfrm = astGetFrame( fset, AST__CURRENT );
         if( astIsASkyFrame( cfrm ) ) {

/* Create a POLANAL Frame. */
            pfrm = astFrame( 2, "Domain=POLANAL" );
            astSet( pfrm, "Title=Polarimetry reference frame" );
            astSet( pfrm, "Label(1)=Polarimetry reference direction" );
            astSet( pfrm, "Label(2)=" );

/* Create a PermMap that ensures that axis 1 of the POLANAL Frame is parallel
   to the latitude axis (i.e. north) of the curent Frame (the current Frame axes
   may have been swapped). */
            outperm[ 0 ] = astGetI( cfrm, "LatAxis" );
            outperm[ 1 ] = astGetI( cfrm, "LonAxis" );
            inperm[ outperm[ 0 ] - 1 ] = 1;
            inperm[ outperm[ 1 ] - 1 ] = 2;
            pm = astPermMap( 2, inperm, 2, outperm, NULL, " " );

/* Record the index of the original current Frame. */
            icurr = astGetI( fset, "Current" );

/* Determine the system to use. */
            if( !strcmp( polnorth, "TRACKING" ) ) {
               trsys = sc2ast_convert_system( hdr->state->tcs_tr_sys, status );
            } else {
               trsys = polnorth;
            }

/* If the current Frame in the supplied FrameSet has this system. Then we
   use the above PermMap to connect the POLANAL Frame directly to the current
   Frame. */
            cursys = astGetC( cfrm, "System" );
            if( trsys && cursys && !strcmp( cursys, trsys ) ) {
               astAddFrame( fset, AST__CURRENT, pm, pfrm );

/* Otherwise we need to get a Mapping from the current Frame to the
   required frame. */
            } else {

/* Take a copy of the current Frame (in order to pick up epoch, observatory
   position, etc), and set its System to the required system. */
               tfrm = astCopy( cfrm );
               astSetC( tfrm, "System", trsys );

/* Get the Mapping from the original current Frame to this modified copy.
   Ensure alignment happens in absolute coords (alignment in offset
   coords is always a unit mapping and so no rotation occurs). */
               aloff = astGetI( cfrm, "AlignOffset" );
               if( aloff ) {
                  astSetI( cfrm, "AlignOffset", 0 );
                  astSetI( tfrm, "AlignOffset", 0 );
               }
               tfs = astConvert( cfrm, tfrm, "SKY" );
               if( aloff ) {
                  astSetI( cfrm, "AlignOffset", 1 );
                  astSetI( tfrm, "AlignOffset", 1 );
               }
               if( tfs ) {

/* Use it, in series with with the above PermMap, to connect the POLANAL frame
   to the current Frame. */
                  tmap = astCmpMap( astGetMapping( tfs, AST__BASE,
                                                   AST__CURRENT ),
                                    pm, 1, " " );
                  astAddFrame( fset, AST__CURRENT, astSimplify( tmap ),
                               pfrm );

/* Report an error if the mapping from current to required system could
   not be found. */
               } else if( *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  errRepf( "", "smf_addpolanal: Could not convert Frame "
                           "from %s to %s (prgramming error).", status,
                           cursys, trsys );
               }
            }

/* Re-instate the original current Frame. */
            astSetI( fset, "Current", icurr );

/* Report an error if the current Frame is not a SkyFrame. */
         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRep( "", "smf_addpolanal: The current Frame in the "
                    "supplied FrameSet is not a SkyFrame (prgramming "
                    "error).", status );
         }
      }
   }

/* End the AST object context. */
   astEnd;
}
예제 #10
0
void smf_calc_iqu( ThrWorkForce *wf, smfData *data, int block_start,
                  int block_end, int ipolcrd, int qplace, int uplace,
                  int iplace, NdgProvenance *oprov, AstFitsChan *fc,
                  int pasign, double paoff, double angrot, int submean,
                  int harmonic, int *status ){

/* Local Variables: */
   AstCmpMap *cm1;
   AstCmpMap *cm2;
   AstFrameSet *wcs;          /* WCS FrameSet for output NDFs */
   AstMapping *fpmap1;
   AstMapping *fpmap2;
   AstMapping *oskymap;
   AstMapping *totmap;
   AstSkyFrame *oskyfrm;
   AstWinMap *wm;             /* Mapping to reverse the X GRID axis */
   const JCMTState *state;    /* JCMTState info for current time slice */
   const char *usesys;        /* Used system string */
   dim_t itime;               /* Time slice index */
   dim_t nbolo;               /* No. of bolometers */
   dim_t ncol;                /* No. of columns of bolometers */
   dim_t nrow;                /* No. of rows of bolometers */
   dim_t ntime;               /* Time slices to check */
   dim_t ntslice;             /* Number of time-slices in data */
   double *ipi;               /* Pointer to output I array */
   double *ipiv;              /* Pointer to output I variance array */
   double *ipq;               /* Pointer to output Q array */
   double *ipqv;              /* Pointer to output Q variance array */
   double *ipu;               /* Pointer to output U array */
   double *ipuv;              /* Pointer to output U variance array */
   double *mean;
   double ang_data[2];
   double fox[2];
   double foy[2];
   double fpr0;
   double fprinc;
   double fx[2];
   double fy[2];
   double ina[ 2 ];           /* Bolometer coords at bottom left */
   double inb[ 2 ];           /* Bolometer coords at top right */
   double outa[ 2 ];          /* NDF GRID coords at bottom left */
   double outb[ 2 ];          /* NDF GRID coords at top right */
   int bstep;                 /* Bolometer step between threads */
   int el;                    /* Number of mapped array elements */
   int gotvar;                /* Were any output variances created? */
   int indfi;                 /* Identifier for NDF holding I values */
   int indfq;                 /* Identifier for NDF holding Q values */
   int indfu;                 /* Identifier for NDF holding Q values */
   int iworker;               /* Index of a worker thread */
   int lbnd[ 2 ];             /* Lower pixel bounds of output NDF */
   int moving;
   int nworker;               /* No. of worker threads */
   int old;                   /* Data has old-style POL_ANG values? */
   int tstep;                 /* Time slice step between threads */
   int ubnd[ 2 ];             /* Upper pixel bounds of output NDF */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfCalcIQUJobData *job_data = NULL; /* Pointer to all job data */
   smfCalcIQUJobData *pdata = NULL;/* Pointer to next job data */
   smfHead *hdr;              /* Pointer to data header this time slice */

/* Check the inherited status. */
   if( *status != SAI__OK ) return;

/* Convenience pointers. */
   hdr = data->hdr;

/* Obtain number of time slices - will also check for 3d-ness. Also get
   the dimensions of the bolometer array and the strides between adjacent
   bolometer values. */
   smf_get_dims( data, &nrow, &ncol, &nbolo, &ntslice, NULL, &bstride,
                 &tstride, status );

/* Report an error if the block of time slices extends of either end. */
   if( block_start < 0 || block_end >= (int) ntslice ) {
      if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         msgSeti( "S", block_start );
         msgSeti( "E", block_end );
         msgSeti( "N", ntslice );
         errRep( " ", "smf_calc_iqu: invalid block of time slices - ^S to "
                 "^E (^N time slices are available).", status );
      }
   }

/* Create the output NDFs. Each one is a 2D array with dimensions
   equal to the bolometer array. */
   lbnd[ 0 ] = 1;
   lbnd[ 1 ] = 1;
   ubnd[ 0 ] = ncol;
   ubnd[ 1 ] = nrow;
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &qplace, &indfq, status );
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &uplace, &indfu, status );
   if( iplace != NDF__NOPL ) {
      ndfNew( "_DOUBLE", 2, lbnd, ubnd, &iplace, &indfi, status );
   } else {
      indfi = NDF__NOID;
   }

/* Store any supplied provenance in all NDFs. */
   if( oprov ) {
      ndgWriteProv( oprov, indfq, 1, status );
      ndgWriteProv( oprov, indfu, 1, status );
      if( indfi != NDF__NOID ) ndgWriteProv( oprov, indfi, 1, status );
   }

/* Store any supplied FITS headers in all NDFs.*/
   if( fc && astGetI( fc, "NCard" ) > 0 ) {
      kpgPtfts( indfq, fc, status );
      kpgPtfts( indfu, fc, status );
      if( indfi != NDF__NOID )  kpgPtfts( indfi, fc, status );
   }

/* Store the WCS frameSet in all NDFs. First get the FrameSet for the
   central time slice in the block, and set its current Frame to the
   tracking frame. */
   smf_tslice_ast( data, ( block_start + block_end )/2, 1, NO_FTS, status);
   usesys = sc2ast_convert_system( (data->hdr->allState)[0].tcs_tr_sys,
                                    status );
   astSetC( hdr->wcs, "System", usesys );

/* Get the Mapping from focal plane coords to bolometer grid coords. This
   is the same for all time slices. sc2ast ensures that frame 3 is FPLANE. */
   fpmap1 = astGetMapping( hdr->wcs, 3, AST__BASE );

/* Take a copy and then reverse the X axis of the GRID Frame by remaping the
   base Frame using a WinMap. This produces a pixel grid such as you would
   see by looking up at the sky from underneath the array, rather than looking
   down at the ground from above the array. */
   wcs = astCopy( hdr->wcs );
   ina[ 0 ] = 1.0;
   inb[ 0 ] = ncol;
   ina[ 1 ] = 1.0;
   inb[ 1 ] = nrow;

   outa[ 0 ] = ncol;
   outb[ 0 ] = 1.0;
   outa[ 1 ] = 1.0;
   outb[ 1 ] = nrow;

   wm = astWinMap( 2, ina, inb, outa, outb, " " );
   astRemapFrame( wcs, AST__BASE, wm );
   wm = astAnnul( wm );

/* Get the Mapping from output grid coords to focal plane coords. */
   fpmap2 = astGetMapping( wcs, AST__BASE, 3 );

/* If the target is moving (assumed to be the case if the tracking
   system is AZEL or GAPPT), make the FrameSet current Frame represent
   offsets from the reference position (i.e. the moving target), and
   indicate that the offset coord system should be used for alignment. */
   if( !strcmp( usesys, "AZEL" ) || !strcmp( usesys, "GAPPT" ) ){
      astSet( wcs, "SkyRefIs=Origin,AlignOffset=1" );
      moving = 1;
   } else {
      moving = 0;
   }

/* Store the FrameSet in the output NDFs. */
   ndfPtwcs( wcs, indfq, status );
   ndfPtwcs( wcs, indfu, status );
   if( indfi != NDF__NOID ) ndfPtwcs( wcs, indfi, status );

/* Map the Data array in each NDF. */
   ndfMap( indfq, "Data", "_DOUBLE", "WRITE", (void **) &ipq, &el, status );
   ndfMap( indfu, "Data", "_DOUBLE", "WRITE", (void **) &ipu, &el, status );
   if( indfi != NDF__NOID ) {
      ndfMap( indfi, "Data", "_DOUBLE", "WRITE", (void **) &ipi, &el, status );
   } else {
      ipi = NULL;
   }

/* Map the Variance array in each NDF. */
   ndfMap( indfq, "Variance", "_DOUBLE", "WRITE", (void **) &ipqv, &el, status );
   ndfMap( indfu, "Variance", "_DOUBLE", "WRITE", (void **) &ipuv, &el, status );
   if( indfi != NDF__NOID ) {
      ndfMap( indfi, "Variance", "_DOUBLE", "WRITE", (void **) &ipiv, &el, status );
   } else {
      ipiv = NULL;
   }

/* If required, allocate memory to hold the mean bolometer value at each
   time slice. */
   mean = submean ? astMalloc( ntslice*sizeof( *mean ) ) : NULL;

/* Create structures used to pass information to the worker threads. */
   nworker = wf ? wf->nworker : 1;
   job_data = astMalloc( nworker*sizeof( *job_data ) );

/* Check the above pointers can be used safely. */
   if( *status == SAI__OK ) {

/* Go through the first thousand POL_ANG values to see if they are in
   units of radians (new data) or arbitrary encoder units (old data).
   They are assumed to be in radians if no POL_ANG value is larger than
   20. */
      old = 0;
      state = hdr->allState;
      ntime = ( ntslice > 1000 ) ? 1000 : ntslice;
      for( itime = 0; itime < ntime; itime++,state++ ) {
         if( state->pol_ang > 20 ) {
            old = 1;
            msgOutif( MSG__VERB, "","   POL2 data contains POL_ANG values "
                      "in encoder units - converting to radians.", status );
            break;
         }
      }

/* If required, find the mean bolometer value at each time slice. */
      if( submean ) {

/* Determine which time-slices are to be processed by which threads. */
         tstep = ntslice/nworker;
         if( tstep < 1 ) tstep = 1;

         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;
            pdata->block_start = iworker*tstep;
            if( iworker < nworker - 1 ) {
               pdata->block_end = pdata->block_start + tstep - 1;
            } else {
               pdata->block_end = ntslice - 1;
            }
         }

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;

            pdata->bstride = bstride;
            pdata->dat = data->pntr[0];
            pdata->nbolo = nbolo;
            pdata->qua = smf_select_qualpntr( data, NULL, status );;
            pdata->tstride = tstride;
            pdata->mean = mean;
            pdata->action = 1;

/* Pass the job to the workforce for execution. */
            thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                         status );
         }

/* Wait for the workforce to complete all jobs. */
         thrWait( wf, status );

      }

/* Get the Frame representing absolute sky coords in the output NDF,
   and the Mapping from sky to grid in the output NDF. */
      oskyfrm = astCopy( astGetFrame( wcs, AST__CURRENT ) );
      astSet( oskyfrm, "SkyRefIs=Ignored" );
      oskymap = astGetMapping( wcs, AST__CURRENT, AST__BASE );
      wcs = astAnnul( wcs );

/* Find the first and last time slices, calculate the angle between the
   focal pane Y axis at the time slice, and the focal plane Y axis in
   the output NDF. For intervening time-slices, the angle is found by
   linear interpolation between the extreme time slices. */
      for( el = 0; el < 2; el++ ) {

/* Get the mapping from GRID coords in the input time slice to GRID
   coords in the output. */
         totmap = smf_rebin_totmap( data, el?ntslice-1:0, oskyfrm, oskymap,
                                    moving, NO_FTS, status );

/* Modify it to be the Mapping from focal plane coords in the input time
   slice to focal plane coords in the output. */
         cm1 = astCmpMap( fpmap1, totmap, 1, " " );
         cm2 = astCmpMap( cm1, fpmap2, 1, " " );

/* Use this Mapping to convert two points on the focal plane Y axis from
   the input to the output. */
         fx[0] = 0.0;
         fy[0] = 0.0;
         fx[1] = 0.0;
         fy[1] = 4.0;
         astTran2( cm2, 2, fx, fy, 1, fox, foy );

/* The angle from the focal plane Y axis in the output to the focal plane
   Y axis in the input time slice, measured positive in sense of rotation
   from Fy to Fx. */
         ang_data[ el ] = atan2( fox[1]-fox[0], foy[1]-foy[0] );

/* Free resources for this time slice. */
         totmap = astAnnul( totmap );
         cm1 = astAnnul( cm1 );
         cm2 = astAnnul( cm2 );
      }

/* Annul objects. */
      oskymap = astAnnul( oskymap );
      oskyfrm = astAnnul( oskyfrm );
      fpmap1 = astAnnul( fpmap1 );
      fpmap2 = astAnnul( fpmap2 );

/* Get the constants of the linear relationship between focal plane
   rotation and time slice index "fpr = fpr0 + itime*fprinc". */
      fpr0 = ang_data[ 0 ];
      fprinc = ( ang_data[ 1 ] - fpr0 )/( ntslice - 1 );

/* Determine which bolometers are to be processed by which threads. */
      bstep = nbolo/nworker;
      if( bstep < 1 ) bstep = 1;

      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         pdata->b1 = iworker*bstep;
         pdata->b2 = pdata->b1 + bstep - 1;
      }

/* Ensure that the last thread picks up any left-over bolometers */
      pdata->b2 = nbolo - 1;

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;

         pdata->bstride = bstride;
         pdata->dat = data->pntr[0];;
         pdata->nbolo = nbolo;
         pdata->qua = smf_select_qualpntr( data, NULL, status );;
         pdata->tstride = tstride;
         pdata->allstates = hdr->allState;
         pdata->ipq = ipq;
         pdata->ipu = ipu;
         pdata->ipi = ipi;
         pdata->ipqv = ipqv;
         pdata->ipuv = ipuv;
         pdata->ipiv = ipiv;
         pdata->ipolcrd = ipolcrd;
         pdata->block_start = block_start;
         pdata->block_end = block_end;
         pdata->old = old;
         pdata->ncol = ncol;
         pdata->pasign = pasign ? +1: -1;
         pdata->paoff = paoff;
         pdata->angrot = angrot;
         pdata->fpr0 = fpr0;
         pdata->fprinc = fprinc;
         pdata->angfac = harmonic/4.0;
         pdata->action = 0;
         pdata->mean = mean;

/* Pass the job to the workforce for execution. */
         thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                      status );
      }

/* Wait for the workforce to complete all jobs. */
      thrWait( wf, status );

/* See if any thread produced non-bad variance values. */
      gotvar = 0;
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         if( pdata->gotvar ) gotvar = 1;
      }

/* If no variances were created, erase the Variance component and tell
   the user. */
      ndfUnmap( indfq, "*", status );
      ndfUnmap( indfu, "*", status );
      if( ipi ) ndfUnmap( indfi, "*", status );

      if( !gotvar ) {
         ndfReset( indfq, "Variance", status );
         ndfReset( indfu, "Variance", status );
         if( ipi ) ndfReset( indfi, "Variance", status );
         msgOut( "", "Warning: Insufficient input data to produce variances",
                 status );
      }
   }

/* Add POLANAL Frames to the WCS FrameSet in each output NDF. This Frame
   is used by POLPACK to determine the reference direction of the Stokes
   vectors (focal plane Y in this case, i.e. zero-based axis 1 ). */
   smf_polext( indfq, 0, 0.0, "FPLANE", 1, status );
   smf_polext( indfu, 0, 0.0, "FPLANE", 1, status );
   if( ipi ) smf_polext( indfi, 0, 0.0, "FPLANE", 1, status );

/* Free the two output NDFs. */
   ndfAnnul( &indfq, status );
   ndfAnnul( &indfu, status );
   if( ipi ) ndfAnnul( &indfi, status );

/* Free other resources. */
   job_data = astFree( job_data );
   mean = astFree( mean );
}
예제 #11
0
void smf_flat_malloc( size_t nheat, const smfData * refdata,
                      smfData **powvald, smfData **bolvald, int *status ) {

  size_t rowidx = SC2STORE__ROW_INDEX;
  size_t colidx = SC2STORE__COL_INDEX;
  double * bolval = NULL; /* Data array inside bolrefd */
  double * bolvalvar = NULL; /* Variance inside bolrefd */
  dim_t dims[] = { 1, 1, 1 }; /* Default dimensions */
  smfHead * hdr = NULL;      /* New header */
  int lbnd[] = { 1, 1, 1 };  /* Default pixel lower bounds */
  size_t nelem = 0;      /* Number of elements in first two dimensions of refdims */
  smfHead * oldhdr = NULL;   /* header from refdata */
  void *pntr[] = { NULL, NULL };          /* pointers for smfData */
  double * powval = NULL; /* Data array inside powrefd */
  const char *dom;        /* Domain of axis 1 */
  AstFrameSet *new_fs;    /* New FrameSet for returned *bolvald */
  AstMapping *map;        /* Mapping from pixel index 3 to heater index */
  AstFrame *frm;          /* Frame describing heater index */
  int ubnd[ 1 ];          /* Upper bound on heater index */

  if (bolvald) *bolvald = NULL;
  if (powvald) *powvald = NULL;

  if ( *status != SAI__OK ) return;

  if ( !bolvald && !powvald) {
    *status = SAI__ERROR;
    errRep( "", "Must provide at least one non-NULL pointer to smf_flat_malloc"
            " (possible programming error)", status );
    return;
  }

  /* Sanity check */
  if ( nheat == 0 ) {
    *status = SAI__ERROR;
    errRep( "", "No flatfield information present for creating new smfData",
            status );
    return;
  }

  if ( !smf_validate_smfData( refdata, 1, 0, status ) ) return;
  oldhdr = refdata->hdr;

  if (powvald) {
    powval = astCalloc( nheat, sizeof(*powval) );
    pntr[0] = powval;
    pntr[1] = NULL;
    dims[0] = nheat;
    *powvald = smf_construct_smfData( NULL, NULL, NULL, NULL, NULL, SMF__DOUBLE,
                                      pntr, NULL, SMF__QFAM_NULL, NULL, 0, 1,
                                      dims, NULL, 1, 0, 0, NULL,
                                      NULL, status );
  }

  if (bolvald) {
    /* Handle data ordering */
    if ( ! refdata->isTordered ) {
      rowidx++;
      colidx++;
    }

    nelem = refdata->dims[rowidx] * refdata->dims[colidx];
    bolval = astCalloc( nheat * nelem, sizeof(*bolval) );
    bolvalvar = astCalloc( nheat * nelem, sizeof(*bolvalvar) );
    pntr[0] = bolval;
    pntr[1] = bolvalvar;
    dims[SC2STORE__ROW_INDEX] = refdata->dims[rowidx];
    dims[SC2STORE__COL_INDEX] = refdata->dims[colidx];
    dims[2] = nheat;
    lbnd[SC2STORE__ROW_INDEX] = refdata->lbnd[rowidx];
    lbnd[SC2STORE__COL_INDEX] = refdata->lbnd[colidx];
    lbnd[2] = 1;

    /* Create a header to attach to the bolometer data. We only want the basic 2-d
       information to propagate. */
    hdr = smf_construct_smfHead( NULL, oldhdr->instrument, NULL, NULL,
                                 astCopy( oldhdr->fitshdr ), NULL, 0,
                                 oldhdr->instap, nheat, oldhdr->steptime,
                                 oldhdr->scanvel, oldhdr->obsmode,
                                 oldhdr->swmode, oldhdr->obstype,
                                 oldhdr->seqtype, oldhdr->inbeam, 0, NULL, NULL,
                                 NULL, NULL, 0, NULL,
                                 "Flatfield measurement", "Response",
                                 oldhdr->units, oldhdr->telpos,
                                 NULL, oldhdr->obsidss, status );

    *bolvald = smf_construct_smfData( NULL, NULL, hdr, NULL, NULL, SMF__DOUBLE,
                                      pntr, NULL, SMF__QFAM_TSERIES, NULL, 0, 1,
                                      dims, lbnd, 3, 0, 0, NULL, NULL, status );

    /* Assign a 3D WCS FRameSet in which the third axis represents heater
       value index (note, not actual heater value, since we do not yet
       know what the heater values are). First split the supplied time-series
       WCS FrameSet to extract a FrameSet in which the current Frame
       contains only the axes within the ame Domain as the first axis
       (this is safe because the first axis is always a spatial axis). */
    if( oldhdr->tswcs ) {
      dom = astGetC( oldhdr->tswcs, "Domain(1)" );
      new_fs = atlFrameSetSplit( oldhdr->tswcs, dom, NULL, NULL, status );

      /* Check this FrameSet is 2D, and if so, add in a third axis describing
         heater value index. */
      if( new_fs && astGetI( new_fs, "Naxes" ) == 2 ) {
         map = (AstMapping *) astUnitMap( 1, " " );
         frm = astFrame( 1, "Domain=HEATER_INDEX" );
         ubnd[ 0 ] = nheat;
         atlAddWcsAxis(  new_fs, map, frm, NULL, ubnd, status );
         map = astAnnul( map );
         frm = astAnnul( frm );

         /* Hand over the FrameSet pointer to the returned smfData. */
         (*bolvald)->hdr->tswcs = new_fs;

      }
    }
  }

  return;
}
예제 #12
0
void
smf_store_outputbounds (int updatepars, const int lbnd_out[3],
                        const int ubnd_out[3],
                        const AstFrameSet * wcsout,
                        const AstSkyFrame *oskyfrm,
                        const AstMapping * oskymap, int *status) {

  double corner[2];          /* WCS of a corner (SKY) */
  int i;                     /* loop counter */
  double glbnd_out[ 3 ];     /* double prec Lower GRID bounds for output map */
  double gubnd_out[ 3 ];     /* double prec Upper GRID bounds for output map */
  double gx_in[ 4 ];         /* X Grid coordinates of four corners */
  double gx_out[ 4 ];        /* X WCS coordinates of four corners */
  double gy_in[ 4 ];         /* Y Grid coordinates of four corners */
  double gy_out[ 4 ];        /* Y WCS coordinates of four corners */
  int ndims;                 /* Number of active dimensions */
  char tmpstr[10];           /* temporary unit string */
  double wcslbnd_out[3];     /* Array of lower bounds of output cube */
  double wcsubnd_out[3];     /* Array of upper bounds of output cube */

  /* Parameter names associated with the bounds */
  const char * bounds[] = {
    "FTR", "FTL", "FBR", "FBL", NULL
  };


  if (*status != SAI__OK) return;

/* work out how many dimensions we have */
  ndims = astGetI( wcsout, "Naxes");

/* Calculate and output the WCS bounds (matching NDFTRACE output). The bounds
   are normalised. Celestial coordinates will use radians. */
   for( i = 0; i < ndims; i++ ) {
     glbnd_out[ i ] = 0.5;
     gubnd_out[ i ] = ubnd_out[ i ] - lbnd_out[i] + 1.5;
   }

   for( i = 0; i < ndims; i++ ) {
     astMapBox( wcsout, glbnd_out, gubnd_out, 1, i+1, &(wcslbnd_out[ i ]),
                &(wcsubnd_out[ i ]), NULL, NULL );
   }

   astNorm( wcsout, wcslbnd_out );
   astNorm( wcsout, wcsubnd_out );

   /* adjust resolution of output frameset since in some cases we are interested in
      sub-arcsec resolution when comparing positions with different arguments
      (especially with RxA and using very small pixel sizes. Use digits() rather
      than format() so that we do not have to worry about hms vs dms */
   astSet( (AstFrameSet*)wcsout, "digits(1)=9,digits(2)=9" );

   if (ndims == 3) {
     msgOutif( MSG__NORM, "WCS_WBND1",
               "   Output cube WCS bounds:", status );
   } else {
     msgOutif( MSG__NORM, "WCS_WBND1",
               "   Output map WCS bounds:", status );
   }

   for( i = 0; i < ndims && *status == SAI__OK; i++ ) {
     msgSetc( "L", astFormat( wcsout, i+1, wcslbnd_out[i]));
     msgSetc( "U", astFormat( wcsout, i+1, wcsubnd_out[i]));

     if( i == 2 ) {
       sprintf( tmpstr, "unit(%d)", i+1 );
       msgSetc( "UNT", astGetC( wcsout, tmpstr ));
     } else {
       msgSetc( "UNT", "" );
     }

     sprintf( tmpstr, "label(%d)", i + 1 );
     msgSetc( "LAB", astGetC( wcsout, tmpstr ) );

     msgOutif( MSG__NORM, "WCS_WBND2",
	       "        ^LAB: ^L -> ^U ^UNT", status );
   }

   /* Return if we are not required to update the parameters */
   if (!updatepars) return;

   parPut1d( "FLBND", ndims,  wcslbnd_out, status );
   parPut1d( "FUBND", ndims,  wcsubnd_out, status );

   /* if we have a 2d frameset we can use that directly rather
      than having to split the mapping or provide explicit 2d
      versions. Since we know that MAKECUBE already calculates
      2d mappings/frames and we also know that MAKEMAP doesn't
      we provide some logic here to switch on Naxes */
   if (ndims == 2) {
     if (oskyfrm == NULL) oskyfrm = (AstSkyFrame*)wcsout;
     if (oskymap == NULL) oskymap = (AstMapping*)wcsout;
   }

/* Now also calculate the spatial coordinates of the four corners (required
   for CADC science archive. First, calculate input GRID coordinates for 4
   corners: TR, TL, BR, BL. Use pixel centres for reporting. This is
   important for cases where the pixels are very large and we want to make
   sure that we are conservative with the database reporting. */

   gx_in[ 0 ] = ubnd_out[ 0 ] - lbnd_out[ 0 ] + 1.0; /* Right */
   gx_in[ 1 ] = 1.0;                                 /* Left */
   gx_in[ 2 ] = gx_in[ 0 ];                          /* Right */
   gx_in[ 3 ] = gx_in[ 1 ];                          /* Left */
   gy_in[ 0 ] = ubnd_out[ 1 ] - lbnd_out[ 1 ] + 1.0; /* Top */
   gy_in[ 1 ] = gy_in[ 0 ];                          /* Top */
   gy_in[ 2 ] = 1.0;                                 /* Bottom */
   gy_in[ 3 ] = gy_in[ 2 ];                          /* Bottom */

   astTran2( oskymap, 4, gx_in, gy_in, 1, gx_out, gy_out );

   /* Store the bounds in the parameters */
   for (i = 0; i < 4; i++) {
     corner[ 0 ] = gx_out[ i ];
     corner[ 1 ] = gy_out[ i ];
     astNorm( oskyfrm, corner );
     parPut1d( bounds[i], 2, corner, status );
   }

}
예제 #13
0
void smf_getrefwcs( const char *param, Grp *igrp, AstFrameSet **specwcs,
                    AstFrameSet **spacewcs, int *isjsa, int *status ){

/* Local Variables */
   AstFrame *frm = NULL;
   AstFrameSet *refwcs = NULL;  /* The WCS FrameSet from the reference NDF */
   AstRegion *circle;
   char text[ 255 ];            /* Parameter value */
   int *tiles;
   int i;
   int jsatiles;
   int lbnd[2];                 /* Lower pixel index bounds of mid tile */
   int ntile;
   int perm[ 2 ];
   int refndf;                  /* NDF identifier for the refence NDF */
   int ubnd[2];                 /* Upper pixel index bounds of mid tile */
   size_t code;
   smfData *data = NULL;        /* Structure describing 1st input file */
   smfJSATiling skytiling;
   smf_inst_t inst = SMF__INST_NONE;
   smf_jsaproj_t proj;          /* Specific JSA projection to use */
   smf_subinst_t subinst;

/* Initialise the returned values. */
   *specwcs = NULL;
   *spacewcs = NULL;
   *isjsa = 0;

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST context. */
   astBegin;

/* If the JSAILES parameter is TRUE, then we use the JSA all-sky pixel
   grid regardless of the setting of REF. */
   parGet0l( "JSATILES", &jsatiles, status );
   if( jsatiles ) {
      strcpy( text, "JSA" );
      *isjsa = 1;

/* Otherwise, first get the parameter value as a string. Use subpar to avoid problem
   caused by interpretion of the text within the parameter system. */
   } else {
      subParFindpar( param, &code, status );
      subParGetname( code, text, sizeof(text), status );
   }

/* If no value was supplied, annul the error and do nothing more. */
   if( *status == PAR__NULL ) {
      errAnnul( status );

/* If it is "JSA", or one of the JSA projection codes, we return WCS that
   describes one of the the JSA all-sky pixel grids. */
   } else if( *status == SAI__OK ) {
      proj = smf_jsaproj_fromstr( text, 0, status );
      if( astChrMatch( text, "JSA" ) || proj != SMF__JSA_NULL ) {
         *isjsa = 1;

/* Report an error if the instrument cannot be determined. */
         if( !igrp ) {
            *status = SAI__ERROR;
            errRep( "", "smf_getrefwcs: Cannot use the JSA all-sky pixel "
                    "grid since no input group has been supplied (possibly "
                    "programming error).", status );
         } else {

/* Open the first input file. */
            smf_open_file( NULL, igrp, 1, "READ", SMF__NOCREATE_DATA, &data,
                           status );
            if( *status == SAI__OK ) {

/* Get the instrument. */
               if( data->hdr->instrument == INST__SCUBA2 ) {
                  subinst = smf_calc_subinst( data->hdr, status );
                  if( subinst == SMF__SUBINST_850 ) {
                     inst = SMF__INST_SCUBA_2_850;
                  } else {
                     inst = SMF__INST_SCUBA_2_450;
                  }

               } else if( data->hdr->instrument == INST__ACSIS ) {
                  inst = SMF__INST_ACSIS;

               } else if( *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  if( data->file ) {
                     smf_smfFile_msg( data->file, "FILE", 1, "one or more of "
                                      "the input data files" );
                  } else {
                     msgSetc( "FILE", "one or more of the input data files" );
                  }
                  errRep( "", "No tiles are yet defined for the instrument that "
                          "created ^FILE.", status );
               }

/* Get the parameters that define the layout of sky tiles for the
   instrument. */
               smf_jsatiling( inst, &skytiling, status );

/* For "JSA" - choose the best projection. */
               if( astChrMatch( text, "JSA" ) ) {

/* Use the FITS headers in the first raw data file to create an AST Circle
   describing the approximate area of the observation within the tracking
   system. */
                  circle = smf_mapregion_approx( igrp, status );

/* Convert the circle to ICRS (as used by the JSA all-sky grid). */
                  astSetC( circle, "System", "ICRS" );

/* Get a list of the tiles that touch this circle. */
                  tiles = smf_jsatiles_region( circle, &skytiling,
                                               &ntile, status );

/* Choose the best projection (i.e. the projection that puts the circle
   furthest away from any singularities). */
                  proj = smf_jsaproj( ntile, tiles, &skytiling, status);

/* Free resources. */
                  tiles = astFree( tiles );
                  circle = astAnnul( circle );

/* If a good projection was specified, use it. Otherwise report an error. */
               } else if( proj == SMF__JSA_NULL && *status == SAI__OK ) {
                  *status = SAI__ERROR;
                  errRepf( "", "Bad value '%s' supplied for parameter %s.",
                           status, text, param );
               }

/* Report the projection type. */
               msgOutf( " ", "The %s will be created on the JSA %s "
                        "pixel grid.", status,
                        (data->hdr->instrument==INST__ACSIS)?"cube":"map",
                        smf_jsaproj_tostr( proj ) );

/* All tiles within the same JSA projection use the same WCS, so we get
   the WCS FrameSet for an arbitrary central tile, and use it for the
   full map. The exception is that tiles within the HPX facet that is
   split between bottom-left and top-right, use a different WCS (they
   have different reference points). But our choice of projection should
   mean that the map never falls in that facet. The base Frame will be
   GRID coords within the tile, and the current Frame will be ICRS
   (RA,Dec). */
               smf_jsatile( ((skytiling.ntpf * skytiling.ntpf - 1) * 2) / 3,
                            &skytiling, 0, proj, NULL, spacewcs, NULL, lbnd,
                            ubnd, status );

/* Change the base Frame to be PIXEL. */
               for( i = 1; i <= astGetI( *spacewcs, "NFrame" ); i++ ) {
                  frm = astGetFrame( *spacewcs, i );
                  if( astChrMatch( astGetC( frm, "Domain" ), "PIXEL" ) ) {
                     astSetI( *spacewcs, "Base", i );
                  }
                  frm = astAnnul( frm );
               }
            }

/* Close the current input data file. */
            smf_close_file( NULL, &data, status);
         }

/* Otherwise get the parameter value as an NDF. */
      } else {
         ndfAssoc( param, "READ", &refndf, status );

/* Get the WCS FrameSet from the reference NDF. */
         ndfGtwcs( refndf, &refwcs, status );

/* Attempt to extract a new FrameSet from this WCS FrameSet, in which the
   current Frame is a SkyFrame, and the base Frame is a 2D PIXEL Frame.
   Since the NDF library sets the GRID Frame to be the Base Frame, we need
   to make the PIXEL Frame the base Frame first. The NDF library ensures
   that the pixel Frame is Frame 2. */
         astSetI( refwcs, "Base", 2 );
         *spacewcs = atlFrameSetSplit( refwcs, "SKY", NULL, NULL, status );
         if( !(*spacewcs) ) {
            if( *status == SAI__OK ) {
               ndfMsg( "N", refndf );
               *status = SAI__ERROR;
               errRep( "", "The supplied reference NDF (^N) either has no "
                       "celestial WCS axes, or the celestial axes cannot "
                       "be separated from the non-celestial axes.", status );
            }

/* The rest of makemap assumes that the sky frame axes are in the default
   order (lon,lat). If this is not the case, permute them. */
         } else if( astGetI( *spacewcs, "IsLatAxis(1)" ) ) {
            perm[ 0 ] = 2;
            perm[ 1 ] = 1;
            astPermAxes( *spacewcs, perm );
         }

/* Now look for the spectral WCS (described by a DSBSpecFrame). */
         smf_getspectralwcs( refwcs, 1, specwcs, status );

/* We no longer need the NDF so annul it. */
         ndfAnnul( &refndf, status );
      }
   }

/* If no error has occurred, export any returned FrameSet pointers from
   the current AST context so that it will not be annulled when the AST
   context is ended. Otherwise, ensure a null pointer is returned. */
   if( *status == SAI__OK ) {
      if( *spacewcs ) astExport( *spacewcs );
      if( *specwcs ) astExport( *specwcs );
   } else {
      if( *spacewcs ) *spacewcs = astAnnul( *spacewcs );
      if( *specwcs ) *specwcs = astAnnul( *specwcs );
   }

/* End the AST context. This will annul all AST objects created within the
   context (except for those that have been exported from the context). */
   astEnd;

}
예제 #14
0
void smf_get_projpar( AstSkyFrame *skyframe, const double skyref[2],
                      int moving, int autogrid, int nallpos,
                      const double * allpos, float telres, double map_pa,
                      double par[7], int * issparse,int *usedefs, int *status ) {

/* Local Variables */
   char reflat[ 41 ];    /* Reference latitude string */
   char reflon[ 41 ];    /* Reference longitude string */
   char usesys[ 41 ];    /* Output skyframe system */
   const char *deflat;   /* Default for REFLAT */
   const char *deflon;   /* Default for REFLON */
   const double fbpixsize = 6.0; /* Fallback pixel size if we have no other information */
   double autorot;       /* Autogrid default for CROTA parameter */
   double defsize[ 2 ];  /* Default pixel sizes in arc-seconds */
   double pixsize[ 2 ];  /* Pixel sizes in arc-seconds */
   double refpix[ 2 ];   /* New REFPIX values */
   double rdiam;         /* Diameter of bounding circle, in rads */
   int coin;             /* Are all points effectively co-incident? */
   int i;
   int nval;             /* Number of values supplied */
   int refine_crpix;     /* Should the pixel ref position be updated? */
   int sparse = 0;       /* Local definition of sparseness */
   int udefs = 0;        /* Flag for defaults used or not */

/* Check inherited status. */
   if( *status != SAI__OK ) return;

/* If the number of supplied positions is 0 or null pointer,
   disable autogrid */
   if( nallpos == 0 || !allpos ) autogrid = 0;

/* Get the output system */
   one_strlcpy( usesys, astGetC( skyframe, "SYSTEM"), sizeof(usesys),
                status );

/* Ensure the reference position in the returned SkyFrame is set to the
   first telescope base pointing position. */
   astSetD( skyframe, "SkyRef(1)", skyref[ 0 ] );
   astSetD( skyframe, "SkyRef(2)", skyref[ 1 ] );

/* If the target is moving, ensure the returned SkyFrame represents
   offsets from the first telescope base pointing position rather than
   absolute coords. */
   if( moving ) smf_set_moving( (AstFrame *) skyframe, NULL, status );

/* Set a flag indicating if all the points are co-incident. */
   coin = 0;

/* Set the sky axis values at the tangent point. If the target is moving,
   the tangent point is at (0,0) (i.e. it is at the origin of the offset
   coordinate system). If the target is not moving, the tangent point is
   at the position held in "skyref". */
   if( par ) {
      if( moving ){
         par[ 2 ] = 0.0;
         par[ 3 ] = 0.0;
      } else {
         par[ 2 ] = skyref[ 0 ];
         par[ 3 ] = skyref[ 1 ];
      }

/* If required, calculate the optimal projection parameters. If the target
   is moving, these refer to the offset coordinate system centred on the
   first time slice base pointing position, with north defined by the
   requested output coordinate system. The values found here are used as
   dynamic defaults for the environment parameter */
      if( autogrid ) {
         kpg1Opgrd( nallpos, allpos, strcmp( usesys, "AZEL" ), par, &rdiam,
                          status );

/* See if all the points are effectively co-incident (i.e. within an Airy
   disk). If so, we use default grid parameters that result in a grid of
   1x1 spatial pixels. The grid pixel sizes (par[4] and par[5]) are made
   larger than the area covered by the points in order to avoid points
   spanning two pixels. */
         if( rdiam < telres || nallpos < 3 ) {
            if( rdiam < 0.1*AST__DD2R/3600.0 ) rdiam = 0.1*AST__DD2R/3600.0;
            par[ 0 ] = 0.0;
            par[ 1 ] = 0.0;
            par[ 4 ] = -rdiam*4;
            par[ 5 ] = -par[ 4 ];
            par[ 6 ] = 0.0;

            coin = 1;

/* If the sky positions are not co-incident, and the automatic grid
   determination failed, we cannot use a grid, so warn the user. */
         } else if( par[ 0 ] == AST__BAD ) {
            msgOutif( MSG__NORM, " ", "   Automatic grid determination "
                           "failed: the detector samples do not form a "
                           "regular grid.", status );
         }
      }

/* If autogrid values were not found, use the following fixed default
   values. Do not override extenal defaults for pixel size. */
      if( !autogrid || ( autogrid && par[ 0 ] == AST__BAD ) ) {
         par[ 0 ] = 0.0;
         par[ 1 ] = 0.0;
         if (par[4] == AST__BAD || par[5] == AST__BAD ) {
           par[ 4 ] = (fbpixsize/3600.0)*AST__DD2R;
           par[ 5 ] = (fbpixsize/3600.0)*AST__DD2R;
         }
         par[ 6 ] = map_pa;
      }

/* Ensure the default pixel sizes have the correct signs. */
      if( par[ 4 ] != AST__BAD ) {
         if( !strcmp( usesys, "AZEL" ) ) {
            par[ 4 ] = fabs( par[ 4 ] );
         } else {
            par[ 4 ] = -fabs( par[ 4 ] );
         }
         par[ 5 ] = fabs( par[ 5 ] );
      }

/* See if the output cube is to include a spatial projection, or a sparse
   list of spectra. Disabled if the sparse pointer is NULL. */
      if (issparse) {
        parDef0l( "SPARSE", ( par[ 0 ] == AST__BAD ), status );
        parGet0l( "SPARSE",  &sparse, status );

      }

/* If we are producing an output cube with the XY plane being a spatial
   projection, then get the parameters describing the projection, using the
   defaults calculated above. */
      if( !sparse && *status == SAI__OK ) {
         const int ndigits = 8; /* Number of digits for deflat/deflon precision */

/* If the target is moving, display the tracking centre coordinates for
   the first time slice. */
         if( moving ) {
            astClear( skyframe, "SkyRefIs" );
            msgBlank( status );
            msgSetc( "S1", astGetC( skyframe, "Symbol(1)" ) );
            msgSetc( "S2", astGetC( skyframe, "Symbol(2)" ) );
            msgOutif( MSG__NORM, " ", "   Output sky coordinates are "
                           "(^S1,^S2) offsets from the (moving)", status );
            msgSetc( "S1", astGetC( skyframe, "Symbol(1)" ) );
            msgSetc( "S2", astGetC( skyframe, "Symbol(2)" ) );
            msgSetc( "SREF", astGetC( skyframe, "SkyRef" ) );
            msgOutif( MSG__NORM, " ", "   telescope base position, which "
                           "started at (^S1,^S2) = (^SREF).", status );
            astSet( skyframe, "SkyRefIs=Origin" );
         }

/* Set up a flag indicating that the default values calculated by autogrid
   are being used. */
         udefs = 1;

/* Ensure we have usable CRPIX1/2 values */
         if( par[ 0 ] == AST__BAD ) par[ 0 ] = 1.0;
         if( par[ 1 ] == AST__BAD ) par[ 1 ] = 1.0;

/* Get the crpix1/2 (in the interim GRID frame) to use. Note if the user
   specifies any values. These parameters have vpath=default (which is null)
   and ppath=dynamic. */
         refine_crpix = 0;
         parDef0d( "REFPIX1", par[ 0 ], status );
         parDef0d( "REFPIX2", par[ 1 ], status );
         if( *status == SAI__OK ) {
            parGet0d( "REFPIX1", refpix + 0, status );
            parGet0d( "REFPIX2", refpix + 1, status );
            if( *status == PAR__NULL ) {
               errAnnul( status );
               refine_crpix = 1;
            } else {
               par[ 0 ] = refpix[ 0 ];
               par[ 1 ] = refpix[ 1 ];
            }
         }

/* Get the sky coords reference position strings. Use the returned SkyFrame
   to format and unformat them. */
         if( par[ 2 ] != AST__BAD ) {
            int curdigits;
            curdigits = astGetI( skyframe, "digits(1)" );
            astSetI( skyframe, "digits(1)", ndigits );
            deflon = astFormat( skyframe, 1, par[ 2 ] );
            astSetI( skyframe, "digits(1)", curdigits );
            parDef0c( "REFLON", deflon, status );
         } else {
            deflon = NULL;
         }

         if( par[ 3 ] != AST__BAD ) {
            int curdigits;
            curdigits = astGetI( skyframe, "digits(2)" );
            astSetI( skyframe, "digits(2)", ndigits );
            deflat = astFormat( skyframe, 2, par[ 3 ] );
            astSetI( skyframe, "digits(2)", curdigits );
            parDef0c( "REFLAT", deflat, status );
         } else {
            deflat = NULL;
         }

         parGet0c( "REFLON", reflon, 40, status );
         parGet0c( "REFLAT", reflat, 40, status );

         if( *status == SAI__OK ) {

            if( ( deflat && strcmp( deflat, reflat ) ) ||
                  ( deflon && strcmp( deflon, reflon ) ) ) udefs = 0;

            if( astUnformat( skyframe, 1, reflon, par + 2 ) == 0 && *status == SAI__OK ) {
               msgSetc( "REFLON", reflon );
               errRep( "", "Bad value supplied for REFLON: '^REFLON'", status );
            }

            if( astUnformat( skyframe, 2, reflat, par + 3 ) == 0 && *status == SAI__OK ) {
               msgSetc( "REFLAT", reflat );
               errRep( "", "Bad value supplied for REFLAT: '^REFLAT'", status );
            }

/* Ensure the reference position in the returned SkyFrame is set to the
   supplied position (which defaults to the first telescope base pointing
   position). */
            if( !moving ){
               astSetD( skyframe, "SkyRef(1)", par[ 2 ] );
               astSetD( skyframe, "SkyRef(2)", par[ 3 ] );
            }
         }

/* Get the user defined spatial pixel size in arcsec (the calibration for
   the spectral axis is fixed by the first input data file - see
   smf_cubebounds.c). First convert the autogrid values form rads to arcsec
   and establish them as the dynamic default for "PIXSIZE". */
         nval = 0;
         if( par[ 4 ] != AST__BAD || par[ 5 ] != AST__BAD ) {
           for ( i = 4; i <= 5; i++ ) {
             if ( par[ i ] != AST__BAD ) {
               defsize[ nval ] = 0.1*NINT( fabs( par[ i ] )*AST__DR2D*36000.0 );
               nval++;
             }
           }
           /* set the dynamic default, handling case where both dimensions
              have same default. */
           if (nval == 1) {
             defsize[1] = defsize[0];
           } else if (nval == 2 && defsize[0] == defsize[1]) {
             nval = 1;
           }
           parDef1d( "PIXSIZE", nval, defsize, status );

         } else {
           /* pick a default in case something odd happens and we have
              no other values*/
           defsize[ 0 ] = fbpixsize;
           defsize[ 1 ] = defsize[ 0 ];
           nval = 2;
         }
         if (*status == SAI__OK) {
           pixsize[0] = AST__BAD;
           pixsize[1] = AST__BAD;
           parGet1d( "PIXSIZE", 2, pixsize, &nval, status );
           if (*status == PAR__NULL) {
             /* Null just defaults to what we had before */
             errAnnul( status );
             pixsize[0] = defsize[0];
             pixsize[1] = defsize[1];
             nval = 2;
           }
         }

/* If OK, duplicate the first value if only one value was supplied. */
         if( *status == SAI__OK ) {
            if( nval < 2 ) pixsize[ 1 ] = pixsize[ 0 ];

            if( defsize[ 0 ] != pixsize[ 0 ] ||
                  defsize[ 1 ] != pixsize[ 1 ] ) udefs = 0;

/* Check the values are OK. */
            if( pixsize[ 0 ] <= 0 || pixsize[ 1 ] <= 0 ) {
               msgSetd( "P1", pixsize[ 0 ] );
               msgSetd( "P2", pixsize[ 1 ] );
               *status = SAI__ERROR;
               errRep( FUNC_NAME, "Invalid pixel sizes (^P1,^P2).", status);
            }

/* Convert to rads, and set the correct signs. */
            if( par[ 4 ] == AST__BAD || par[ 4 ] < 0.0 ) {
               par[ 4 ] = -pixsize[ 0 ]*AST__DD2R/3600.0;
            } else {
               par[ 4 ] = pixsize[ 0 ]*AST__DD2R/3600.0;
            }

            if( par[ 5 ] == AST__BAD || par[ 5 ] < 0.0 ) {
               par[ 5 ] = -pixsize[ 1 ]*AST__DD2R/3600.0;
            } else {
               par[ 5 ] = pixsize[ 1 ]*AST__DD2R/3600.0;
            }

         }

/* Convert the autogrid CROTA value from rads to degs and set as the
   dynamic default for parameter CROTA (the position angle of the output
   Y axis, in degrees). The get the CROTA value and convert to rads. */
         if( par[ 6 ] != AST__BAD ) {
            autorot = par[ 6 ]*AST__DR2D;
            parDef0d( "CROTA", autorot, status );

         } else {
            parDef0d( "CROTA", map_pa*AST__DR2D, status );
            autorot = AST__BAD;
         }

         parGet0d( "CROTA", par + 6, status );
         if( par[ 6 ] != autorot ) udefs = 0;
         par[ 6 ] *= AST__DD2R;

/* If any parameter were given explicit values which differ from the
   autogrid default values, then we need to re-calculate the optimal CRPIX1/2
   values. We also do this if all the points are effectively co-incident. */
         if( ( coin || !udefs ) && autogrid && refine_crpix ) {
            par[ 0 ] = AST__BAD;
            par[ 1 ] = AST__BAD;
            kpg1Opgrd( nallpos, allpos, strcmp( usesys, "AZEL" ), par,
                       &rdiam, status );
         }

/* Display the projection parameters being used. */
         smf_display_projpars( skyframe, par, status );

/* Write out the reference grid coords to output parameter PIXREF. */
         parPut1d( "PIXREF", 2, par, status );

/* If no grid was found, indicate that no spatial projection will be used. */
      } else {
         msgBlank( status );
         msgOutif( MSG__NORM, " ", "   The output will be a sparse array "
                        "containing a list of spectra.", status );
      }

/* If we have a pre-defined spatial projection, indicate that the output
   array need not be sparse. */
   } else {
      sparse = 0;
   }

/* Return usedefs if requested */
   if( usedefs ) {
     *usedefs = udefs;
   }

/* Set sparse if requested */
   if( issparse ) *issparse = sparse;

}
예제 #15
0
int getI( void * fset, const QString & key ) {
    std::string keys = key.toStdString();
    return astGetI( fset, keys.c_str());
}
예제 #16
0
/* Main entry */
void smf_jsadicer( int indf, const char *base, int trim, smf_inst_t instrument,
                   smf_jsaproj_t proj, size_t *ntile, Grp *grp, int *status ){

/* Local Variables: */
   AstBox *box;
   AstFitsChan *fc;
   AstFrame *specfrm = NULL;
   AstFrame *tile_frm = NULL;
   AstFrameSet *iwcs;
   AstFrameSet *tfs = NULL;
   AstFrameSet *tile_wcs;
   AstMapping *ndf_map = NULL;
   AstMapping *p2pmap = NULL;
   AstMapping *specmap = NULL;
   AstMapping *tile_map = NULL;
   AstRegion *region;
   Grp *grpt = NULL;
   char *path;
   char dtype[ NDF__SZFTP + 1 ];
   char jsatile_comment[45];
   char type[ NDF__SZTYP + 1 ];
   const char *dom = NULL;
   const char *keyword;
   const char *latsys = NULL;
   const char *lonsys = NULL;
   double *pd;
   double dlbnd[3];
   double dubnd[3];
   double gcen[3];
   double lbnd_in[3];
   double lbnd_out[3];
   double ubnd_in[3];
   double ubnd_out[3];
   float *pf;
   int *created_tiles = NULL;
   int *tiles;
   int axlat;
   int axlon;
   int axspec;
   int bbox[ 6 ];
   int i;
   int ifrm;
   int igrid;
   int indfo;
   int indfs;
   int indfx;
   int inperm[3];
   int ipixel;
   int ishpx;
   int isxph;
   int itile;
   int ix;
   int iy;
   int iz;
   int junk;
   int latax = -1;
   int lbnd[3];
   int lbnd_tile[ 3 ];
   int lbndx[ NDF__MXDIM ];
   int lonax = -1;
   int nbase;
   int ndim;
   int ndimx;
   int nfrm;
   int nsig;
   int ntiles;
   int olbnd[ 3 ];
   int oubnd[ 3 ];
   int outperm[ 3 ];
   int place;
   int qual;
   int tile_index;
   int tile_lbnd[2];
   int tile_ubnd[2];
   int ubnd[3];
   int ubnd_tile[ 3 ];
   int ubndx[ NDF__MXDIM ];
   int var;
   size_t iext;
   size_t size;
   smfJSATiling tiling;
   unsigned char *ipq = NULL;
   void *ipd = NULL;
   void *ipv = NULL;

/* Initialise */
   *ntile = 0;

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST context. */
   astBegin;

/* Begin an NDF context. */
   ndfBegin();

/* Note the used length of the supplied base string. If it ends with
   ".sdf", reduce it by 4. */
   nbase = astChrLen( base );
   if( !strcmp( base + nbase - 4, ".sdf" ) ) nbase -= 4;

/* Allocate a buffer large enough to hold the full path for an output NDF. */
   path = astMalloc( nbase + 25 );

/* Get the WCS from the NDF. */
   kpg1Gtwcs( indf, &iwcs, status );

/* Note if the NDF projection is HPX or XPH. */
   ishpx = astChrMatch( astGetC( iwcs, "Projection" ), "HEALPix" );
   isxph = astChrMatch( astGetC( iwcs, "Projection" ), "polar HEALPix" );

/* Report an error if the NDFs projection is neither of these. */
   if( !ishpx && !isxph && *status == SAI__OK ) {
      ndfMsg( "N", indf );
      *status = SAI__ERROR;
      errRep( "", "The input NDF (^N) does not appear to be gridded "
              "on the JSA all-sky pixel grid.", status );
   }

/* Get the bounds of the NDF in pixel indices and the the corresponding
   double precision GRID bounds (reduce the size of the grid by a small
   amount to avoid problems with tiles that are on the edge of the valid sky
   regions - astMapRegion can report an error for such tiles). Also store
   the GRID coords of the centre. Also count the number of significant
   pixel axes. */
   ndfBound( indf, 3, lbnd, ubnd, &ndim, status );
   nsig = 0;
   for( i = 0; i < ndim; i++ ) {
      dlbnd[ i ] = 0.5 + 0.1;
      dubnd[ i ] = ubnd[ i ] - lbnd[ i ]  + 1.5 - 0.1;
      gcen[ i ] = 0.5*( dlbnd[ i ] + dubnd[ i ] );
      if( ubnd[ i ] > lbnd[ i ] ) nsig++;
   }

/* Find the one-based indices of the RA, Dec and spectral axes in the
   current Frame of the NDF. */
   axlon = 0;
   if( astGetI( iwcs, "IsLonAxis(1)" ) ) {
      axlon = 1;
      lonsys = astGetC( iwcs, "System(1)" );
   } else if( astGetI( iwcs, "IsLonAxis(2)" ) ) {
      axlon = 2;
      lonsys = astGetC( iwcs, "System(2)" );
   } else if( ndim == 3 && astGetI( iwcs, "IsLonAxis(3)" ) ) {
      axlon = 3;
      lonsys = astGetC( iwcs, "System(3)" );
   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: Cannot find the longitude axis in the "
              "input NDF.", status );
   }

   axlat = 0;
   if( astGetI( iwcs, "IsLatAxis(1)" ) ) {
      axlat = 1;
      latsys = astGetC( iwcs, "System(1)" );
   } else if( astGetI( iwcs, "IsLatAxis(2)" ) ) {
      axlat = 2;
      latsys = astGetC( iwcs, "System(2)" );
   } else if( ndim == 3 && astGetI( iwcs, "IsLatAxis(3)" ) ) {
      axlat = 3;
      latsys = astGetC( iwcs, "System(3)" );
   } else if( *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: Cannot find the latitude axis in the "
              "input NDF.", status );
   }

   axspec = 6 - axlon - axlat;

/* Report an error if the spatial axes are not ICRS RA and Dec. */
   if( ( lonsys && strcmp( lonsys, "ICRS" ) ) ||
       ( latsys && strcmp( latsys, "ICRS" ) ) ) {
      if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         ndfMsg( "N", indf );
         errRep( "", "smf_jsadicer: The spatial axes in '^N' are not "
                 "ICRS RA and Dec.", status );
      }
   }

/* Create a Box describing the region covered by the NDF pixel grid in
   GRID coords. */
   box = astBox( astGetFrame( iwcs, AST__BASE ), 1, dlbnd, dubnd,
                 AST__NULL, " " );

/* Map this Box into the current WCS Frame of the NDF. */
   region = astMapRegion( box, iwcs, iwcs );

/* If no instrument was specified, we will determine the instrument from
   the contexts of the FITS extension. Copy the NDF FITS extension to a
   FitsChan. Annul the error if the NDF no FITS extension. */
   if( instrument == SMF__INST_NONE && *status == SAI__OK ) {
      kpgGtfts( indf, &fc, status );
      if( *status == KPG__NOFTS ) {
         errAnnul( status );
         fc = NULL;
      }
   } else {
      fc = NULL;
   }

/* Get the parameters of the required tiling scheme. */
   smf_jsainstrument( NULL, fc, instrument, &tiling, status );

/* Get a list of the JSA tiles touched by the supplied NDF. */
   tiles = smf_jsatiles_region( region, &tiling, &ntiles, status );
   if( ntiles == 0 && *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRep( "", "smf_jsadicer: No JSA tiles found touching supplied NDF "
              "(programming error).", status );
   }

/* Does the input NDF have a Variance component? */
   ndfState( indf, "Variance", &var, status );

/* Does the input NDF have a Quality component? */
   ndfState( indf, "Quality", &qual, status );

/* Decide on the data type to use: _REAL or _DOUBLE. */
   ndfMtype( "_REAL,_DOUBLE", indf, indf, "Data", type, sizeof(type), dtype,
             sizeof(dtype), status );

/* Tell the user what is happening. */
   msgBlank( status );
   msgOutf( "", "Dicing %s into JSA tiles:", status,
            ( nsig == 2 ) ? "map" : "cube" );

/* Loop round all tiles that overlap the supplied NDF. */
   for( itile = 0; itile < ntiles && *status == SAI__OK; itile++ ) {
      tile_index = tiles[ itile ];

/* Get the spatial pixel bounds of the current tile within the requested
   JSA all-sky projection. Also get the (2D) WCS FrameSet for the tile. */
      smf_jsatile( tile_index, &tiling, 0, proj, NULL, &tile_wcs, NULL,
                   tile_lbnd, tile_ubnd, status );

/* Extract the tile pixel->WCS mapping and WCS Frame. We know the indices
   of the required Frames because they are hard-wired in smf_jsatile. */
      tile_map = astGetMapping( tile_wcs, 3, 2 );
      tile_frm = astGetFrame( tile_wcs, 2 );

/* Find the indices of the grid and pixel frames in the input NDF. */
      ipixel = -1;
      igrid = astGetI( iwcs, "Base" );
      nfrm = astGetI( iwcs, "NFrame" );
      for( ifrm = 0; ifrm < nfrm; ifrm++ ) {
         dom = astGetC( astGetFrame( iwcs, ifrm + 1 ), "Domain" );
         if( astChrMatch( dom, "PIXEL" ) ) ipixel = ifrm + 1;
      }

/* If required, extract the pixel->spectral mapping and spectral frame in
   the input NDF, and add it in parallel with the above tile mapping. */
      if( ndim == 3 ) {
         astSetI( iwcs, "Base", ipixel );
         tfs = atlFrameSetSplit( iwcs, "DSBSPECTRUM SPECTRUM", NULL,
                                 NULL, status );
         astSetI( iwcs, "Base", igrid );
         if( tfs ) {
            specmap = astGetMapping( tfs, AST__BASE, AST__CURRENT );
            specfrm = astGetFrame( tfs, AST__CURRENT );
         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            ndfMsg( "N", indf );
            errRep( "", "smf_jsadicer: Cannot find the spectral axis "
                    "in '^N'.", status );
         }

         tile_map = (AstMapping *) astCmpMap( tile_map, specmap, 0, " " );
         tile_frm = (AstFrame *) astCmpFrame( tile_frm, specfrm, " " );
      }

/* Ensure the Epoch is inherited form the input NDF. */
      astSetD( tile_frm, "Epoch", astGetD( iwcs, "Epoch" ) );

/* Currently tile axis 1 is RA, axis 2 is Dec and axis 3 (if present) is
   spectral. Append a PermMap that re-orders these tile WCS axes to match
   those of the NDF. */
      outperm[ axlon - 1 ] = 1;
      outperm[ axlat - 1 ] = 2;
      outperm[ axspec - 1 ] = 3;
      inperm[ 0 ] = axlon;
      inperm[ 1 ] = axlat;
      inperm[ 2 ] = axspec;
      tile_map = (AstMapping *) astCmpMap( tile_map, astPermMap( ndim, inperm,
                                                                 ndim, outperm,
                                                                 NULL, " " ),
                                           1, " " );
      tile_map = astSimplify( tile_map );

/* Also re-order the WCS axes in the tile frame. */
      astPermAxes( tile_frm, outperm );

/* We want the zero-based indicies of the input pixel axes corresponding
   to ra, dec and spectral. So find the indicies of the pixel axes in the
   supplied NDF that are most closely aligned with each WCS axis. */
      atlPairAxes( iwcs, NULL, gcen, NULL, inperm, status );
      if( inperm[ 0 ] == axlon ) {
         lonax = 0;
      } else if( inperm[ 1 ] == axlon ) {
         lonax = 1;
      } else {
         lonax = 2;
      }
      if( inperm[ 0 ] == axlat ) {
         latax = 0;
      } else if( inperm[ 1 ] == axlat ) {
         latax = 1;
      } else {
         latax = 2;
      }

/* To get the mapping from pixel coords in the input NDF to pixel coords
   in the output NDF, we invert the above mapping so that it goes from WCS
   to pixel, and append it to the end of the NDF pixel->WCS mapping. */
      ndf_map = astGetMapping( iwcs, ipixel, AST__CURRENT );
      astInvert( tile_map );
      p2pmap = (AstMapping *) astCmpMap( ndf_map, tile_map, 1, " " );
      p2pmap = astSimplify( p2pmap );
      astInvert( tile_map );

/* Show the bounds of the tile within the input NDF. */
      msgOutiff( MSG__DEBUG, "", "   tile %d has bounds (%d:%d,%d:%d) "
                 "within the output NDF.", status, tile_index,
                 tile_lbnd[ 0 ], tile_ubnd[ 0 ], tile_lbnd[ 1 ],
                 tile_ubnd[ 1 ] );

/* Next job is to find the pixel bounds of the output NDF to create
   which will hold data for the current tile. First map the pixel bounds
   of the whole tile from output to input. */
      lbnd_in[ 0 ] = tile_lbnd[ 0 ] - 0.5;
      lbnd_in[ 1 ] = tile_lbnd[ 1 ] - 0.5;
      lbnd_in[ 2 ] = lbnd[ 2 ] - 0.5;
      ubnd_in[ 0 ] = tile_ubnd[ 0 ] - 0.5;
      ubnd_in[ 1 ] = tile_ubnd[ 1 ] - 0.5;
      ubnd_in[ 2 ] = ubnd[ 2 ] - 0.5;

      astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 1, lbnd_out + 0,
                 ubnd_out + 0, NULL, NULL );
      astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 2, lbnd_out + 1,
                 ubnd_out + 1, NULL, NULL );
      if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 0, 3,
                                 lbnd_out + 2, ubnd_out + 2, NULL,
                                 NULL );


      lbnd_tile[ 0 ] = floor( lbnd_out[ 0 ] ) + 1;
      lbnd_tile[ 1 ] = floor( lbnd_out[ 1 ] ) + 1;
      lbnd_tile[ 2 ] = floor( lbnd_out[ 2 ] ) + 1;
      ubnd_tile[ 0 ] = floor( ubnd_out[ 0 ] ) + 1;
      ubnd_tile[ 1 ] = floor( ubnd_out[ 1 ] ) + 1;
      ubnd_tile[ 2 ] = floor( ubnd_out[ 2 ] ) + 1;

/* Show the bounds of the tile within the input NDF. */
      msgOutiff( MSG__DEBUG, "", "   tile %d has bounds (%d:%d,%d:%d) "
                 "within the input NDF.", status, tile_index,
                 lbnd_tile[ 0 ], ubnd_tile[ 0 ], lbnd_tile[ 1 ],
                 ubnd_tile[ 1 ] );

/* If required, trim the bounds to the extent of the input NDF. */
      if( trim ) {
         if( lbnd_tile[ 0 ] < lbnd[ 0 ] ) lbnd_tile[ 0 ] = lbnd[ 0 ];
         if( lbnd_tile[ 1 ] < lbnd[ 1 ] ) lbnd_tile[ 1 ] = lbnd[ 1 ];
         if( lbnd_tile[ 2 ] < lbnd[ 2 ] ) lbnd_tile[ 2 ] = lbnd[ 2 ];
         if( ubnd_tile[ 0 ] > ubnd[ 0 ] ) ubnd_tile[ 0 ] = ubnd[ 0 ];
         if( ubnd_tile[ 1 ] > ubnd[ 1 ] ) ubnd_tile[ 1 ] = ubnd[ 1 ];
         if( ubnd_tile[ 2 ] > ubnd[ 2 ] ) ubnd_tile[ 2 ] = ubnd[ 2 ];
      }

/* Check there is some overlap. */
      if( lbnd_tile[ 0 ] <= ubnd_tile[ 0 ] &&
          lbnd_tile[ 1 ] <= ubnd_tile[ 1 ] &&
          lbnd_tile[ 2 ] <= ubnd_tile[ 2 ] ){

/* Now need to check if this section of the input NDF contains any good
   values. We also find the bounding box of the good values (within the
   input pixel coordinate system). So first obtain and map the required
   section of the input NDF. */
         ndfSect( indf, ndim, lbnd_tile, ubnd_tile, &indfs, status );
         ndfMap( indfs, "Data", type, "Read", &ipd, &junk, status );
         if( var ) ndfMap( indfs, "Variance", type, "Read", &ipv, &junk, status );
         if( qual ) ndfMap( indfs, "Quality", "_UBYTE", "Read", (void **) &ipq,
                            &junk, status );

/* Initialise the pixel bounds (within the input NDF) of the box holding
   good data values for the current tile. */
         bbox[ 0 ] = INT_MAX;
         bbox[ 1 ] = INT_MAX;
         bbox[ 2 ] = INT_MAX;
         bbox[ 3 ] = -INT_MAX;
         bbox[ 4 ] = -INT_MAX;
         bbox[ 5 ] = -INT_MAX;

/* Loop round all pixels in the section. */
         if( *status == SAI__OK ) {
            if( !strcmp( type, "_REAL" ) ) {
               pf = (float *) ipd;
               for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) {
                  for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) {
                     for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) {
                        if( *(pf++) != VAL__BADR ) {
                           if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix;
                           if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy;
                           if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz;
                           if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix;
                           if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy;
                           if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz;
                        }
                     }
                  }
               }
            } else {
               pd = (double *) ipd;
               for( iz = lbnd_tile[ 2 ]; iz <= ubnd_tile[ 2 ]; iz++ ) {
                  for( iy = lbnd_tile[ 1 ]; iy <= ubnd_tile[ 1 ]; iy++ ) {
                     for( ix = lbnd_tile[ 0 ]; ix <= ubnd_tile[ 0 ]; ix++ ) {
                        if( *(pd++) != VAL__BADD ) {
                           if( ix < bbox[ 0 ] ) bbox[ 0 ] = ix;
                           if( iy < bbox[ 1 ] ) bbox[ 1 ] = iy;
                           if( iz < bbox[ 2 ] ) bbox[ 2 ] = iz;
                           if( ix > bbox[ 3 ] ) bbox[ 3 ] = ix;
                           if( iy > bbox[ 4 ] ) bbox[ 4 ] = iy;
                           if( iz > bbox[ 5 ] ) bbox[ 5 ] = iz;
                        }
                     }
                  }
               }
            }

/* Skip empty tiles. */
            if( bbox[ 0 ] != INT_MAX ) {
               msgOutf( "", "   tile %d", status, tile_index );

/* If required, trim the bounds to the edges of the bounding box. */
               if( trim >= 2 ) {
                  olbnd[ 0 ] = bbox[ 0 ];
                  olbnd[ 1 ] = bbox[ 1 ];
                  olbnd[ 2 ] = bbox[ 2 ];
                  oubnd[ 0 ] = bbox[ 3 ];
                  oubnd[ 1 ] = bbox[ 4 ];
                  oubnd[ 2 ] = bbox[ 5 ];
               } else {
                  olbnd[ 0 ] = lbnd_tile[ 0 ];
                  olbnd[ 1 ] = lbnd_tile[ 1 ];
                  olbnd[ 2 ] = lbnd_tile[ 2 ];
                  oubnd[ 0 ] = ubnd_tile[ 0 ];
                  oubnd[ 1 ] = ubnd_tile[ 1 ];
                  oubnd[ 2 ] = ubnd_tile[ 2 ];
               }

/* Modify these pixel bounds so that they refer to the output NDF. */
               lbnd_in[ 0 ] = olbnd[ 0 ] - 0.5;
               lbnd_in[ 1 ] = olbnd[ 1 ] - 0.5;
               lbnd_in[ 2 ] = olbnd[ 2 ] - 0.5;
               ubnd_in[ 0 ] = oubnd[ 0 ] - 0.5;
               ubnd_in[ 1 ] = oubnd[ 1 ] - 0.5;
               ubnd_in[ 2 ] = oubnd[ 2 ] - 0.5;

               astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 1, lbnd_out + 0,
                          ubnd_out + 0, NULL, NULL );
               astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 2, lbnd_out + 1,
                          ubnd_out + 1, NULL, NULL );
               if( ndim == 3 ) astMapBox( p2pmap, lbnd_in, ubnd_in, 1, 3,
                                          lbnd_out + 2, ubnd_out + 2, NULL,
                                          NULL );

               olbnd[ 0 ] = floor( lbnd_out[ 0 ] ) + 1;
               olbnd[ 1 ] = floor( lbnd_out[ 1 ] ) + 1;
               olbnd[ 2 ] = floor( lbnd_out[ 2 ] ) + 1;
               oubnd[ 0 ] = floor( ubnd_out[ 0 ] ) + 1;
               oubnd[ 1 ] = floor( ubnd_out[ 1 ] ) + 1;
               oubnd[ 2 ] = floor( ubnd_out[ 2 ] ) + 1;

/* Get the full path to the output NDF for the current tile, and create an
   NDF placeholder for it. */
               sprintf( path, "%.*s_%d", nbase, base, tile_index );
               ndfPlace( NULL, path, &place, status );

/* Create a new output NDF by copying the meta-data from the input NDF
   section. */
               ndfScopy( indfs, "Units", &place, &indfo, status );

/* Set the pixel bounds of the output NDF to the values found above and copy
   the input data for the current tile into it. */
               smf1_jsadicer( indfo, olbnd, oubnd, tile_map, tile_frm, p2pmap,
                              ipd, ipv, ipq, status );

/* Add the name of this output NDF to the group holding the names of the
   output NDFs that have actually been created. */
               if( grp ) grpPut1( grp, path, 0, status );

/* Add a TILENUM header to the output FITS extension. */
               kpgGtfts( indfo, &fc, status );
               if( *status == KPG__NOFTS ) {
                  errAnnul( status );
                  fc = astFitsChan( NULL, NULL, " " );

/* If the last card is "END", remove it. */
               } else {
                  astSetI( fc, "Card", astGetI( fc, "NCARD" ) );
                  keyword = astGetC( fc, "CardName" );
                  if( keyword && !strcmp( keyword, "END" ) ) astDelFits( fc );
               }

               one_snprintf(jsatile_comment, 45, "JSA all-sky tile index (Nside=%i)",
                            status, tiling.ntpf);
               atlPtfti( fc, "TILENUM", tile_index, jsatile_comment, status );
               kpgPtfts( indfo, fc, status );
               fc = astAnnul( fc );

/* Now store an STC-S polygon that describes the shortest boundary
   enclosing the good data in the output NDF, and store it as an NDF extension. */
               kpgPutOutline( indfo, 0.5, 1, status );

/* We now reshape any extension NDFs contained within the output NDF to
   have the same spatial bounds as the main NDF (but only for extension
   NDFs that originally have the same spatial bounds as the supplied NDF).
   Get a group containing paths to all extension NDFs in the output NDF. */
               ndgMoreg( indfo, &grpt, &size, status );

/* Loop round each output extension NDF. */
               for( iext = 1; iext <= size && *status == SAI__OK; iext++ ) {
                  ndgNdfas( grpt, iext, "Update", &indfx, status );

/* Get its bounds. */
                  ndfBound( indfx, NDF__MXDIM, lbndx, ubndx, &ndimx, status );

/* See if this extension NDF has the same bounds on the spatial axes as
   the supplied NDF. */
                  if( ndimx > 1 && lbndx[ lonax ] == lbnd[ lonax ] &&
                                   lbndx[ latax ] == lbnd[ latax ] &&
                                   ubndx[ lonax ] == ubnd[ lonax ] &&
                                   ubndx[ latax ] == ubnd[ latax ] ) {

/* If so, change the bounds of the output extension NDF so that they are
   the same as the main NDF on the spatial axes, and map the original
   contents of the NDF onto the new pixel grid. */
                     smf1_jsadicer( indfx, olbnd, oubnd, tile_map, tile_frm, p2pmap,
                                    NULL, NULL, NULL, status );
                  }

/* Annul the extension NDF identifier. */
                  ndfAnnul( &indfx, status );
               }

/* Free resources associated with the current tile. */
               grpDelet( &grpt, status );
               ndfAnnul( &indfo, status );

/* Issue warnings about empty tiles. */
            } else {
               msgOutiff( MSG__VERB, "", "   tile %d is empty and so will not be "
                          "created", status, tile_index );
            }
         }

/* Free the section of the input NDF. */
         ndfAnnul( &indfs, status );

/* Append the index of this tile in the list of tiles to be created. */
         created_tiles = astGrow( created_tiles, ++(*ntile),
                                  sizeof( *created_tiles ) );
         if( *status == SAI__OK ) created_tiles[ *ntile - 1 ] = tile_index;

      } else {
         msgOutiff( MSG__DEBUG, "", "   Tile %d does not overlap the input "
                    "NDF after trimming.", status, tile_index );
      }
   }
   msgBlank( status );

/* Write the indicies of the created tiles out to a parameter. */
   if( *ntile ) parPut1i( "JSATILELIST", *ntile, created_tiles, status );

/* Free resources. */
   created_tiles = astFree( created_tiles );
   tiles = astFree( tiles );
   path = astFree( path );

/* End the NDF context. */
   ndfEnd( status );

/* End the AST context. */
   astEnd;

}
예제 #17
0
void smf_calc_iqu( ThrWorkForce *wf, smfData *data, int block_start,
                  int block_end, int ipolcrd, int qplace, int uplace,
                  int iplace, NdgProvenance *oprov, AstFitsChan *fc,
                  int pasign, double paoff, double angrot, int submean,
                  int *status ){

/* Local Variables: */
   AstFrameSet *wcs;          /* WCS FrameSet for output NDFs */
   AstWinMap *wm;             /* Mapping to reverse the X GRID axis */
   const JCMTState *state;    /* JCMTState info for current time slice */
   dim_t nbolo;               /* No. of bolometers */
   dim_t ncol;                /* No. of columns of bolometers */
   dim_t nrow;                /* No. of rows of bolometers */
   dim_t ntslice;             /* Number of time-slices in data */
   double *ipi;               /* Pointer to output I array */
   double *ipq;               /* Pointer to output Q array */
   double *ipu;               /* Pointer to output U array */
   double ina[ 2 ];           /* Bolometer coords at bottom left */
   double inb[ 2 ];           /* Bolometer coords at top right */
   double outa[ 2 ];          /* NDF GRID coords at bottom left */
   double outb[ 2 ];          /* NDF GRID coords at top right */
   int bstep;                 /* Bolometer step between threads */
   int el;                    /* Number of mapped array elements */
   int indfi;                 /* Identifier for NDF holding I values */
   int indfq;                 /* Identifier for NDF holding Q values */
   int indfu;                 /* Identifier for NDF holding Q values */
   int itime;                 /* Time slice index */
   int iworker;               /* Index of a worker thread */
   int lbnd[ 2 ];             /* Lower pixel bounds of output NDF */
   int ntime;                 /* Time slices to check */
   int nworker;               /* No. of worker threads */
   int old;                   /* Data has old-style POL_ANG values? */
   int ubnd[ 2 ];             /* Upper pixel bounds of output NDF */
   size_t bstride;            /* Stride between adjacent bolometer values */
   size_t tstride;            /* Stride between adjacent time slice values */
   smfCalcIQUJobData *job_data = NULL; /* Pointer to all job data */
   smfCalcIQUJobData *pdata = NULL;/* Pointer to next job data */
   smfHead *hdr;              /* Pointer to data header this time slice */
   double *mean;
   int tstep;                 /* Time slice step between threads */

/* Check the inherited status. */
   if( *status != SAI__OK ) return;

/* Convenience pointers. */
   hdr = data->hdr;

/* Obtain number of time slices - will also check for 3d-ness. Also get
   the dimensions of the bolometer array and the strides between adjacent
   bolometer values. */
   smf_get_dims( data, &nrow, &ncol, &nbolo, &ntslice, NULL, &bstride,
                 &tstride, status );

/* Report an error if the block of time slices extends of either end. */
   if( block_start < 0 || block_end >= (int) ntslice ) {
      if( *status == SAI__OK ) {
         *status = SAI__ERROR;
         msgSeti( "S", block_start );
         msgSeti( "E", block_end );
         msgSeti( "N", ntslice );
         errRep( " ", "smf_calc_iqu: invalid block of time slices - ^S to "
                 "^E (^N time slices are available).", status );
      }
   }

/* Create the output NDFs. Each one is a 2D array with dimensions
   equal to the bolometer array. */
   lbnd[ 0 ] = 1;
   lbnd[ 1 ] = 1;
   ubnd[ 0 ] = ncol;
   ubnd[ 1 ] = nrow;
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &qplace, &indfq, status );
   ndfNew( "_DOUBLE", 2, lbnd, ubnd, &uplace, &indfu, status );
   if( iplace != NDF__NOPL ) {
      ndfNew( "_DOUBLE", 2, lbnd, ubnd, &iplace, &indfi, status );
   } else {
      indfi = NDF__NOID;
   }

/* Store any supplied provenance in all NDFs. */
   if( oprov ) {
      ndgWriteProv( oprov, indfq, 1, status );
      ndgWriteProv( oprov, indfu, 1, status );
      if( indfi != NDF__NOID ) ndgWriteProv( oprov, indfi, 1, status );
   }

/* Store any supplied FITS headers in all NDFs.*/
   if( fc && astGetI( fc, "NCard" ) > 0 ) {
      kpgPtfts( indfq, fc, status );
      kpgPtfts( indfu, fc, status );
      if( indfi != NDF__NOID )  kpgPtfts( indfi, fc, status );
   }

/* Store the WCS frameSet in all NDFs. First get the FrameSet for the
   central time slice in the block, and set its current Frame to the
   tracking frame. */
   smf_tslice_ast( data, ( block_start + block_end )/2, 1, status);
   astSetC( hdr->wcs, "System",
            sc2ast_convert_system( (data->hdr->allState)[0].tcs_tr_sys,
                                    status ) );

/* Take a copy and then reverse the X axis of the GRID Frame by remaping the
   base Frame using a WinMap. This produces a pixel grid such as you would
   see by looking up at the sky from underneath the array, rather than looking
   down at the ground from above the array. */
   wcs = astCopy( hdr->wcs );
   ina[ 0 ] = 1.0;
   inb[ 0 ] = ncol;
   ina[ 1 ] = 1.0;
   inb[ 1 ] = nrow;

   outa[ 0 ] = ncol;
   outb[ 0 ] = 1.0;
   outa[ 1 ] = 1.0;
   outb[ 1 ] = nrow;

   wm = astWinMap( 2, ina, inb, outa, outb, " " );
   astRemapFrame( wcs, AST__BASE, wm );
   wm = astAnnul( wm );

/* Store the FrameSet in the output NDFs, then annull the copy. */
   ndfPtwcs( wcs, indfq, status );
   ndfPtwcs( wcs, indfu, status );
   if( indfi != NDF__NOID ) ndfPtwcs( wcs, indfi, status );
   wcs = astAnnul( wcs );

/* Map the Data array in each NDF. */
   ndfMap( indfq, "Data", "_DOUBLE", "WRITE", (void **) &ipq, &el, status );
   ndfMap( indfu, "Data", "_DOUBLE", "WRITE", (void **) &ipu, &el, status );
   if( indfi != NDF__NOID ) {
      ndfMap( indfi, "Data", "_DOUBLE", "WRITE", (void **) &ipi, &el, status );
   } else {
      ipi = NULL;
   }


/* If required, allocate memory to hold the mean bolometer value at each
   time slice. */
   mean = submean ? astMalloc( ntslice*sizeof( *mean ) ) : NULL;

/* Create structures used to pass information to the worker threads. */
   nworker = wf ? wf->nworker : 1;
   job_data = astMalloc( nworker*sizeof( *job_data ) );

/* Check the above pointers can be used safely. */
   if( *status == SAI__OK ) {

/* Go through the first thousand POL_ANG values to see if they are in
   units of radians (new data) or arbitrary encoder units (old data).
   They are assumed to be in radians if no POL_ANG value is larger than
   20. */
      old = 0;
      state = hdr->allState;
      ntime = ( ntslice > 1000 ) ? 1000 : ntslice;
      for( itime = 0; itime < ntime; itime++,state++ ) {
         if( state->pol_ang > 20 ) {
            old = 1;
            msgOutif( MSG__VERB, "","   POL2 data contains POL_ANG values "
                      "in encoder units - converting to radians.", status );
            break;
         }
      }

/* If required, find the mean bolometer value at each time slice. */
      if( submean ) {

/* Determine which time-slices are to be processed by which threads. */
         tstep = ntslice/nworker;
         if( tstep < 1 ) tstep = 1;

         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;
            pdata->block_start = iworker*tstep;
            if( iworker < nworker - 1 ) {
               pdata->block_end = pdata->block_start + tstep - 1;
            } else {
               pdata->block_end = ntslice - 1;
            }
         }

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
         for( iworker = 0; iworker < nworker; iworker++ ) {
            pdata = job_data + iworker;

            pdata->bstride = bstride;
            pdata->dat = data->pntr[0];
            pdata->nbolo = nbolo;
            pdata->qua = smf_select_qualpntr( data, NULL, status );;
            pdata->tstride = tstride;
            pdata->mean = mean;
            pdata->action = 1;

/* Pass the job to the workforce for execution. */
            thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                         status );
         }

/* Wait for the workforce to complete all jobs. */
         thrWait( wf, status );

      }

/* Determine which bolometers are to be processed by which threads. */
      bstep = nbolo/nworker;
      if( bstep < 1 ) bstep = 1;

      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;
         pdata->b1 = iworker*bstep;
         pdata->b2 = pdata->b1 + bstep - 1;
      }

/* Ensure that the last thread picks up any left-over bolometers */
      pdata->b2 = nbolo - 1;

/* Store all the other info needed by the worker threads, and submit the
   jobs to calculate the Q and U values in each bolo, and then wait for
   them to complete. */
      for( iworker = 0; iworker < nworker; iworker++ ) {
         pdata = job_data + iworker;

         pdata->bstride = bstride;
         pdata->dat = data->pntr[0];;
         pdata->nbolo = nbolo;
         pdata->qua = smf_select_qualpntr( data, NULL, status );;
         pdata->tstride = tstride;
         pdata->allstates = hdr->allState;
         pdata->ipq = ipq;
         pdata->ipu = ipu;
         pdata->ipi = ipi;
         pdata->ipolcrd = ipolcrd;
         pdata->block_start = block_start;
         pdata->block_end = block_end;
         pdata->old = old;
         pdata->ncol = ncol;
         pdata->pasign = pasign ? +1: -1;
         pdata->paoff = paoff;
         pdata->angrot = angrot;
         pdata->action = 0;
         pdata->mean = mean;

/* Pass the job to the workforce for execution. */
         thrAddJob( wf, THR__REPORT_JOB, pdata, smf1_calc_iqu_job, 0, NULL,
                      status );
      }

/* Wait for the workforce to complete all jobs. */
      thrWait( wf, status );
   }

/* Add POLANAL Frames to the WCS FrameSet in each output NDF. This Frame
   is used by POLPACK to determine the reference direction of the Stokes
   vectors (focal plane Y in this case, i.e. zero-based axis 1 ). */
   smf_polext( indfq, 0, 0.0, "FPLANE", 1, status );
   smf_polext( indfu, 0, 0.0, "FPLANE", 1, status );
   if( ipi ) smf_polext( indfi, 0, 0.0, "FPLANE", 1, status );

/* Free the two output NDFs. */
   ndfAnnul( &indfq, status );
   ndfAnnul( &indfu, status );
   if( ipi ) ndfAnnul( &indfi, status );

/* Free other resources. */
   job_data = astFree( job_data );
   mean = astFree( mean );
}
예제 #18
0
void smf_add_spectral_axis( int indf, AstFitsChan *fc, int *status ){

/* Local Variables */
   AstFrame *cfrm;         /* Pointer to the current WCS Frame in the NDF */
   AstFrameSet *wcs;       /* Pointer to the WCS FrameSet for the NDF */
   AstSpecFrame *specfrm;  /* Pointer to the new SpecFrame */
   AstWinMap *specmap;     /* Pointer to Mapping from GRID to wavelength */
   char attrib[ 10 ];      /* Buffer for attribute name */
   double bandwid;         /* Bandwidth, in metres */
   double grid_hi;         /* GRID coord at upper edge of spectral pixel */
   double grid_lo;         /* GRID coord at lower edge of spectral pixel */
   double ref_lat;         /* Celestial latitude at reference point */
   double ref_lon;         /* Celestial longitude at reference point */
   double spec_hi;         /* Wavelength at upper edge of spectral pixel */
   double spec_lo;         /* Wavelength at lower edge of spectral pixel */
   double wavelen;         /* Central wavelength, in metres */
   int lbnd[ NDF__MXDIM ]; /* Original lower pixel bounds of the NDF */
   int ndim;               /* Original number of pixel axis in the the NDF */
   int ubnd[ NDF__MXDIM ]; /* Original lower pixel bounds of the NDF */

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST Object context so that we do not need to annul explicitly
   the AST Objects created in this function. */
   astBegin;

/* Get the pixel bounds of the NDF. */
   ndfBound( indf, NDF__MXDIM, lbnd, ubnd, &ndim, status );

/* Get the required FITS header. Return without further action if either
   is not present in the supplied FitsChan, or if the NDF is not
   2-dimensional. */
   if( astGetFitsF( fc, "WAVELEN", &wavelen ) &&
       astGetFitsF( fc, "BANDWID", &bandwid ) && ndim == 2 ) {

/* Get the current WCS FrameSet from the supplied NDF, and get a pointer
   to its current Frame. */
      ndfGtwcs( indf, &wcs, status );
      cfrm = astGetFrame( wcs, AST__CURRENT );

/* Return without action if this is not a SkyFrame. */
      if( astIsASkyFrame( cfrm ) ) {

/* Construct a topocentric wavelength SpecFrame to describe the new spectral
   WCS axis. */
         specfrm = astSpecFrame( "System=wavelen,StdOfRest=topo,Unit=m" );

/* We set the RefRA and RefDec attributes for the SpecFrame to the FK5
   J2000 equivalent of the SkyRef attribute in the current Frame. */
         sprintf( attrib, "SkyRef(%d)", astGetI( cfrm, "LonAxis" ) );
         ref_lon = astGetD( cfrm, attrib );

         sprintf( attrib, "SkyRef(%d)", astGetI( cfrm, "LatAxis" ) );
         ref_lat = astGetD( cfrm, attrib );

         astSetRefPos( specfrm, cfrm, ref_lon, ref_lat );

/* Inherit other relevant Frame attributes from the SkyFrame. */
#define OVERLAY(attr) \
         if( astTest( cfrm, attr ) ) { \
            astSetC( specfrm, attr, astGetC( cfrm, attr ) ); \
         }

         OVERLAY( "Dut1" );
         OVERLAY( "Epoch" );
         OVERLAY( "ObsAlt" );
         OVERLAY( "ObsLat" );
         OVERLAY( "ObsLon" );

#undef OVERLAY

/* Create a WinMap that gives wavelength as a function of spectral GRID
   position. Assume the pixel centre maps onto WAVELEN and the pixel
   width is BANDWID. */
         grid_lo= 0.5;
         grid_hi = 1.5;
         spec_lo = wavelen - 0.5*bandwid;
         spec_hi = spec_lo + bandwid;
         specmap = astWinMap( 1, &grid_lo, &grid_hi, &spec_lo, &spec_hi, " " );

/* Modify the WCS FrameSet so that the base and current Frames are
   3-dimensional. The current Frame is expanded by adding in the
   SpecFrame, and the base Frame is expanded by adding in a 3rd GRID
   axis. Other Frames are left unchanged. The SpecFrame and the new GRID
   axis are connected using the WinMap created above. */
         atlAddWcsAxis( wcs, (AstMapping *) specmap, (AstFrame *) specfrm,
                        NULL, NULL, status );

/* Change the NDF bounds to include a 3rd axis with pixel bounds "1:1". */
         lbnd[ 2 ] = 1;
         ubnd[ 2 ] = 1;
         ndfSbnd( 3, lbnd, ubnd, indf, status );

/* Store the modified WCS FrameSet in the NDF. */
         ndfPtwcs( wcs, indf, status );
      }
   }

/* End the AST Object context. This will annull annull the AST Objects
   created in this function. */
   astEnd;
}
예제 #19
0
void smurf_jsatileinfo( int *status ) {

/* Local Variables */
   AstCmpRegion *overlap;
   AstFitsChan *fc;
   AstFrameSet *fs;
   AstObject *obj;
   AstRegion *region;
   AstRegion *target;
   HDSLoc *cloc = NULL;
   HDSLoc *xloc = NULL;
   char *jcmt_tiles;
   char *tilendf = NULL;
   char text[ 200 ];
   double dec[ 8 ];
   double dist;
   double dlbnd[ 2 ];
   double dubnd[ 2 ];
   double gx[ 8 ];
   double gy[ 8 ];
   double maxdist;
   double norm_radec[2];
   double point1[ 2 ];
   double point2[ 2 ];
   double ra[ 8 ];
   double ra0;
   double dec0;
   int *ipntr;
   int axes[ 2 ];
   int create;
   int dirlen;
   int el;
   int exists;
   int flag;
   int i;
   int indf1;
   int indf2;
   int indf3;
   int itile;
   int iv;
   int jtile;
   int lbnd[ 2 ];
   int local_origin;
   int nc;
   int place;
   int tlbnd[ 2 ];
   int tubnd[ 2 ];
   int ubnd[ 2 ];
   smf_jsaproj_t proj;
   int xt;
   int yt;
   smfJSATiling skytiling;
   void *pntr;

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Start a new AST context. */
   astBegin;

/* Get the instrument to use abnd get the parameters describing the
   layout of its JSA tiles. */
   smf_jsainstrument( "INSTRUMENT", NULL, SMF__INST_NONE, &skytiling,
                      status );

/* Return the maximum tile index. */
   parPut0i( "MAXTILE", skytiling.ntiles - 1, status );

/* Abort if an error has occurred. */
   if( *status != SAI__OK ) goto L999;

/* Decide what sort of projection to use. */
   parChoic( "PROJ", "HPX", "HPX,HPX12,XPHN,XPHS", 1, text, sizeof(text),
             status );
   proj = smf_jsaproj_fromstr( text, 1, status );

/* If required, create an all-sky NDF in which each pixel covers the area
   of a single tile, and holds the integer tile index. The NDF has an
   initial size of 1x1 pixels, but is expanded later to the required size. */
   lbnd[ 0 ] = ubnd[ 0 ] = lbnd[ 1 ] = ubnd[ 1 ] = 1;
   ndfCreat( "ALLSKY", "_INTEGER", 2, lbnd, ubnd, &indf3, status );

/* If a null (!) value was supplied for parameter ALLSKY, annull the
   error and pass on. */
   if( *status == PAR__NULL ) {
      errAnnul( status );

/* Otherwise, create a FrameSet describing the whole sky in which each
   pixel corresponds to a single tile. */
   } else {
      smf_jsatile( -1, &skytiling, 0, proj, NULL, &fs, NULL, lbnd, ubnd,
                   status );

/* Change the bounds of the output NDF. */
      ndfSbnd( 2, lbnd, ubnd, indf3, status );

/* Store the FrameSet in the NDF. */
      ndfPtwcs( fs, indf3, status );

/* Map the data array. */
      ndfMap( indf3, "Data", "_INTEGER", "WRITE/BAD", (void **) &ipntr, &el,
              status );

/* Create all-sky map using XPH projection. */
      if( *status == SAI__OK ) {

/* Loop round every tile index. */
         for( jtile = 0; jtile < skytiling.ntiles; jtile++ ) {

/* Get the zero-based (x,y) indices of the tile within an HPX projection.
   This flips the bottom left half-facet up to the top right. */
            smf_jsatilei2xy( jtile, &skytiling, &xt, &yt, NULL, status );

/* Convert these HPX indices to the corresponding indices within the
   required projection. Note, the lower left facet is split by the above
   call to smf_jsatilei2xy tile (i.e. (xt,yt) indices are *not* in the
   "raw" mode). For instance, (0,0) is not a valid tile. */
            smf_jsatilexyconv( &skytiling, proj, xt, yt, 0, &xt, &yt, status );

/* Get the vector index of the corresponding element of the all-sky NDF. */
            if( proj == SMF__JSA_HPX || proj == SMF__JSA_HPX12 ) {
               iv = xt + 5*skytiling.ntpf*yt;
            } else {
               iv = xt + 4*skytiling.ntpf*yt;
            }

/* Report an error if this element has already been assigned a tile
   index. Otherwise, store the tile index. */
            if( ipntr[ iv ] == VAL__BADI ) {
               ipntr[ iv ] = jtile;
            } else if( *status == SAI__OK ) {
               *status = SAI__ERROR;
               errRepf( "", "%s projection assigns multiple tiles to "
                        "pixel (%d,%d).", status, text, xt, yt );
               break;
            }
         }
      }

/* Store NDF title. */
      sprintf( text, "JSA tile indices for %s data", skytiling.name );
      ndfCput( text, indf3, "TITLE", status );

/* Store the instrument as a component in the SMURF extension. */
      ndfXnew( indf3, "SMURF", "INSTRUMENT", 0, 0, &xloc, status );
      ndfXpt0c( skytiling.name, indf3, "SMURF", "INSTRUMENT", status );
      datAnnul( &xloc, status );

/* Close the NDF. */
      ndfAnnul( &indf3, status );
   }

/* Abort if an error has occurred. */
   if( *status != SAI__OK ) goto L999;

/* Get the zero-based index of the required tile. If a null value is
   supplied, annull the error and skip to the end. */
   parGdr0i( "ITILE", 0, 0, skytiling.ntiles - 1, 0, &itile, status );
   if( *status == PAR__NULL ) {
       errAnnul( status );
       goto L999;
   }

/* See if the pixel origin is to be at the centre of the tile. */
   parGet0l( "LOCAL", &local_origin, status );

/* Display the tile number. */
   msgBlank( status );
   msgSeti( "ITILE", itile );
   msgSeti( "MAXTILE", skytiling.ntiles - 1);
   msgOut( " ", "   Tile ^ITILE (from 0 to ^MAXTILE):", status );

/* Get the FITS header, FrameSet and Region defining the tile, and the tile
   bounds in pixel indices. */
   smf_jsatile( itile, &skytiling, local_origin,  proj, &fc, &fs, &region,
                lbnd, ubnd, status );

/* Write the FITS headers out to a file, annulling the error if the
   header is not required. */
   if( *status == SAI__OK ) {
      atlDumpFits( "HEADER", fc, status );
      if( *status == PAR__NULL ) errAnnul( status );
   }

/* If required, write the Region out to a text file. */
   if( *status == SAI__OK ) {
      atlCreat( "REGION", (AstObject *) region, status );
      if( *status == PAR__NULL ) errAnnul( status );
   }

/* Store the lower and upper pixel bounds of the tile. */
   parPut1i( "LBND", 2, lbnd, status );
   parPut1i( "UBND", 2, ubnd, status );

/* Display pixel bounds on the screen. */
   msgSeti( "XL", lbnd[ 0 ] );
   msgSeti( "XU", ubnd[ 0 ] );
   msgSeti( "YL", lbnd[ 1 ] );
   msgSeti( "YU", ubnd[ 1 ] );
   msgOut( " ", "      Pixel bounds: (^XL:^XU,^YL:^YU)", status );

/* Get the RA,Dec at the tile centre. */
   if( astTest( fs, "SkyRef" ) ) {
      ra0 = astGetD( fs, "SkyRef(1)" );
      dec0 = astGetD( fs, "SkyRef(2)" );

/* Format the central RA and Dec. and display. Call astNorm on the
   coordinates provided that the frame set has the correct number of
   axes (which it should as it comes from smf_jsatile). */
      norm_radec[0] = ra0;
      norm_radec[1] = dec0;
      if (astGetI(fs, "Naxes") == 2) astNorm(fs, norm_radec);
      msgSetc( "RACEN",  astFormat( fs, 1, norm_radec[ 0 ] ));
      msgSetc( "DECCEN",  astFormat( fs, 2, norm_radec[ 1 ] ));
      msgOut( " ", "      Centre (ICRS): RA=^RACEN DEC=^DECCEN", status );

/* Transform a collection of points on the edge of the region (corners and
   side mid-points) from GRID coords to RA,Dec. */
      point1[ 0 ] = 0.5;
      point1[ 1 ] = 0.5;
      point2[ 0 ] = ubnd[ 0 ] - lbnd[ 0 ] + 1;
      point2[ 1 ] = ubnd[ 1 ] - lbnd[ 1 ] + 1;

      gx[ 0 ] = point1[ 0 ];         /* Bottom left */
      gy[ 0 ] = point1[ 1 ];

      gx[ 1 ] = point1[ 0 ];         /* Centre left */
      gy[ 1 ] = gy[ 0 ];

      gx[ 2 ] = point1[ 0 ];         /* Top left */
      gy[ 2 ] = point2[ 1 ];

      gx[ 3 ] = gx[ 0 ];             /* Top centre */
      gy[ 3 ] = point2[ 1 ];

      gx[ 4 ] = point2[ 0 ];         /* Top right */
      gy[ 4 ] = point2[ 1 ];

      gx[ 5 ] = point2[ 0 ];         /* Centre right */
      gy[ 5 ] = gy[ 0 ];

      gx[ 6 ] = point2[ 0 ];         /* Bottom right */
      gy[ 6 ] = point1[ 1 ];

      gx[ 7 ] = gx[ 0 ];             /* Bottom centre */
      gy[ 7 ] = point1[ 1 ];

      astTran2( fs, 8, gx, gy, 1, ra, dec );

/* Find the arc-distance from the centre to the furthest point from the
   centre. */
      point1[ 0 ] = ra0;
      point1[ 1 ] = dec0;
      maxdist = -1.0;

      for( i = 1; i < 8; i++ ) {
         if( ra[ i ] != AST__BAD && dec[ i ] != AST__BAD ) {
            point2[ 0 ] = ra[ i ];
            point2[ 1 ] = dec[ i ];
            dist = astDistance( fs, point1, point2 );
            if( dist > maxdist ) maxdist = dist;
         }
      }

/* Convert from radius to diameter. */
      maxdist *= 2.0;

/* Format this size as a dec value (i.e. arc-distance) and display it. */
      if( maxdist > 0.0 ) {
         msgSetc( "SIZE",  astFormat( fs, 2, maxdist ) );
         msgOut( " ", "      Size: ^SIZE", status );
      } else {
         maxdist = AST__BAD;
         msgOut( " ", "      Size: <unknown>", status );
      }

/* If a discontinuity passes through the tile, the centre and size may be
   unknown. */
   } else {
      ra0 = AST__BAD;
      dec0 = AST__BAD;
      maxdist = AST__BAD;
      msgOut( " ", "      Centre (ICRS): RA=<unknown> DEC=<unknown>", status );
      msgOut( " ", "      Size: <unknown>", status );
   }

/* Write the tile centre ra and dec in radians to the output parameters. */
   parPut0d( "RACEN", norm_radec[ 0 ], status );
   parPut0d( "DECCEN", norm_radec[ 1 ], status );

/* Write the size to the output parameter as radians. */
   parPut0d( "SIZE", maxdist, status );

/* Get the translation of the environment variable JSA_TILE_DIR. */
   jcmt_tiles = getenv( "JSA_TILE_DIR" );

/* Initialise the path to the tile's NDF to hold the root directory.
   Use the current working directory if JSA_TILE_DIR is undefined. */
   if( jcmt_tiles ) {
      nc = 0;
      tilendf = astAppendString( tilendf, &nc, jcmt_tiles );

   } else {

      nc = 512;
      jcmt_tiles = astMalloc( nc );

      while( !getcwd( jcmt_tiles, nc ) ) {
         nc *= 2;
         jcmt_tiles = astRealloc( jcmt_tiles, nc );
      }

      nc = 0;
      tilendf = astAppendString( tilendf, &nc, jcmt_tiles );
      jcmt_tiles = astFree( jcmt_tiles );
   }

/* Complete the path to the tile's NDF. */
   tilendf = astAppendString( tilendf, &nc, "/" );
   tilendf = astAppendString( tilendf, &nc, skytiling.subdir );
   dirlen = nc;
   sprintf( text, "/tile_%d.sdf", itile );
   tilendf = astAppendString( tilendf, &nc, text );

/* Write it to the output parameter. */
   parPut0c( "TILENDF", tilendf, status );

/* See if the NDF exists, and store the flag in the output parameter. */
   exists = access( tilendf, F_OK ) ? 0 : 1;
   parPut0l( "EXISTS", exists, status );

/* If the NDF does not exist, create it if required. */
   parGet0l( "CREATE", &create, status );
   if( !exists && create && *status == SAI__OK ) {

/* Write the NDF info to the screen. */
      msgSetc( "NDF",  tilendf );
      msgOutif( MSG__NORM, " ", "      NDF: ^NDF (created)", status );

/* Temporarily terminate the NDF path at the end of the subdirectory. */
      tilendf[ dirlen ] = 0;

/* Create the required directory (does nothing if the directory
   already exists).  It is given read/write/search permissions for owner
   and group, and read/search permissions for others. */
      (void) mkdir( tilendf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );

/* Replace the character temporarily overwritten above. */
      tilendf[ dirlen ] = '/';

/* Now create the tile's NDF. */
      ndfPlace( NULL, tilendf, &place, status );
      ndfNew( skytiling.type, 2, lbnd, ubnd, &place, &indf1, status );

/* Fill its data array with zeros. */
      ndfMap( indf1, "Data", skytiling.type, "WRITE/ZERO", &pntr, &el,
              status );

/* Store the WCS FrameSet. */
      ndfPtwcs( fs, indf1, status );

/* If the instrument jsatiles.have variance, fill the variance array with zeros. */
      if( skytiling.var ) {
         ndfMap( indf1, "Variance", skytiling.type, "WRITE/ZERO", &pntr,
                 &el, status );
      }

/* Create a SMURF extension. */
      ndfXnew( indf1, SMURF__EXTNAME, SMURF__EXTTYPE, 0, NULL, &xloc, status );

/* Store the tile number and instrument name in the extension. */
      datNew0I( xloc, "TILE", status );
      datFind( xloc, "TILE", &cloc, status );
      datPut0I( cloc, itile, status );
      datAnnul( &cloc, status );

      datNew0C( xloc, "INSTRUMENT", strlen( skytiling.name ), status );
      datFind( xloc, "INSTRUMENT", &cloc, status );
      datPut0C( cloc, skytiling.name, status );
      datAnnul( &cloc, status );

/* Create a weights NDF within the SMURF extension, and fill its data
   array with zeros. */
      ndfPlace( xloc, "WEIGHTS", &place, status );
      ndfNew( skytiling.type, 2, lbnd, ubnd, &place, &indf2, status );
      ndfMap( indf2, "Data", skytiling.type, "WRITE/ZERO", &pntr, &el,
              status );
      ndfPtwcs( fs, indf2, status );
      ndfAnnul( &indf2, status );

/* Annul the extension locator and the main NDF identifier. */
      datAnnul( &xloc, status );
      ndfAnnul( &indf1, status );

/* Write the NDF info to the screen. */
   } else {
      msgSetc( "NDF",  tilendf );
      msgSetc( "E",  exists ? "exists" : "does not exist" );
      msgOut( " ", "      NDF: ^NDF (^E)", status );
   }

/* Initialise TBND and TLBND to indicate no overlap. */
   tlbnd[ 0 ] = 1;
   tlbnd[ 1 ] = 1;
   tubnd[ 0 ] = 0;
   tubnd[ 1 ] = 0;

/* Attempt to to get an AST Region (assumed to be in some 2D sky coordinate
   system) using parameter "TARGET". */
   if( *status == SAI__OK ) {
      kpg1Gtobj( "TARGET", "Region",
                 (void (*)( void )) F77_EXTERNAL_NAME(ast_isaregion),
                 &obj, status );

/* Annul the error if none was obtained. */
      if( *status == PAR__NULL ) {
         errAnnul( status );

/* Otherwise, use the supplied object. */
      } else {
         target = (AstRegion *) obj;

/* If the target Region is 3-dimensional, remove the third axis, which
   is assumed to be a spectral axis. */
         if( astGetI( target, "Naxes" ) == 3 ) {
            axes[ 0 ] = 1;
            axes[ 1 ] = 2;
            target = astPickAxes( target, 2, axes, NULL );
         }

/* See if there is any overlap between the target and the tile. */
         overlap = NULL;
         flag = astOverlap( region, target );

         if( flag == 0 ) {
            msgOut( "", "      Cannot convert between the coordinate system of the "
                    "supplied target and the tile.", status );

         } else if( flag == 1 || flag == 6 ) {
            msgOut( "", "      There is no overlap between the target and the tile.",
                    status );

         } else if( flag == 2 ) {
            msgOut( "", "      The tile is contained within the target.",
                    status );
            tlbnd[ 0 ] = lbnd[ 0 ];
            tlbnd[ 1 ] = lbnd[ 1 ];
            tubnd[ 0 ] = ubnd[ 0 ];
            tubnd[ 1 ] = ubnd[ 1 ];

         } else if( flag == 3 ) {
            overlap = astCmpRegion( region, target, AST__AND, " " );

         } else if( flag == 4 ) {
            overlap = astCmpRegion( region, target, AST__AND, " " );

         } else if( flag == 5 ) {
            msgOut( "", "      The target and tile are identical.",
                    status );
            tlbnd[ 0 ] = lbnd[ 0 ];
            tlbnd[ 1 ] = lbnd[ 1 ];
            tubnd[ 0 ] = ubnd[ 0 ];
            tubnd[ 1 ] = ubnd[ 1 ];

         } else if( *status == SAI__OK ) {
            *status = SAI__OK;
            errRepf( "", "Unexpected value %d returned by astOverlap "
                     "(programming error).", status, flag );
         }

/* If a region containing the intersection of the tile and target was
   created above, map it into the grid coordinate system of the tile. */
         if( overlap ) {
            overlap = astMapRegion( overlap, astGetMapping( fs, AST__CURRENT,
                                                            AST__BASE ),
                                    astGetFrame( fs, AST__BASE ) );

/* Get its GRID bounds. */
            astGetRegionBounds( overlap, dlbnd, dubnd );

/* Convert to integer. */
            tlbnd[ 0 ] = ceil( dlbnd[ 0 ] - 0.5 );
            tlbnd[ 1 ] = ceil( dlbnd[ 1 ] - 0.5 );
            tubnd[ 0 ] = ceil( dubnd[ 0 ] - 0.5 );
            tubnd[ 1 ] = ceil( dubnd[ 1 ] - 0.5 );

/* Convert to PIXEL indices within the tile. */
            tlbnd[ 0 ] += lbnd[ 0 ] - 1;
            tlbnd[ 1 ] += lbnd[ 1 ] - 1;
            tubnd[ 0 ] += lbnd[ 0 ] - 1;
            tubnd[ 1 ] += lbnd[ 1 ] - 1;

            msgOutf( "", "      The target overlaps section (%d:%d,%d:%d).",
                     status, tlbnd[ 0 ], tubnd[ 0 ], tlbnd[ 1 ], tubnd[ 1 ] );
         }
      }
   }

/* Store the pixel index bounds of the tiles overlap with the target. */
   parPut1i( "TLBND", 2, tlbnd, status );
   parPut1i( "TUBND", 2, tubnd, status );

/* Arrive here if an error occurs. */
   L999:;

/* Free resources. */
   tilendf = astFree( tilendf );

/* End the AST context. */
   astEnd;

/* Issue a status indication.*/
   msgBlank( status );
   if( *status == SAI__OK ) {
      msgOutif( MSG__VERB, "", "JSATILEINFO succeeded.", status);
   } else {
      msgOutif( MSG__VERB, "", "JSATILEINFO failed.", status);
   }
}
예제 #20
0
void smf_rebinsparse( smfData *data, int first, int *ptime, AstFrame *ospecfrm,
                      AstMapping *ospecmap, AstSkyFrame *oskyframe,
                      Grp *detgrp, int lbnd_out[ 3 ], int ubnd_out[ 3 ],
                      int genvar, float *data_array, float *var_array,
                      int *ispec, float *texp_array, float *teff_array,
                      double *fcon, int *status ){

/* Local Variables */
   AstCmpMap *fmap = NULL;      /* Mapping from spectral grid to topo freq Hz */
   AstCmpMap *ssmap = NULL;     /* I/p GRID-> o/p PIXEL Mapping for spectral axis */
   AstFitsChan *fc = NULL;      /* Storage for FITS headers */
   AstFrame *specframe = NULL;  /* Spectral Frame in input FrameSet */
   AstFrame *specframe2 = NULL; /* Temporary copy of SpecFrame in input WCS */
   AstFrameSet *fs = NULL;      /* A general purpose FrameSet pointer */
   AstFrameSet *swcsin = NULL;  /* FrameSet describing spatial input WCS */
   AstMapping *fsmap = NULL;    /* Base->Current Mapping extracted from a FrameSet */
   AstMapping *specmap = NULL;  /* PIXEL -> Spec mapping in input FrameSet */
   char *fftwin = NULL;  /* Name of FFT windowing function */
   const char *name = NULL; /* Pointer to current detector name */
   const double *tsys=NULL; /* Pointer to Tsys value for first detector */
   dim_t timeslice_size; /* No of detector values in one time slice */
   double *spectab = NULL;/* Workspace for spectral output grid positions */
   double *xin = NULL;   /* Workspace for detector input grid positions */
   double *xout = NULL;  /* Workspace for detector output pixel positions */
   double *yin = NULL;   /* Workspace for detector input grid positions */
   double *yout = NULL;  /* Workspace for detector output pixel positions */
   double at;            /* Frequency at which to take the gradient */
   double dnew;          /* Channel width in Hz */
   double fcon2;         /* Variance factor for whole file */
   double k;             /* Back-end degradation factor */
   double tcon;          /* Variance factor for whole time slice */
   float *pdata = NULL;  /* Pointer to next data sample */
   float *qdata = NULL;  /* Pointer to next data sample */
   float rtsys;          /* Tsys value */
   float teff;           /* Effective integration time, times 4 */
   float texp;           /* Total time ( = ton + toff ) */
   float toff;           /* Off time */
   float ton;            /* On time */
   int *nexttime = NULL; /* Pointer to next time slice index to use */
   int dim[ 3 ];         /* Output array dimensions */
   int found;            /* Was current detector name found in detgrp? */
   int good;             /* Are there any good detector samples? */
   int ibasein;          /* Index of base Frame in input FrameSet */
   int ichan;            /* Index of current channel */
   int iv;               /* Offset to next element */
   int iz;               /* Output grid index on axis 3 */
   int nchan;            /* Number of input spectral channels */
   int pixax[ 3 ];       /* The output fed by each selected mapping input */
   int specax;           /* Index of spectral axis in input FrameSet */
   size_t irec;          /* Index of current input detector */
   size_t itime;         /* Index of current time slice */
   smfHead *hdr = NULL;  /* Pointer to data header for this time slice */

/* Check inherited status */
   if( *status != SAI__OK ) return;

/* Begin an AST context.*/
   astBegin;

/* Store a pointer to the input NDFs smfHead structure. */
   hdr = data->hdr;

/* Store the dimensions of the output array. */
   dim[ 0 ] = ubnd_out[ 0 ] - lbnd_out[ 0 ] + 1;
   dim[ 1 ] = ubnd_out[ 1 ] - lbnd_out[ 1 ] + 1;
   dim[ 2 ] = ubnd_out[ 2 ] - lbnd_out[ 2 ] + 1;

/* Store the number of pixels in one time slice */
   timeslice_size = (data->dims)[ 0 ]*(data->dims)[ 1 ];

/* We want a description of the spectral WCS axis in the input file. If
   the input file has a WCS FrameSet containing a SpecFrame, use it,
   otherwise we will obtain it from the FITS header later. NOTE, if we knew
   that all the input NDFs would have the same spectral axis calibration,
   then the spectral WCS need only be obtained from the first NDF. However,
   in the general case, I presume that data files may be combined that use
   different spectral axis calibrations, and so these differences need to
   be taken into account. */
   if( hdr->tswcs ) {
      fs = astClone( hdr->tswcs );

/* The first axis should be a SpecFrame. See if this is so. If not annul
   the specframe pointer. */
      specax = 1;
      specframe = astPickAxes( fs, 1, &specax, NULL );
      if( !astIsASpecFrame( specframe ) ) specframe = astAnnul( specframe );
   }

/* If the above did not yield a SpecFrame, use the FITS-WCS headers in the
   FITS extension of the input NDF. Take a copy of the FITS header (so that
   the contents of the header are not changed), and then read a FrameSet
   out of it. */
   if( !specframe ) {
      fc = astCopy( hdr->fitshdr );
      astClear( fc, "Card" );
      fs = astRead( fc );

/* Extract the SpecFrame that describes the spectral axis from the current
   Frame of this FrameSet. This is assumed to be the third WCS axis (NB
   the different axis number). */
      specax = 3;
      specframe = astPickAxes( fs, 1, &specax, NULL );
   }

/* Split off the 1D Mapping for this single axis from the 3D Mapping for
   the whole WCS. This results in "specmap" holding the Mapping from
   SpecFrame value to GRID value. */
   fsmap = astGetMapping( fs, AST__CURRENT, AST__BASE );
   astMapSplit( fsmap, 1, &specax, pixax, &specmap );

/* Invert the Mapping for the spectral axis so that it goes from input GRID
   coord to spectral coord. */
   astInvert( specmap );

/* Get a Mapping that converts values in the input spectral system to the
   corresponding values in the output spectral system. */
   fs = astConvert( specframe, ospecfrm, "" );

/* Concatenate these Mappings with the supplied spectral Mapping to get
   a Mapping from the input spectral grid axis (pixel axis 1) to the
   output spectral grid axis (pixel axis 3). Simplify the Mapping. */
   ssmap = astCmpMap( astCmpMap( specmap, astGetMapping( fs, AST__BASE,
                                                         AST__CURRENT ),
                                 1, " " ),
                      ospecmap, 1, " " );
   ssmap = astSimplify( ssmap );

/* Create a table with one element for each channel in the input array,
   holding the index of the nearest corresponding output channel. */
   nchan = (data->dims)[ 0 ];
   spectab = astMalloc( sizeof( *spectab )*nchan );
   if( spectab ) {
      for( ichan = 0; ichan < nchan; ichan++ ) spectab[ ichan ] = ichan + 1;
      astTran1( ssmap, nchan, spectab, 1, spectab );
      for( ichan = 0; ichan < nchan; ichan++ ) {
         if( spectab[ ichan ] != AST__BAD ) {
            iz = floor( spectab[ ichan ] + 0.5 );
            if( iz >= 1 && iz <= dim[ 2 ] ) {
               spectab[ ichan ] = iz;
            } else {
               spectab[ ichan ] = 0;
            }
         } else {
            spectab[ ichan ] = 0;
         }
      }
   }

/* Allocate work arrays big enough to hold the coords of all the
   detectors in the current input file.*/
   xin = astMalloc( (data->dims)[ 1 ] * sizeof( *xin ) );
   yin = astMalloc( (data->dims)[ 1 ] * sizeof( *yin ) );
   xout = astMalloc( (data->dims)[ 1 ] * sizeof( *xout ) );
   yout = astMalloc( (data->dims)[ 1 ] * sizeof( *yout ) );

/* Initialise a string to point to the name of the first detector for which
   data is available */
   name = hdr->detname;

/* Store input coords for the detectors. Axis 1 is the detector index, and
   axis 2 is a dummy axis that always has the value 1. */
   for( irec = 0; irec < (data->dims)[ 1 ]; irec++ ) {
      xin[ irec ] = irec + 1.0;
      yin[ irec ] = 1.0;

/* If a group of detectors to be used was supplied, search the group for
   the name of the current detector. If not found, set the GRID coords bad. */
      if( detgrp ) {
         found = grpIndex( name, detgrp, 1, status );
         if( !found ) {
            xin[ irec ] = AST__BAD;
            yin[ irec ] = AST__BAD;
         }
      }

/* Move on to the next available detector name. */
      name += strlen( name ) + 1;
   }

/* Find the constant factor associated with the current input file. This
   is the squared backend degradation factor, divided by the noise bandwidth.
   Get the required FITS headers, checking they were found. */
   if( astGetFitsF( hdr->fitshdr, "BEDEGFAC", &k ) &&
       astGetFitsS( hdr->fitshdr, "FFT_WIN", &fftwin ) ){

/* Get a Mapping that converts values in the input spectral system to
   topocentric frequency in Hz, and concatenate this Mapping with the
   Mapping from input GRID coord to the input spectral system. The result
   is a Mapping from input GRID coord to topocentric frequency in Hz. */
      specframe2 = astCopy( specframe );
      astSet( specframe2, "system=freq,stdofrest=topo,unit=Hz" );
      fmap = astCmpMap( specmap, astGetMapping( astConvert( specframe,
                                                            specframe2,
                                                            "" ),
                                                AST__BASE, AST__CURRENT ),
                        1, " " );

/* Differentiate this Mapping at the mid channel position to get the width
   of an input channel in Hz. */
      at = 0.5*nchan;
      dnew = astRate( fmap, &at, 1, 1 );

/* Modify the channel width to take account of the effect of the FFT windowing
   function. Allow undef value because FFT_WIN for old data had a broken value
   in hybrid subband modes. */
      if( dnew != AST__BAD ) {
         dnew = fabs( dnew );

         if( !strcmp( fftwin, "truncate" ) ) {
            dnew *= 1.0;

         } else if( !strcmp( fftwin, "hanning" ) ) {
            dnew *= 1.5;

	    } else if( !strcmp( fftwin, "<undefined>" ) ) {
	      /* Deal with broken data - make an assumption */
	       dnew *= 1.0;

         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            msgSetc( "W", fftwin );
            errRep( FUNC_NAME, "FITS header FFT_WIN has unknown value "
                    "'^W' (programming error).", status );
         }

/* Form the required constant. */
         fcon2 = k*k/dnew;

      } else {
         fcon2 = VAL__BADD;
      }

   } else {
      fcon2 = VAL__BADD;
   }

/* Return the factor needed for calculating Tsys from the variance. */
   if( first ) {
      *fcon = fcon2;
   } else if( fcon2 != *fcon ) {
      *fcon = VAL__BADD;
   }

/* Initialise a pointer to the next time slice index to be used. */
   nexttime = ptime;

/* Loop round all the time slices in the input file. */
   for( itime = 0; itime < (data->dims)[ 2 ] && *status == SAI__OK; itime++ ) {

/* If this time slice is not being pasted into the output cube, pass on. */
      if( nexttime ){
         if( *nexttime != itime ) continue;
         nexttime++;
      }

/* Store a pointer to the first input data value in this time slice. */
      pdata = ( (float *) (data->pntr)[ 0 ] ) + itime*timeslice_size;

/* Get a FrameSet describing the spatial coordinate systems associated with
   the current time slice of the current input data file. The base frame in
   the FrameSet will be a 2D Frame in which axis 1 is detector number and
   axis 2 is unused. The current Frame will be a SkyFrame (the SkyFrame
   System may be any of the JCMT supported systems). The Epoch will be
   set to the epoch of the time slice. */
      smf_tslice_ast( data, itime, 1, NO_FTS, status );
      swcsin = hdr->wcs;

/* Note the total exposure time (texp) for all the input spectra produced by
   this time slice. */
      ton = hdr->state->acs_exposure;
      if( ton == 0.0 ) ton = VAL__BADR;

      toff = hdr->state->acs_offexposure;
      if( toff == 0.0 ) toff = VAL__BADR;

      if( ton != VAL__BADR && toff != VAL__BADR ) {
         texp = ton + toff;
         teff = 4*ton*toff/( ton + toff );
      } else {
         texp = VAL__BADR;
         teff = VAL__BADR;
      }

/* If output variances are being calculated on the basis of Tsys values
   in the input, find the constant factor associated with the current
   time slice. */
      tcon = AST__BAD;
      if( genvar == 2 && fcon2 != AST__BAD && texp != VAL__BADR ) {
         tcon = fcon2*( 1.0/ton + 1.0/toff );

/* Get a pointer to the start of the Tsys values for this time slice. */
         tsys = hdr->tsys + hdr->ndet*itime;
      }

/* We now create a Mapping from detector index to position in oskyframe. */
      astInvert( swcsin );
      ibasein = astGetI( swcsin, "Base" );
      fs = astConvert( swcsin, oskyframe, "SKY" );
      astSetI( swcsin, "Base", ibasein );
      astInvert( swcsin );

      if( fs == NULL ) {
         if( *status == SAI__OK ) {
            if (data->file) {
               smf_smfFile_msg(data->file, "FILE", 1, "<unknown>");
            } else {
               msgSetc( "FILE", "<unknown>" );
            }
            *status = SAI__ERROR;
            errRep( FUNC_NAME, "The spatial coordinate system in ^FILE "
                    "is not compatible with the spatial coordinate "
                    "system in the first input file.", status );
         }
         break;
      }

/* Transform the positions of the detectors from input GRID to oskyframe
   coords. */
      astTran2( fs, (data->dims)[ 1 ], xin, yin, 1, xout, yout );

/* Loop round all detectors. */
      for( irec = 0; irec < (data->dims)[ 1 ]; irec++ ) {

/* If the detector has a valid position, see if it produced any good
   data values. */
         if( xout[ irec ] != AST__BAD && yout[ irec ] != AST__BAD ) {
            qdata = pdata;
            good = 0;
            for( ichan = 0; ichan < nchan; ichan++ ){
               if( *(qdata++) != VAL__BADR ) {
                  good = 1;
                  break;
               }
            }

/* If it did, calculate the variance associated with each detector
   sample (if required), based on the input Tsys values, and copy the
   spectrum to the output NDF. */
            if( good ) {
               if( *ispec < dim[ 0 ] ){
                  rtsys = tsys ? (float) tsys[ irec ] : VAL__BADR;
                  if( rtsys <= 0.0 ) rtsys = VAL__BADR;
                  if( tcon != AST__BAD && genvar == 2 && rtsys != VAL__BADR ) {
                     var_array[ *ispec ] = tcon*rtsys*rtsys;
                  } else if( var_array ) {
                     var_array[ *ispec ] = VAL__BADR;
                  }

                  if( texp != VAL__BADR ) {
                     texp_array[ *ispec ] = texp;
                     teff_array[ *ispec ] = teff;
                  }

                  for( ichan = 0; ichan < nchan; ichan++, pdata++ ) {
                     iz = spectab[ ichan ] - 1;
                     if( iz >= 0 && iz < dim[ 2 ] ) {
                        iv = *ispec + dim[ 0 ]*iz;
                        data_array[ iv ] = *pdata;
                     }
                  }

                  (*ispec)++;

               } else if( *status == SAI__OK ){
                  *status = SAI__ERROR;
                  msgSeti( "DIM", dim[ 0 ] );
                  errRep( " ", "Too many spectra (more than ^DIM) for "
                          "the output NDF (programming error).", status );
                  break;
               }

/* If this detector does not have any valid data values, increment the data
   pointer to point at the first sample for the next detector. */
            } else {
               pdata += nchan;
            }

/* If this detector does not have a valid position, increment the data
   pointer to point at the first sample for the next detector. */
         } else {
            pdata += nchan;
         }
      }

/* For efficiency, explicitly annul the AST Objects created in this tight
   loop. */
      fs = astAnnul( fs );
   }

/* Free resources */
   spectab = astFree( spectab );
   xin = astFree( xin );
   yin = astFree( yin );
   xout = astFree( xout );
   yout = astFree( yout );

/* End the AST context. This will annul all AST objects created within the
   context (except for those that have been exported from the context). */
   astEnd;
}
예제 #21
0
void atlGetPixelParams( AstFrameSet *fset, int *dims, int degs,
                        double *crpix, double *crval, double *cdelt,
                        double *crota, int *status ){
/*
*+
*  Name:
*     atlGetPixelParams

*  Purpose:
*     Find typical values for "FITS-like" parameters describing a FrameSet.

*  Invocation:
*     void atlGetPixelParams( AstFrameSet *fset, int *dims, int degs,
*                             double *crpix, double *crval, double *cdelt,
*                             double *crota, int *status )

*  Description:
*     This function finds values that resemble the the FITS keywords
*     CRVAL1/2/3.., CRPIX1/2/3..., CRDELT1/2/3... and CROTA2, on the
*     assumption that the base Frame in the supplied FrameSet describe
*     GRID coords (i.e. FITS pixel coords), and the current Frame describe
*     the required WCS.  It is not restricted to 2D FrameSets.
*
*     If the FrameSet can be written to a FitsChan successfully using
*     FITS-WCS encoding, the the resulting keyword values are returned.
*     Otherwise, the values are estimated by transforming closely spaced
*     pixel positions along each axis. If the current Frame contains a
*     SkyFrame, and the SkyFrame has a defined reference position, then
*     this position specifies the returned CRVAL values. Otherwise, the
*     reference position is assumed to be at the central pixel.

*  Arguments:
*     fset
*        The FrameSet.
*     dims
*        Pointer to an array supplied holding the number of pixels along
*        each edge of the pixel array. The number of elements in this array
*        should match the number of axes in the base Frame of "fset".
*     degs
*        If non-zero, then the crval, cdelt and crota values for sky axes
*        are returned in units of degrees. Otherwise they are returned in
*        radians.
*     crpix
*        Pointer to an array returned holding the position of the
*        reference pixel in the base Frame of "fset". The number of
*        elements in this array should match the number of axes in the base
*        Frame of "fset".
*     crval
*        Pointer to an array returned holding the position of the
*        reference pixel in the current Frame of "fset". The number of
*        elements in this array should match the number of axes in the
*        current Frame of "fset".
*     cdelt
*        Pointer to an array returned holding the geodesic distance
*        along each edge of the reference pixel, measured within the
*        current Frame of "fset". The number of elements in this array
*        should match the number of axes in the base Frame of "fset".
*     crota
*        Pointer to a double in which to return the angle from north in
*        the current frame of "fset" to the second spatial pixel axis,
*        measured positive through east. This will be returned set to
*        AST__BAD if the current frame of "fset" does not contain a SkyFrame.
*     status
*        The global status.

*  Copyright:
*     Copyright (C) 2013 Science & Technology Facilities Council.
*     All Rights Reserved.

*  Licence:
*     This program is free software; you can redistribute it and/or
*     modify it under the terms of the GNU General Public License as
*     published by the Free Software Foundation; either version 2 of
*     the License, or (at your option) any later version.
*
*     This program is distributed in the hope that it will be
*     useful,but WITHOUT ANY WARRANTY; without even the implied
*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
*     PURPOSE. See the GNU General Public License for more details.
*
*     You should have received a copy of the GNU General Public License
*     along with this program; if not, write to the Free Software
*     Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA
*     02110-1301, USA

*  Authors:
*     DSB: David S. Berry (JAC, Hawaii)
*     {enter_new_authors_here}

*  History:
*     13-DEC-2013 (DSB):
*        Original version.
*     {enter_further_changes_here}
*-
*/


/* Local Variables: */
   AstFitsChan *fc;
   AstMapping *map;
   int npix;
   int nwcs;
   int lataxis;
   int lonaxis;
   char name[20];
   const char *cval;
   int ipix;
   double dval1;
   double dval2;
   int ival;
   int iwcs;
   double pixpos[ ATL__MXDIM ];
   double wcspos[ ATL__MXDIM ];
   int pixaxes[ ATL__MXDIM ];
   int wcsaxes[ ATL__MXDIM ];
   int skyaxis1;
   int skyaxis2;

/* Initialise returned values. */
   *crota = AST__BAD;

/* Check the inherited status. */
   if( *status != SAI__OK ) return;

/* Begin an AST context so that all AST objects created in this function
   are freed automatically when the context is ended. */
   astBegin;

/* Get the number of pixel axes (base frame) and wcs axes (current
   frame). */
   npix = astGetI( fset, "Nin" );
   if( npix > ATL__MXDIM && *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRepf( "", "atlGetPixelParams: Too many pixel axes (%d). Must be "
               "no more than %d.", status, npix, ATL__MXDIM );
   }

   nwcs = astGetI( fset, "Nout" );
   if( nwcs > ATL__MXDIM && *status == SAI__OK ) {
      *status = SAI__ERROR;
      errRepf( "", "atlGetPixelParams: Too many WCS axes (%d). Must be "
               "no more than %d.", status, nwcs, ATL__MXDIM );
   }

/* Attempt to find a pair of sky axes in the current Frame by checking
   the "Domain" value for each WCS axis. */
   lataxis = -1;
   lonaxis = -1;
   skyaxis1 = -1;
   skyaxis2 = -1;

   for( iwcs = 0; iwcs < nwcs; iwcs++ ) {
      sprintf( name, "Domain(%d)", iwcs + 1 );
      cval = astGetC( fset, name );
      if( cval && !strcmp( cval, "SKY" ) ) {

/* Determine if this sky axis is a longitude or latitude axis, and record
   the zero-based indicies of the longitude and latitude axes. */
         sprintf( name, "IsLatAxis(%d)", iwcs + 1 );
         ival = astGetI( fset, name );
         if( ival ) {
            lataxis = iwcs;
         } else {
            lonaxis = iwcs;
         }
      }
   }

/* If a pair of sky axes were found in the current Frame, get the indices
   of the corresponding pair of pixel axes. */
   if( lonaxis >= 0 && lataxis >= 0 ) {

/* If there are only two pixel axes, they must be the sky axes. */
      if( nwcs == 2 ) {
         skyaxis1 = 0;
         skyaxis2 = 1;

/* If there are more than two pixel axes, we need to work harder. */
      } else {

/* Use astMapSplit to find the two pixel axes that feed the two sky axes.
   astMapSplit identifes outputs corresponding to specified mapping inputs,
   so we need to invert the FrameSet first so that the WCS Frame becomes
   the input (i.e. base Frame). Remember to un-invert the FrameSet
   afterwards. */
         astInvert( fset );
         wcsaxes[ 0 ] = lataxis + 1;
         wcsaxes[ 1 ] = lonaxis + 1;
         astMapSplit( fset, 2, wcsaxes, pixaxes, &map );
         astInvert( fset );

/* If the wcs->pixel mapping was split succesfully, the pixaxes array
   will contain the one-based pixel axes that feed the sky axes. Convert
   them to zero-based and note the lowest and highest. */
         if( map && astGetI( map, "Nout" ) == 2 ) {
            if( pixaxes[ 0 ] < pixaxes[ 1 ] ) {
               skyaxis1 = pixaxes[ 0 ] - 1;
               skyaxis2 = pixaxes[ 1 ] - 1;
            } else {
               skyaxis1 = pixaxes[ 1 ] - 1;
               skyaxis2 = pixaxes[ 0 ] - 1;
            }

/* If it could not be split, it means the spatial and non-spatial axes are
   tangle up by the pixel->wcs mapping to such an extent that they cannot
   be separated. */
         } else if( *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRepf( "", "atlGetPixelParams: Cannot separate the spatial "
                     "axes from the non-spatial axes.", status );
         }
      }
   }

/* Attempt to write the supplied FrameSet to FitsChan using FITS-WCS
   encoding. If successful, retrieve the required values. Convert sky
   values from degrees to radians if required. */
   fc = astFitsChan( NULL, NULL, "Encoding=FITS-WCS" );
   if( astWrite( fc, fset ) == 1 ) {

      for( ipix = 0; ipix < npix; ipix++ ) {
         sprintf( name, "CRPIX%d", ipix + 1 );
         if( !astGetFitsF( fc, name, crpix + ipix ) && *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRepf( "", "atlGetPixelParams: %s not found in FitsChan "
                     "(possible programming error).", status, name );
         }

         sprintf( name, "CDELT%d", ipix + 1 );
         if( !astGetFitsF( fc, name, cdelt + ipix ) && *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRepf( "", "atlGetPixelParams: %s not found in FitsChan "
                     "(possible programming error).", status, name );
         }

         if( !degs && ( ipix == skyaxis1 || ipix == skyaxis2 ) ){
            cdelt[ ipix ] *= AST__DD2R;
         }

      }

      for( iwcs = 0; iwcs < nwcs; iwcs++ ) {

         sprintf( name, "CRVAL%d", iwcs + 1 );
         if( !astGetFitsF( fc, name, crval + iwcs ) && *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRepf( "", "atlGetPixelParams: %s not found in FitsChan "
                     "(possible programming error).", status, name );
         }

         if( !degs && ( iwcs == lonaxis || iwcs == lataxis ) ){
            crval[ iwcs ] *= AST__DD2R;
         }

      }

/* Derive the position angle (within the sky frame) of the second spatial
   pixel axis, based on the PCi_j rotation matrix elements. Note, there is
   no assumption here that the latitude and longitude axes are orthogonal
   in the pixel frame. FITS-WCS allows for shear, so this value says
   nothing about the orientation of the first spatial pixel axis. But in
   practice images nearly always have no shear. */
      if( lataxis >= 0 && lonaxis >= 0 ) {
         sprintf( name, "PC%d_%d", lonaxis + 1, skyaxis1 + 1 );
         if( !astGetFitsF( fc, name, &dval1 ) && *status == SAI__OK ) {
            dval1 = ( lonaxis == skyaxis1 ) ? 1.0 : 0.0;
         }

         sprintf( name, "PC%d_%d", lonaxis + 1, skyaxis2 + 1 );
         if( !astGetFitsF( fc, name, &dval2 ) && *status == SAI__OK ) {
            dval2 = ( lonaxis == skyaxis2 ) ? 1.0 : 0.0;
         }

         *crota = atan2( dval2, dval1 );
         if( *crota < 0.0 ) *crota += 2*AST__DPI;
         if( degs ) *crota *= AST__DR2D;
      }

/* If the supplied FrameSet could not be converted to a set of
   FITS-WCS keywords, we derive similar values by looking at small
   increments of pixel position. */
   } else {

/* First job is to decide on the reference position. By default we use
   the central pixel. Store the corresponding pixel coords. */
      for( ipix = 0; ipix < npix; ipix++ ) {
         crpix[ ipix ] = ( 1.0 + dims[ ipix ] )/2.0;
      }

/* Convert this pixel position to the WCS Frame. */
      astTranN( fset, 1, npix, 1, crpix, 1, nwcs, 1, crval );

/* If the current Frame contains a pair of sky axes, then the associated
   SkyFrame may include a reference position. If so, we will use it
   instead of the central pixel. First test to see if the SkyFrame has a
   reference position. If so get the reference longitude and latitude in
   radians, and convert the new reference position back to pixel coords. */
      if( lonaxis >= 0 && lataxis >= 0 ) {
         sprintf( name, "SkyRef(%d)", lonaxis + 1 );
         if( astTest( fset, name ) ) {
            crval[ lonaxis ] = astGetD( fset, name );
            sprintf( name, "SkyRef(%d)", lataxis + 1 );
            crval[ lataxis ] = astGetD( fset, name );

            astTranN( fset, 1, nwcs, 1, crval, 0, npix, 1, crpix );

/* If we have sky axes but the skyframe has no reference position, we
   need to check that the central pixel is a good default. For instance,
   it may be off the edge of an all-sky map, in which case it is no good
   as a reference position. */
         } else if( ( crval[ lonaxis ] == AST__BAD ||
                      crval[ lataxis ] == AST__BAD ) && *status == SAI__OK ) {
            *status = SAI__ERROR;
            errRepf( "", "atlGetPixelParams: No reference position can be "
                     "determined.", status );
         }
      }

/* Normalize the reference position. */
      astNorm( fset, crval );

/* Now we find the pixel size on each pixel axis. First take a copy of
   the pixel reference position. */
      memcpy( pixpos, crpix, npix*sizeof( *pixpos ) );
      for( ipix = 0; ipix < npix; ipix++ ) {

/* Store a pixel position which is offset away from the reference position
   by one pixel along the current pixel axis, and then transform it into
   the WCS Frame. */
         pixpos[ ipix ] += 1.0;
         astTranN( fset, 1, npix, 1, pixpos, 1, nwcs, 1, wcspos );
         pixpos[ ipix ] -= 1.0;

/* Find the geodesic distance between this WCS position and the reference
   position. */
         cdelt[ ipix ] = astDistance( fset, crval, wcspos );
      }

/* Find the crota value if we have a pair of sky axes. */
      if( lonaxis >= 0 && lataxis >= 0 ){

/* Get a WCS position about one arc-second north of the reference position. */
         memcpy( wcspos, crval, nwcs*sizeof( *wcspos ) );
         wcspos[ lataxis ] += 5.0E-6;

/* Transform to pixel coordinates. */
         astTranN( fset, 1, nwcs, 1, wcspos, 0, npix, 1, pixpos );

/* Get the required angle. */
         *crota = atan2( pixpos[ skyaxis1 ] - crpix[ skyaxis1 ],
                         pixpos[ skyaxis1 ] - crpix[ skyaxis2 ] );
         if( *crota < 0.0 ) *crota += 2*AST__DPI;
         if( !degs ) *crota *= AST__DR2D;
      }

/* Convert the returned angles to degrees if required. */
      if( !degs && ( lonaxis >= 0 && lataxis >= 0 ) ){
         crval[ lataxis ] *= AST__DR2D;
         crval[ lonaxis ] *= AST__DR2D;
         cdelt[ skyaxis1 ] *= AST__DR2D;
         cdelt[ skyaxis2 ] *= AST__DR2D;
      }
   }

/* End the AST context. This will annull all AST objects created in this
   function. */
   astEnd;

}