package Astro::Catalog::IO::SExtractor;
=head1 NAME
Astro::Catalog::IO::SExtractor - SExtractor output catalogue I/O for
Astro::Catalog.
=head1 SYNOPSIS
$cat = Astro::Catalog::IO::SExtractor->_read_catalog( \@lines );
=head1 DESCRIPTION
This class provides read and write methods for catalogues written by
SExtractor, as long as they were written in ASCII_HEAD format. The
methods are not public and should, in general, only be called from the
C<Astro::Catalog> C<read_catalog> and C<write_catalog> methods.
=cut
use 5.006;
use warnings;
use warnings::register;
use Carp;
use strict;
# Bring in the Astro:: modules.
use Astro::Catalog;
use Astro::Catalog::Item;
use Astro::Catalog::Item::Morphology;
use Astro::Coords;
use Number::Uncertainty;
use Astro::Flux;
use Astro::FluxColor;
use Astro::Fluxes;
use base qw/ Astro::Catalog::IO::ASCII /;
use vars qw/ $VERSION $DEBUG /;
$VERSION = '4.31';
$DEBUG = 0;
=begin __PRIVATE_METHODS__
=head1 PRIVATE METHODS
These methods are usually called automatically from the C<Astro::Catalog>
constructor.
=over 4
=item B<_read_catalog>
Parses the catalogue lines and returns a new C<Astro::Catalog> object
containing the catalogue entries.
$cat = Astro::Catalog::IO::SExtractor->_read_catalog( \@lines );
The catalogue lines must include column definitions as written using
the 'ASCII_HEAD' catalogue type from SExtractor. This implementation
currently only supports reading information from the following output
parameters:
NUMBER id
X_IMAGE
Y_IMAGE
X_PIXEL
Y_PIXEL
ERRX2_IMAGE
ERRY2_IMAGE
XWIN_IMAGE
YWIN_IMAGE
ERRX2WIN_IMAGE
ERRY2WIN_IMAGE
ALPHA_J2000 coords
DELTA_J2000 coords
MAG_ISO
MAGERR_ISO
FLUX_ISO
FLUXERR_ISO
MAG_ISOCOR
MAGERR_ISOCOR
FLUX_ISOCOR
FLUXERR_ISOCOR
MAG_APER
MAGERR_APER
FLUX_APER
FLUXERR_APER
MAG_AUTO
MAGERR_AUTO
FLUX_AUTO
FLUXERR_AUTO
MAG_BEST
MAGERR_BEST
FLUX_BEST
FLUXERR_BEST
ELLIPTICITY morphology ellipticity
THETA_IMAGE morphology position_angle_pixel
ERRTHETA_IMAGE morphology position_angle_pixel
THETA_SKY morphology position_angle_world
ERRTHETA_SKY morphology position_angle_world
B_IMAGE morphology minor_axis_pixel
ERRB_IMAGE morphology minor_axis_pixel
A_IMAGE morphology major_axis_pixel
ERRA_IMAGE morphology major_axis_pixel
B_WORLD morphology minor_axis_world
ERRB_WORLD morphology minor_axis_world
A_WORLD morphology major_axis_world
ERRA_WORLD morphology major_axis_world
ISOAREA_IMAGE morphology area
FWHM_IMAGE morphology fwhm_pixel
FWHM_WORLD morphology fwhm_world
FLAGS quality
The pixel coordinate values are special cases. As there are only two
available methods to hold this information in an
C<Astro::Catalog::Item> object, x() and y(), and six potential values
to use, we must make a choice as to which value gets the nod. We
preferentially use the NDF pixel coordinates (which are only available
in output from the Starlink version of EXTRACTOR), then the windowed
coordinates that were made available in SExtractor v2.4.3, then the
standard coordinates.
For the flux and magnitude values, a separate C<Astro::Flux> object is
set up for each type with the flux type() equal to the SExtractor
keyword. For example, if the MAG_AUTO keyword exists in the catalogue,
then the output C<Astro::Catalog::Item> objects will have an
C<Astro::Flux> object of the type 'MAG_AUTO' in it.
There are optional named parameters. These are case-sensitive, and are:
=item Filter - An Astro::WaveBand object denoting the waveband that
the catalogue values were measured in.
=item Quality - If set, then only objects that have an extraction flag
in the FLAGS column equal to this value will be used to generate the
output catalogue. Otherwise, all objects will be used.
=cut
sub _read_catalog {
my $class = shift;
my $lines = shift;
my %args = @_;
if( ref( $lines ) ne 'ARRAY' ) {
croak "Must supply catalogue contents as a reference to an array";
}
if( defined( $args{'Filter'} ) &&
! UNIVERSAL::isa( $args{'Filter'}, "Astro::WaveBand" ) ) {
croak "Filter as passed to SExtractor->_read_catalog must be an Astro::WaveBand object";
}
my $filter;
if( defined( $args{'Filter'} ) ) {
$filter = $args{'Filter'}->natural;
} else {
$filter = 'unknown';
}
my $quality = $args{'Quality'};
if( ! defined( $quality ) ) {
$quality = -1;
}
my @lines = @$lines; # Dereference, make own copy.
# Create an Astro::Catalog object;
my $catalog = new Astro::Catalog();
# Set up columns.
my $id_column = -1;
my $x_column = -1;
my $x_pixel_column = -1;
my $xerr_column = -1;
my $xwin_column = -1;
my $xwinerr_column = -1;
my $y_column = -1;
my $y_pixel_column = -1;
my $yerr_column = -1;
my $ywin_column = -1;
my $ywinerr_column = -1;
my $ra_column = -1;
my $dec_column = -1;
my $mag_iso_column = -1;
my $magerr_iso_column = -1;
my $flux_iso_column = -1;
my $fluxerr_iso_column = -1;
my $flux_isocor_column = -1;
my $fluxerr_isocor_column = -1;
my $mag_isocor_column = -1;
my $magerr_isocor_column = -1;
my $flux_aper1_column = -1;
my $fluxerr_aper1_column = -1;
my $mag_aper1_column = -1;
my $magerr_aper1_column = -1;
my $flux_aper2_column = -1;
my $fluxerr_aper2_column = -1;
my $mag_aper2_column = -1;
my $magerr_aper2_column = -1;
my $flux_auto_column = -1;
my $fluxerr_auto_column = -1;
my $mag_auto_column = -1;
my $magerr_auto_column = -1;
my $flux_best_column = -1;
my $fluxerr_best_column = -1;
my $mag_best_column = -1;
my $magerr_best_column = -1;
my $ell_column = -1;
my $posang_pixel_column = -1;
my $posangerr_pixel_column = -1;
my $posang_world_column = -1;
my $posangerr_world_column = -1;
my $minor_pixel_column = -1;
my $minorerr_pixel_column = -1;
my $major_pixel_column = -1;
my $majorerr_pixel_column = -1;
my $minor_world_column = -1;
my $minorerr_world_column = -1;
my $major_world_column = -1;
my $majorerr_world_column = -1;
my $area_column = -1;
my $fwhm_pixel_column = -1;
my $fwhm_world_column = -1;
my $flag_column = -1;
# Loop through the lines.
for ( @lines ) {
my $line = $_;
# If we're on a column line that starts with a #, check to see
# if it's describing where the X, Y, RA, or Dec position is in
# the table, or the object number, or the flux, or the error in
# flux.
if( $line =~ /^#/ ) {
my @column = split( /\s+/, $line );
if( $column[2] =~ /^NUMBER/ ) {
$id_column = $column[1] - 1;
print "ID column is $id_column\n" if $DEBUG;
} elsif( $column[2] =~ /^X_IMAGE/ ) {
$x_column = $column[1] - 1;
print "X_IMAGE column is $x_column\n" if $DEBUG;
} elsif( $column[2] =~ /^Y_IMAGE/ ) {
$y_column = $column[1] - 1;
print "Y_IMAGE column is $y_column\n" if $DEBUG;
} elsif( $column[2] =~ /^X_PIXEL/ ) {
$x_pixel_column = $column[1] - 1;
print "X_PIXEL column is $x_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^Y_PIXEL/ ) {
$y_pixel_column = $column[1] - 1;
print "Y_PIXEL column is $y_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRX2_IMAGE/ ) {
$xerr_column = $column[1] - 1;
print "X ERROR column is $xerr_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRY2_IMAGE/ ) {
$yerr_column = $column[1] - 1;
print "Y ERROR column is $yerr_column\n" if $DEBUG;
} elsif( $column[2] =~ /^XWIN_IMAGE/ ) {
$xwin_column = $column[1] - 1;
print "XWIN_IMAGE column is $xwin_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRX2WIN_IMAGE/ ) {
$xwinerr_column = $column[1] - 1;
print "ERRX2WIN_IMAGE column is $xwinerr_column\n" if $DEBUG;
} elsif( $column[2] =~ /^YWIN_IMAGE/ ) {
$ywin_column = $column[1] - 1;
print "YWIN_IMAGE column is $ywin_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRY2WIN_IMAGE/ ) {
$ywinerr_column = $column[1] - 1;
print "ERRY2WIN_IMAGE column is $ywinerr_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ALPHA_J2000/ ) {
$ra_column = $column[1] - 1;
print "RA column is $ra_column\n" if $DEBUG;
} elsif( $column[2] =~ /^DELTA_J2000/ ) {
$dec_column = $column[1] - 1;
print "DEC column is $dec_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAG_ISO$/ ) {
$mag_iso_column = $column[1] - 1;
print "MAG_ISO column is $mag_iso_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAGERR_ISO$/ ) {
$magerr_iso_column = $column[1] - 1;
print "MAGERR_ISO column is $magerr_iso_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUX_ISO$/ ) {
$flux_iso_column = $column[1] - 1;
print "FLUX_ISO column is $flux_iso_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUXERR_ISO$/ ) {
$fluxerr_iso_column = $column[1] - 1;
print "FLUXERR_ISO column is $fluxerr_iso_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUX_ISOCOR/ ) {
$flux_isocor_column = $column[1] - 1;
print "FLUX_ISOCOR column is $flux_isocor_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUXERR_ISOCOR/ ) {
$fluxerr_isocor_column = $column[1] - 1;
print "FLUXERR_ISOCOR column is $fluxerr_isocor_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAG_ISOCOR/ ) {
$mag_isocor_column = $column[1] - 1;
print "MAG_ISOCOR column is $mag_isocor_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAGERR_ISOCOR/ ) {
$magerr_isocor_column = $column[1] - 1;
print "MAGERR_ISOCOR column is $magerr_isocor_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUX_APER/ ) {
$flux_aper1_column = $column[1] - 1;
print "FLUX_APER column is $flux_aper1_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUXERR_APER/ ) {
$fluxerr_aper1_column = $column[1] - 1;
print "FLUXERR_APER column is $fluxerr_aper1_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAG_APER/ ) {
$mag_aper1_column = $column[1] - 1;
print "MAG_APER column is $mag_aper1_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAGERR_APER/ ) {
$magerr_aper1_column = $column[1] - 1;
print "MAGERR_APER column is $magerr_aper1_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUX_AUTO/ ) {
$flux_auto_column = $column[1] - 1;
print "FLUX_AUTO column is $flux_auto_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUXERR_AUTO/ ) {
$fluxerr_auto_column = $column[1] - 1;
print "FLUXERR_AUTO column is $fluxerr_auto_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAG_AUTO/ ) {
$mag_auto_column = $column[1] - 1;
print "MAG_AUTO column is $mag_auto_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAGERR_AUTO/ ) {
$magerr_auto_column = $column[1] - 1;
print "MAGERR_AUTO column is $magerr_auto_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUX_BEST/ ) {
$flux_best_column = $column[1] - 1;
print "FLUX_BEST column is $flux_best_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLUXERR_BEST/ ) {
$fluxerr_best_column = $column[1] - 1;
print "FLUXERR_BEST column is $fluxerr_best_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAG_BEST/ ) {
$mag_best_column = $column[1] - 1;
print "MAG_BEST column is $mag_best_column\n" if $DEBUG;
} elsif( $column[2] =~ /^MAGERR_BEST/ ) {
$magerr_best_column = $column[1] - 1;
print "MAGERR_BEST_COLUMN is $magerr_best_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ELLIPTICITY/ ) {
$ell_column = $column[1] - 1;
print "ELLIPTICITY column is $ell_column\n" if $DEBUG;
} elsif( $column[2] =~ /^THETA_IMAGE/ ) {
$posang_pixel_column = $column[1] - 1;
print "THETA_IMAGE column is $posang_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRTHETA_IMAGE/ ) {
$posangerr_pixel_column = $column[1] - 1;
print "ERRTHETA_IMAGE column is $posangerr_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^THETA_SKY/ ) {
$posang_world_column = $column[1] - 1;
print "THETA_SKY column is $posang_world_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRTHETA_SKY/ ) {
$posangerr_world_column = $column[1] - 1;
print "ERRTHETA_SKY column is $posangerr_world_column\n" if $DEBUG;
} elsif( $column[2] =~ /^B_IMAGE/ ) {
$minor_pixel_column = $column[1] - 1;
print "B_IMAGE column is $minor_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRB_IMAGE/ ) {
$minorerr_pixel_column = $column[1] - 1;
print "ERRB_IMAGE column is $minorerr_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^A_IMAGE/ ) {
$major_pixel_column = $column[1] - 1;
print "A_IMAGE column is $major_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRA_IMAGE/ ) {
$majorerr_pixel_column = $column[1] - 1;
print "ERRA_IMAGE column is $majorerr_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^B_WORLD/ ) {
$minor_world_column = $column[1] - 1;
print "B_WORLD column is $minor_world_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRB_WORLD/ ) {
$minorerr_world_column = $column[1] - 1;
print "ERRB_WORLD column is $minorerr_world_column\n" if $DEBUG;
} elsif( $column[2] =~ /^A_WORLD/ ) {
$major_world_column = $column[1] - 1;
print "A_WORLD column is $major_world_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ERRA_WORLD/ ) {
$majorerr_world_column = $column[1] - 1;
print "ERRA_WORLD column is $majorerr_world_column\n" if $DEBUG;
} elsif( $column[2] =~ /^ISOAREA_IMAGE/ ) {
$area_column = $column[1] - 1;
print "AREA column is $area_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FWHM_IMAGE/ ) {
$fwhm_pixel_column = $column[1] - 1;
print "FWHM_IMAGE column is $fwhm_pixel_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FWHM_WORLD/ ) {
$fwhm_world_column = $column[1] - 1;
print "FWHM_WORLD column is $fwhm_world_column\n" if $DEBUG;
} elsif( $column[2] =~ /^FLAGS/ ) {
$flag_column = $column[1] - 1;
print "FLAGS column is $flag_column\n" if $DEBUG;
}
next;
}
# Remove leading whitespace and go to the next line if the
# current one is blank.
$line =~ s/^\s+//;
next if length( $line ) == 0;
# Form an array of the fields in the catalogue.
my @fields = split( /\s+/, $line );
# Don't deal with this object if our requested quality is not -1
# and the quality of the object is not equal to the requested
# quality and we have a quality flag for this object.
if( ( $quality != -1 ) &&
( $flag_column != -1 ) &&
( $fields[$flag_column] != $quality ) ) {
next;
}
# Create a temporary Astro::Catalog::Item object.
my $star = new Astro::Catalog::Item();
# Grab the coordinates, forming an Astro::Coords object., but only
# if the RA and Dec columns are defined.
if( $ra_column != -1 &&
$dec_column != -1 ) {
my $coords = new Astro::Coords( type => 'J2000',
ra => $fields[$ra_column],
dec => $fields[$dec_column],
name => ( $id_column != -1 ? $fields[$id_column] : undef ),
units => 'degrees',
);
$star->coords( $coords );
}
if( $flag_column != -1 ) {
$star->quality( $fields[$flag_column] );
} else {
$star->quality( 0 );
}
if( $id_column != -1 ) {
$star->id( $fields[$id_column] );
}
# Set up the various flux and magnitude measurements.
if( $mag_iso_column != -1 ) {
my $num;
if( $magerr_iso_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$mag_iso_column],
Error => $fields[$magerr_iso_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$mag_iso_column] );
}
my $mag_iso = new Astro::Flux( $num, 'MAG_ISO', $filter );
$star->fluxes( new Astro::Fluxes( $mag_iso ) );
}
if( $flux_iso_column != -1 ) {
my $num;
if( $fluxerr_iso_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$flux_iso_column],
Error => $fields[$fluxerr_iso_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$flux_iso_column] );
}
my $flux_iso = new Astro::Flux( $num, 'FLUX_ISO', $filter );
$star->fluxes( new Astro::Fluxes( $flux_iso ) );
}
if( $mag_isocor_column != -1 ) {
my $num;
if( $magerr_isocor_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$mag_isocor_column],
Error => $fields[$magerr_isocor_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$mag_isocor_column] );
}
my $mag_isocor = new Astro::Flux( $num, 'MAG_ISOCOR', $filter );
$star->fluxes( new Astro::Fluxes( $mag_isocor ) );
}
if( $flux_isocor_column != -1 ) {
my $num;
if( $fluxerr_isocor_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$flux_isocor_column],
Error => $fields[$fluxerr_isocor_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$flux_isocor_column] );
}
my $flux_isocor = new Astro::Flux( $num, 'FLUX_ISOCOR', $filter );
$star->fluxes( new Astro::Fluxes( $flux_isocor ) );
}
if( $mag_aper1_column != -1 ) {
my $num;
if( $magerr_aper1_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$mag_aper1_column],
Error => $fields[$magerr_aper1_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$mag_aper1_column] );
}
my $mag_aper1 = new Astro::Flux( $num, 'MAG_APER1', $filter );
$star->fluxes( new Astro::Fluxes( $mag_aper1 ) );
}
if( $flux_aper1_column != -1 ) {
my $num;
if( $fluxerr_aper1_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$flux_aper1_column],
Error => $fields[$fluxerr_aper1_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$flux_aper1_column] );
}
my $flux_aper1 = new Astro::Flux( $num, 'FLUX_APER1', $filter );
$star->fluxes( new Astro::Fluxes( $flux_aper1 ) );
}
if( $mag_auto_column != -1 ) {
my $num;
if( $magerr_auto_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$mag_auto_column],
Error => $fields[$magerr_auto_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$mag_auto_column] );
}
my $mag_auto = new Astro::Flux( $num, 'MAG_AUTO', $filter );
$star->fluxes( new Astro::Fluxes( $mag_auto ) );
}
if( $flux_auto_column != -1 ) {
my $num;
if( $fluxerr_auto_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$flux_auto_column],
Error => $fields[$fluxerr_auto_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$flux_auto_column] );
}
my $flux_auto = new Astro::Flux( $num, 'FLUX_AUTO', $filter );
$star->fluxes( new Astro::Fluxes( $flux_auto ) );
}
if( $mag_best_column != -1 ) {
my $num;
if( $magerr_best_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$mag_best_column],
Error => $fields[$magerr_best_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$mag_best_column] );
}
my $mag_best = new Astro::Flux( $num, 'MAG_BEST', $filter );
$star->fluxes( new Astro::Fluxes( $mag_best ) );
}
if( $flux_best_column != -1 ) {
my $num;
if( $fluxerr_best_column != -1 ) {
$num = new Number::Uncertainty( Value => $fields[$flux_best_column],
Error => $fields[$fluxerr_best_column] );
} else {
$num = new Number::Uncertainty( Value => $fields[$flux_best_column] );
}
my $flux_best = new Astro::Flux( $num, 'FLUX_BEST', $filter );
$star->fluxes( new Astro::Fluxes( $flux_best ) );
}
# Set the x and y coordinates. Preferentially use the NDF pixel
# coordinates, then the windowed coordinates, then the standard
# coordinates.
if( $x_pixel_column != -1 ) {
$star->x( $fields[$x_pixel_column] );
} elsif( $xwin_column != -1 ) {
$star->x( $fields[$xwin_column] );
} elsif( $x_column != -1 ) {
$star->x( $fields[$x_column] );
}
if( $y_pixel_column != -1 ) {
$star->y( $fields[$y_pixel_column] );
} elsif( $ywin_column != -1 ) {
$star->y( $fields[$ywin_column] );
} elsif( $x_column != -1 ) {
$star->y( $fields[$y_column] );
}
# Set up the star's morphology.
my $ellipticity;
my $position_angle_pixel;
my $position_angle_world;
my $major_axis_pixel;
my $minor_axis_pixel;
my $major_axis_world;
my $minor_axis_world;
my $fwhm_pixel;
my $fwhm_world;
my $area;
if( $ell_column != -1 ) {
$ellipticity = new Number::Uncertainty( Value => $fields[$ell_column] );
}
if( $posang_pixel_column != -1 ) {
if( $posangerr_pixel_column != -1 ) {
$position_angle_pixel = new Number::Uncertainty( Value => $fields[$posang_pixel_column],
Error => $fields[$posangerr_pixel_column] );
} else {
$position_angle_pixel = new Number::Uncertainty( Value => $fields[$posang_pixel_column] );
}
}
if( $posang_world_column != -1 ) {
if( $posangerr_world_column != -1 ) {
$position_angle_world = new Number::Uncertainty( Value => $fields[$posang_world_column],
Error => $fields[$posangerr_world_column] );
} else {
$position_angle_world = new Number::Uncertainty( Value => $fields[$posang_world_column] );
}
}
if( $major_pixel_column != -1 ) {
if( $majorerr_pixel_column != -1 ) {
$major_axis_pixel = new Number::Uncertainty( Value => $fields[$major_pixel_column],
Error => $fields[$majorerr_pixel_column] );
} else {
$major_axis_pixel = new Number::Uncertainty( Value => $fields[$major_pixel_column] );
}
}
if( $major_world_column != -1 ) {
if( $majorerr_world_column != -1 ) {
$major_axis_world = new Number::Uncertainty( Value => $fields[$major_world_column],
Error => $fields[$majorerr_world_column] );
} else {
$major_axis_world = new Number::Uncertainty( Value => $fields[$major_world_column] );
}
}
if( $minor_pixel_column != -1 ) {
if( $minorerr_pixel_column != -1 ) {
$minor_axis_pixel = new Number::Uncertainty( Value => $fields[$minor_pixel_column],
Error => $fields[$minorerr_pixel_column] );
} else {
$minor_axis_pixel = new Number::Uncertainty( Value => $fields[$minor_pixel_column] );
}
}
if( $minor_world_column != -1 ) {
if( $minorerr_world_column != -1 ) {
$minor_axis_world = new Number::Uncertainty( Value => $fields[$minor_world_column],
Error => $fields[$minorerr_world_column] );
} else {
$minor_axis_world = new Number::Uncertainty( Value => $fields[$minor_world_column] );
}
}
if( $area_column != -1 ) {
$area = new Number::Uncertainty( Value => $fields[$area_column] );
}
if( $fwhm_pixel_column != -1 ) {
$fwhm_pixel = new Number::Uncertainty( Value => $fields[$fwhm_pixel_column] );
}
if( $fwhm_world_column != -1 ) {
$fwhm_world = new Number::Uncertainty( Value => $fields[$fwhm_world_column] );
}
my $morphology = new Astro::Catalog::Item::Morphology( ellipticity => $ellipticity,
position_angle_pixel => $position_angle_pixel,
position_angle_world => $position_angle_world,
major_axis_pixel => $major_axis_pixel,
minor_axis_pixel => $minor_axis_pixel,
major_axis_world => $major_axis_world,
minor_axis_world => $minor_axis_world,
area => $area,
fwhm_pixel => $fwhm_pixel,
fwhm_world => $fwhm_world,
);
$star->morphology( $morphology );
# Push the star onto the catalog.
$catalog->pushstar( $star );
}
$catalog->origin( 'IO::SExtractor' );
return $catalog;
}
=item B<_write_catalog>
Create an output catalogue in the SExtractor ASCII_HEAD format and
return the lines in an array.
$ref = Astro::Catalog::IO::SExtractor->_write_catalog( $catalog );
Argument is an C<Astro::Catalog> object.
This method currently only returns the ID, X, Y, RA and Dec values in
the returned strings, in that order.
=cut
sub _write_catalog {
croak ( 'Usage: _write_catalog( $catalog, [%opts] ') unless scalar(@_) >= 1;
my $class = shift;
my $catalog = shift;
my @output;
# First, the header. What we write to the header depends on what
# values we have for our objects, so check for ID, X, Y, RA, and Dec
# values.
my $write_id = 0;
my $write_x = 0;
my $write_y = 0;
my $write_ra = 0;
my $write_dec = 0;
my @stars = $catalog->stars();
if( defined( $stars[0]->id ) ) {
$write_id = 1;
}
if( defined( $stars[0]->x ) ) {
$write_x = 1;
}
if( defined( $stars[0]->y ) ) {
$write_y = 1;
}
if( defined( $stars[0]->coords->ra ) ) {
$write_ra = 1;
}
if( defined( $stars[0]->coords->dec ) ) {
$write_dec = 1;
}
# Now for the header.
my $pos = 1;
if( $write_id ) {
push @output, "# $pos NUMBER Running object number";
$pos++;
}
if( $write_x ) {
push @output, "# $pos X_IMAGE Object position along x [pixel]";
$pos++;
}
if( $write_y ) {
push @output, "# $pos Y_IMAGE Object position along y [pixel]";
$pos++;
}
if( $write_ra ) {
push @output, "# $pos ALPHA_J2000 Right ascension of barycenter (J2000) [deg]";
$pos++;
}
if( $write_dec ) {
push @output, "# $pos DELTA_J2000 Declination of barycenter (J2000) [deg]";
$pos++;
}
# Now go through the objects.
foreach my $star ( @stars ) {
my $output_string = "";
if( $write_id ) {
$output_string .= $star->id . " ";
}
if( $write_x ) {
$output_string .= $star->x . " ";
}
if( $write_y ) {
$output_string .= $star->y . " ";
}
if( $write_ra ) {
$output_string .= $star->coords->ra->degrees . " ";
}
if( $write_dec ) {
$output_string .= $star->coords->dec->degrees . " ";
}
push @output, $output_string;
}
# And return!
return \@output;
}
=back
=head1 REVISION
$Id: SExtractor.pm,v 1.19 2006/06/05 21:02:49 cavanagh Exp $
=head1 FORMAT
The SExtractor ASCII_HEAD format consists of a header block and a
data block. The header block is made up of comments denoted by a
# as the first character. These comments describe the column number,
output parameter name, description of the output paramter, and units
of the output parameter enclosed in square brackets. The data block
is space-delimited.
=head1 SEE ALSO
L<Astro::Catalog>
=head1 COPYRIGHT
Copyright (C) 2004 Particle Physics and Astronomy Research Council.
All Rights Reserved.
This module is free software; you can redistribute it and/or modify it
under the terms of the GNU Public License.
=head1 AUTHORS
Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>
=cut
1;